[Flang][OpenMP] - When mapping a fir.boxchar
, map the underlying data pointer as a member (#141715)
This PR adds functionality to the `MapInfoFinalization` pass wherein the underlying data pointer of a `fir.boxchar` is mapped as a member of the parent boxchar.
This commit is contained in:
parent
1b5303744f
commit
f993f362ef
@ -88,6 +88,16 @@ inline AddrAndBoundsInfo getDataOperandBaseAddr(fir::FirOpBuilder &builder,
|
||||
|
||||
return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy);
|
||||
}
|
||||
// For boxchar references, do the same as what is done above for box
|
||||
// references - Load the boxchar so that it is easier to retrieve the length
|
||||
// of the underlying character and the data pointer.
|
||||
if (auto boxCharType = mlir::dyn_cast<fir::BoxCharType>(
|
||||
fir::unwrapRefType((symAddr.getType())))) {
|
||||
if (!isOptional && mlir::isa<fir::ReferenceType>(symAddr.getType())) {
|
||||
mlir::Value boxChar = builder.create<fir::LoadOp>(loc, symAddr);
|
||||
return AddrAndBoundsInfo(boxChar, rawInput, isPresent);
|
||||
}
|
||||
}
|
||||
return AddrAndBoundsInfo(symAddr, rawInput, isPresent);
|
||||
}
|
||||
|
||||
@ -134,26 +144,64 @@ template <typename BoundsOp, typename BoundsType>
|
||||
mlir::Value
|
||||
genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc,
|
||||
fir::ExtendedValue dataExv, AddrAndBoundsInfo &info) {
|
||||
// TODO: Handle info.isPresent.
|
||||
if (auto boxCharType =
|
||||
mlir::dyn_cast<fir::BoxCharType>(info.addr.getType())) {
|
||||
mlir::Type idxTy = builder.getIndexType();
|
||||
mlir::Type lenType = builder.getCharacterLengthType();
|
||||
|
||||
if (!mlir::isa<fir::BoxCharType>(fir::unwrapRefType(info.addr.getType())))
|
||||
return mlir::Value{};
|
||||
|
||||
mlir::Type idxTy = builder.getIndexType();
|
||||
mlir::Type lenType = builder.getCharacterLengthType();
|
||||
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
|
||||
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
|
||||
using ExtentAndStride = std::tuple<mlir::Value, mlir::Value>;
|
||||
auto [extent, stride] = [&]() -> ExtentAndStride {
|
||||
if (info.isPresent) {
|
||||
llvm::SmallVector<mlir::Type> resTypes = {idxTy, idxTy};
|
||||
mlir::Operation::result_range ifRes =
|
||||
builder
|
||||
.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true)
|
||||
.genThen([&]() {
|
||||
mlir::Value boxChar =
|
||||
fir::isa_ref_type(info.addr.getType())
|
||||
? builder.create<fir::LoadOp>(loc, info.addr)
|
||||
: info.addr;
|
||||
fir::BoxCharType boxCharType =
|
||||
mlir::cast<fir::BoxCharType>(boxChar.getType());
|
||||
mlir::Type refType = builder.getRefType(boxCharType.getEleTy());
|
||||
auto unboxed = builder.create<fir::UnboxCharOp>(
|
||||
loc, refType, lenType, boxChar);
|
||||
mlir::SmallVector<mlir::Value> results = {unboxed.getResult(1),
|
||||
one};
|
||||
builder.create<fir::ResultOp>(loc, results);
|
||||
})
|
||||
.genElse([&]() {
|
||||
mlir::SmallVector<mlir::Value> results = {zero, zero};
|
||||
builder.create<fir::ResultOp>(loc, results);
|
||||
})
|
||||
.getResults();
|
||||
return {ifRes[0], ifRes[1]};
|
||||
}
|
||||
// We have already established that info.addr.getType() is a boxchar
|
||||
// or a boxchar address. If an address, load the boxchar.
|
||||
mlir::Value boxChar = fir::isa_ref_type(info.addr.getType())
|
||||
? builder.create<fir::LoadOp>(loc, info.addr)
|
||||
: info.addr;
|
||||
fir::BoxCharType boxCharType =
|
||||
mlir::cast<fir::BoxCharType>(boxChar.getType());
|
||||
mlir::Type refType = builder.getRefType(boxCharType.getEleTy());
|
||||
auto unboxed =
|
||||
builder.create<fir::UnboxCharOp>(loc, refType, lenType, info.addr);
|
||||
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
|
||||
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
|
||||
mlir::Value extent = unboxed.getResult(1);
|
||||
mlir::Value stride = one;
|
||||
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
|
||||
mlir::Type boundTy = builder.getType<mlir::omp::MapBoundsType>();
|
||||
return builder.create<mlir::omp::MapBoundsOp>(
|
||||
loc, boundTy, /*lower_bound=*/zero,
|
||||
/*upper_bound=*/ub, /*extent=*/extent, /*stride=*/stride,
|
||||
/*stride_in_bytes=*/true, /*start_idx=*/zero);
|
||||
}
|
||||
return mlir::Value{};
|
||||
builder.create<fir::UnboxCharOp>(loc, refType, lenType, boxChar);
|
||||
return {unboxed.getResult(1), one};
|
||||
}();
|
||||
|
||||
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
|
||||
mlir::Type boundTy = builder.getType<BoundsType>();
|
||||
return builder.create<BoundsOp>(loc, boundTy,
|
||||
/*lower_bound=*/zero,
|
||||
/*upper_bound=*/ub,
|
||||
/*extent=*/extent,
|
||||
/*stride=*/stride,
|
||||
/*stride_in_bytes=*/true,
|
||||
/*start_idx=*/zero);
|
||||
}
|
||||
|
||||
/// Generate the bounds operation from the descriptor information.
|
||||
@ -293,11 +341,11 @@ genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info,
|
||||
bounds = genBaseBoundsOps<BoundsOp, BoundsType>(builder, loc, dataExv,
|
||||
dataExvIsAssumedSize);
|
||||
}
|
||||
if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType()))) {
|
||||
if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType())) ||
|
||||
mlir::isa<fir::BoxCharType>(fir::unwrapRefType(info.addr.getType()))) {
|
||||
bounds = {genBoundsOpFromBoxChar<BoundsOp, BoundsType>(builder, loc,
|
||||
dataExv, info)};
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include <numeric>
|
||||
|
||||
#define DEBUG_TYPE "omp-map-info-finalization"
|
||||
#define PDBGS() (llvm::dbgs() << "[" << DEBUG_TYPE << "]: ")
|
||||
|
||||
namespace flangomp {
|
||||
#define GEN_PASS_DEF_MAPINFOFINALIZATIONPASS
|
||||
#include "flang/Optimizer/OpenMP/Passes.h.inc"
|
||||
@ -285,6 +285,62 @@ class MapInfoFinalizationPass
|
||||
return false;
|
||||
}
|
||||
|
||||
mlir::omp::MapInfoOp genBoxcharMemberMap(mlir::omp::MapInfoOp op,
|
||||
fir::FirOpBuilder &builder) {
|
||||
if (!op.getMembers().empty())
|
||||
return op;
|
||||
mlir::Location loc = op.getVarPtr().getLoc();
|
||||
mlir::Value boxChar = op.getVarPtr();
|
||||
|
||||
if (mlir::isa<fir::ReferenceType>(op.getVarPtr().getType()))
|
||||
boxChar = builder.create<fir::LoadOp>(loc, op.getVarPtr());
|
||||
|
||||
fir::BoxCharType boxCharType =
|
||||
mlir::dyn_cast<fir::BoxCharType>(boxChar.getType());
|
||||
mlir::Value boxAddr = builder.create<fir::BoxOffsetOp>(
|
||||
loc, op.getVarPtr(), fir::BoxFieldAttr::base_addr);
|
||||
|
||||
uint64_t mapTypeToImplicit = static_cast<
|
||||
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
|
||||
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
|
||||
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
|
||||
|
||||
mlir::ArrayAttr newMembersAttr;
|
||||
llvm::SmallVector<llvm::SmallVector<int64_t>> memberIdx = {{0}};
|
||||
newMembersAttr = builder.create2DI64ArrayAttr(memberIdx);
|
||||
|
||||
mlir::Value varPtr = op.getVarPtr();
|
||||
mlir::omp::MapInfoOp memberMapInfoOp = builder.create<mlir::omp::MapInfoOp>(
|
||||
op.getLoc(), varPtr.getType(), varPtr,
|
||||
mlir::TypeAttr::get(boxCharType.getEleTy()),
|
||||
builder.getIntegerAttr(builder.getIntegerType(64, /*isSigned=*/false),
|
||||
mapTypeToImplicit),
|
||||
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(
|
||||
mlir::omp::VariableCaptureKind::ByRef),
|
||||
/*varPtrPtr=*/boxAddr,
|
||||
/*members=*/llvm::SmallVector<mlir::Value>{},
|
||||
/*member_index=*/mlir::ArrayAttr{},
|
||||
/*bounds=*/op.getBounds(),
|
||||
/*mapperId=*/mlir::FlatSymbolRefAttr(), /*name=*/op.getNameAttr(),
|
||||
builder.getBoolAttr(false));
|
||||
|
||||
mlir::omp::MapInfoOp newMapInfoOp = builder.create<mlir::omp::MapInfoOp>(
|
||||
op.getLoc(), op.getResult().getType(), varPtr,
|
||||
mlir::TypeAttr::get(
|
||||
llvm::cast<mlir::omp::PointerLikeType>(varPtr.getType())
|
||||
.getElementType()),
|
||||
op.getMapTypeAttr(), op.getMapCaptureTypeAttr(),
|
||||
/*varPtrPtr=*/mlir::Value{},
|
||||
/*members=*/llvm::SmallVector<mlir::Value>{memberMapInfoOp},
|
||||
/*member_index=*/newMembersAttr,
|
||||
/*bounds=*/llvm::SmallVector<mlir::Value>{},
|
||||
/*mapperId=*/mlir::FlatSymbolRefAttr(), op.getNameAttr(),
|
||||
/*partial_map=*/builder.getBoolAttr(false));
|
||||
op.replaceAllUsesWith(newMapInfoOp.getResult());
|
||||
op->erase();
|
||||
return newMapInfoOp;
|
||||
}
|
||||
|
||||
mlir::omp::MapInfoOp genDescriptorMemberMaps(mlir::omp::MapInfoOp op,
|
||||
fir::FirOpBuilder &builder,
|
||||
mlir::Operation *target) {
|
||||
@ -575,6 +631,7 @@ class MapInfoFinalizationPass
|
||||
fir::factory::AddrAndBoundsInfo info =
|
||||
fir::factory::getDataOperandBaseAddr(
|
||||
builder, varPtr, /*isOptional=*/false, varPtr.getLoc());
|
||||
|
||||
fir::ExtendedValue extendedValue =
|
||||
hlfir::translateToExtendedValue(varPtr.getLoc(), builder,
|
||||
hlfir::Entity{info.addr},
|
||||
@ -743,6 +800,37 @@ class MapInfoFinalizationPass
|
||||
return mlir::WalkResult::advance();
|
||||
});
|
||||
|
||||
func->walk([&](mlir::omp::MapInfoOp op) {
|
||||
if (!op.getMembers().empty())
|
||||
return;
|
||||
|
||||
if (!mlir::isa<fir::BoxCharType>(fir::unwrapRefType(op.getVarType())))
|
||||
return;
|
||||
|
||||
// POSSIBLE_HACK_ALERT: If the boxchar has been implicitly mapped then
|
||||
// it is likely that the underlying pointer to the data
|
||||
// (!fir.ref<fir.char<k,?>>) has already been mapped. So, skip such
|
||||
// boxchars. We are primarily interested in boxchars that were mapped
|
||||
// by passes such as MapsForPrivatizedSymbols that map boxchars that
|
||||
// are privatized. At present, such boxchar maps are not marked
|
||||
// implicit. Should they be? I don't know. If they should be then
|
||||
// we need to change this check for early return OR live with
|
||||
// over-mapping.
|
||||
bool hasImplicitMap =
|
||||
(llvm::omp::OpenMPOffloadMappingFlags(op.getMapType()) &
|
||||
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT) ==
|
||||
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
|
||||
if (hasImplicitMap)
|
||||
return;
|
||||
|
||||
assert(llvm::hasSingleElement(op->getUsers()) &&
|
||||
"OMPMapInfoFinalization currently only supports single users "
|
||||
"of a MapInfoOp");
|
||||
|
||||
builder.setInsertionPoint(op);
|
||||
genBoxcharMemberMap(op, builder);
|
||||
});
|
||||
|
||||
func->walk([&](mlir::omp::MapInfoOp op) {
|
||||
// TODO: Currently only supports a single user for the MapInfoOp. This
|
||||
// is fine for the moment, as the Fortran frontend will generate a
|
||||
|
@ -22,7 +22,9 @@
|
||||
// 2. Generalize this for more than just omp.target ops.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Optimizer/Builder/DirectivesCommon.h"
|
||||
#include "flang/Optimizer/Builder/FIRBuilder.h"
|
||||
#include "flang/Optimizer/Builder/HLFIRTools.h"
|
||||
#include "flang/Optimizer/Dialect/FIRType.h"
|
||||
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
|
||||
#include "flang/Optimizer/HLFIR/HLFIROps.h"
|
||||
@ -184,37 +186,23 @@ class MapsForPrivatizedSymbolsPass
|
||||
return fir::hasDynamicSize(t);
|
||||
}
|
||||
|
||||
// TODO: Remove this in favor of fir::factory::genImplicitBoundsOps
|
||||
// in a subsequent PR.
|
||||
void genBoundsOps(fir::FirOpBuilder &builder, mlir::Value var,
|
||||
llvm::SmallVector<mlir::Value> &boundsOps) {
|
||||
if (!fir::isBoxAddress(var.getType()))
|
||||
return;
|
||||
|
||||
unsigned int rank = 0;
|
||||
rank = fir::getBoxRank(fir::unwrapRefType(var.getType()));
|
||||
mlir::Location loc = var.getLoc();
|
||||
mlir::Type idxTy = builder.getIndexType();
|
||||
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
|
||||
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
|
||||
mlir::Type boundTy = builder.getType<omp::MapBoundsType>();
|
||||
mlir::Value box = builder.create<fir::LoadOp>(loc, var);
|
||||
for (unsigned int i = 0; i < rank; ++i) {
|
||||
mlir::Value dimNo = builder.createIntegerConstant(loc, idxTy, i);
|
||||
auto dimInfo =
|
||||
builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dimNo);
|
||||
mlir::Value lb = dimInfo.getLowerBound();
|
||||
mlir::Value extent = dimInfo.getExtent();
|
||||
mlir::Value byteStride = dimInfo.getByteStride();
|
||||
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
|
||||
|
||||
mlir::Value boundsOp = builder.create<omp::MapBoundsOp>(
|
||||
loc, boundTy, /*lower_bound=*/zero,
|
||||
/*upper_bound=*/ub, /*extent=*/extent, /*stride=*/byteStride,
|
||||
/*stride_in_bytes = */ true, /*start_idx=*/lb);
|
||||
LLVM_DEBUG(PDBGS() << "Created BoundsOp " << boundsOp << "\n");
|
||||
boundsOps.push_back(boundsOp);
|
||||
}
|
||||
fir::factory::AddrAndBoundsInfo info =
|
||||
fir::factory::getDataOperandBaseAddr(builder, var,
|
||||
/*isOptional=*/false, loc);
|
||||
fir::ExtendedValue extendedValue =
|
||||
hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
|
||||
/*continguousHint=*/true)
|
||||
.first;
|
||||
llvm::SmallVector<mlir::Value> boundsOpsVec =
|
||||
fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
|
||||
mlir::omp::MapBoundsType>(
|
||||
builder, info, extendedValue,
|
||||
/*dataExvIsAssumedSize=*/false, loc);
|
||||
for (auto bounds : boundsOpsVec)
|
||||
boundsOps.push_back(bounds);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
@ -1288,3 +1288,30 @@ omp.declare_mapper @my_mapper : !fir.type<_QFdeclare_mapperTmy_type{data:i32}> {
|
||||
omp.declare_mapper.info map_entries(%4, %3 : !fir.ref<!fir.type<_QFdeclare_mapperTmy_type{data:i32}>>, !fir.ref<i32>)
|
||||
// CHECK: }
|
||||
}
|
||||
|
||||
// -----
|
||||
omp.private {type = firstprivate} @boxchar_privatizer : !fir.boxchar<1> copy {
|
||||
^bb0(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>):
|
||||
omp.yield(%arg1 : !fir.boxchar<1>)
|
||||
}
|
||||
|
||||
func.func @map_privatized_boxchar(%arg0 : !fir.boxchar<1>) {
|
||||
%0 = fir.alloca !fir.boxchar<1>
|
||||
fir.store %arg0 to %0 : !fir.ref<!fir.boxchar<1>>
|
||||
%7 = fir.box_offset %0 base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
|
||||
%8 = omp.map.info var_ptr(%0 : !fir.ref<!fir.boxchar<1>>, !fir.char<1,?>) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%7 : !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>) -> !fir.ref<!fir.boxchar<1>>
|
||||
%9 = omp.map.info var_ptr(%0 : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%8 : [0] : !fir.ref<!fir.boxchar<1>>) -> !fir.ref<!fir.boxchar<1>>
|
||||
omp.target map_entries(%9 -> %arg1, %8 -> %arg2 : !fir.ref<!fir.boxchar<1>>, !fir.ref<!fir.boxchar<1>>) private(@boxchar_privatizer %arg0 -> %arg3 [map_idx=0] : !fir.boxchar<1>) {
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: llvm.func @map_privatized_boxchar(
|
||||
// CHECK-SAME: %[[ARG0:.*]]: !llvm.struct<(ptr, i64)>) {
|
||||
// CHECK: %[[BOXCHAR_ALLOCA:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64)> : (i64) -> !llvm.ptr
|
||||
// CHECK: llvm.store %[[ARG0]], %[[BOXCHAR_ALLOCA]] : !llvm.struct<(ptr, i64)>, !llvm.ptr
|
||||
// CHECK: %[[BASE_ADDR:.*]] = llvm.getelementptr %[[BOXCHAR_ALLOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64)>
|
||||
// CHECK: %[[MAP_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[BOXCHAR_ALLOCA]] : !llvm.ptr, i8) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR]] : !llvm.ptr) -> !llvm.ptr
|
||||
// CHECK: %[[MAP_BOXCHAR:.*]] = omp.map.info var_ptr(%[[BOXCHAR_ALLOCA]] : !llvm.ptr, !llvm.struct<(ptr, i64)>) map_clauses(to) capture(ByRef) members(%[[MAP_BASE_ADDR]] : [0] : !llvm.ptr) -> !llvm.ptr
|
||||
// CHECK: omp.target map_entries(%[[MAP_BOXCHAR]] -> %arg1, %[[MAP_BASE_ADDR]] -> %arg2 : !llvm.ptr, !llvm.ptr) private(@boxchar_privatizer %[[ARG0]] -> %arg3 [map_idx=0] : !llvm.struct<(ptr, i64)>) {
|
||||
|
@ -18,25 +18,38 @@ end subroutine TestOfCharacter
|
||||
!CHECK: %[[A0_DECL:.*]]:2 = hlfir.declare %[[UNBOXED_ARG0]]#0 typeparams %[[UNBOXED_ARG0]]#1 dummy_scope {{.*}} -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
!CHECK: %[[UNBOXED_ARG1:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A1_DECL:.*]]:2 = hlfir.declare %[[UNBOXED_ARG1]]#0 typeparams %[[UNBOXED_ARG1]]#1 dummy_scope {{.*}} -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
!CHECK: %[[UNBOXED_A0_DECL:.*]]:2 = fir.unboxchar %[[A0_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A0_LB:.*]] = arith.constant 0 : index
|
||||
!CHECK: %[[A0_STRIDE:.*]] = arith.constant 1 : index
|
||||
!CHECK: %[[UNBOXED_A0_DECL:.*]]:2 = fir.unboxchar %[[A0_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A0_UB:.*]] = arith.subi %[[UNBOXED_A0_DECL]]#1, %[[A0_STRIDE]] : index
|
||||
!CHECK: %[[A0_BOUNDS:.*]] = omp.map.bounds lower_bound(%[[A0_LB]] : index) upper_bound(%[[A0_UB]] : index) extent(%[[UNBOXED_A0_DECL]]#1 : index)
|
||||
!CHECK-SAME: stride(%[[A0_STRIDE]] : index) start_idx(%[[A0_LB]] : index) {stride_in_bytes = true}
|
||||
!CHECK: %[[A0_MAP:.*]] = omp.map.info var_ptr(%[[A0_DECL]]#1 : !fir.ref<!fir.char<1,?>>, !fir.char<1,?>) map_clauses(to) capture(ByRef) bounds(%[[A0_BOUNDS]]) -> !fir.ref<!fir.char<1,?>> {name = "a0"}
|
||||
!CHECK: %[[UNBOXED_A1_DECL:.*]]:2 = fir.unboxchar %[[A1_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A1_LB:.*]] = arith.constant 0 : index
|
||||
!CHECK: %[[A1_STRIDE:.*]] = arith.constant 1 : index
|
||||
!CHECK: %[[UNBOXED_A1_DECL:.*]]:2 = fir.unboxchar %[[A1_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A1_UB:.*]] = arith.subi %[[UNBOXED_A1_DECL]]#1, %[[A1_STRIDE]] : index
|
||||
!CHECK: %[[A1_BOUNDS:.*]] = omp.map.bounds lower_bound(%[[A1_LB]] : index) upper_bound(%[[A1_UB]] : index) extent(%[[UNBOXED_A1_DECL]]#1 : index)
|
||||
!CHECKL-SAME: stride(%[[A1_STRIDE]] : index) start_idx(%[[A1_LB]] : index) {stride_in_bytes = true}
|
||||
!CHECK: %[[A1_MAP:.*]] = omp.map.info var_ptr(%[[A1_DECL]]#1 : !fir.ref<!fir.char<1,?>>, !fir.char<1,?>) map_clauses(from) capture(ByRef) bounds(%[[A1_BOUNDS]]) -> !fir.ref<!fir.char<1,?>> {name = "a1"}
|
||||
!CHECK: fir.store %[[ARG1]] to %[[A1_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>
|
||||
!CHECK: %[[A1_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) -> !fir.ref<!fir.boxchar<1>> {name = ""}
|
||||
!CHECK: %[[CONST_ZERO:.*]] = arith.constant 0 : index
|
||||
!CHECK: %[[CONST_ONE:.*]] = arith.constant 1 : index
|
||||
!CHECK: %[[UNBOXED_ARG1:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A1_UB:.*]] = arith.subi %[[UNBOXED_ARG1]]#1, %[[CONST_ONE]] : index
|
||||
!CHECK: %[[BOUNDS_A1_BOXCHAR:.*]] = omp.map.bounds lower_bound(%[[CONST_ZERO]] : index) upper_bound(%[[A1_UB]] : index) extent(%[[UNBOXED_ARG1]]#1 : index)
|
||||
!CHECK-SAME: stride(%[[CONST_ONE]] : index) start_idx(%[[CONST_ZERO]] : index) {stride_in_bytes = true}
|
||||
!CHECK: %[[A1_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to)
|
||||
!CHECK-SAME: capture(ByRef) bounds(%[[BOUNDS_A1_BOXCHAR]]) -> !fir.ref<!fir.boxchar<1>> {name = ""}
|
||||
!CHECK: fir.store %[[ARG0]] to %[[A0_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>
|
||||
!CHECK: %[[A0_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) -> !fir.ref<!fir.boxchar<1>> {name = ""}
|
||||
|
||||
!CHECK: %[[CONST_ZERO:.*]] = arith.constant 0 : index
|
||||
!CHECK: %[[CONST_ONE:.*]] = arith.constant 1 : index
|
||||
!CHECK: %[[UNBOXED_ARG0:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
!CHECK: %[[A0_UB:.*]] = arith.subi %[[UNBOXED_ARG0]]#1, %[[CONST_ONE]] : index
|
||||
!CHECK: %[[BOUNDS_A0_BOXCHAR:.*]] = omp.map.bounds lower_bound(%[[CONST_ZERO]] : index) upper_bound(%[[A0_UB]] : index) extent(%[[UNBOXED_ARG0]]#1 : index)
|
||||
!CHECK-SAME: stride(%[[CONST_ONE]] : index) start_idx(%[[CONST_ZERO]] : index) {stride_in_bytes = true}
|
||||
!CHECK: %[[A0_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to)
|
||||
!CHECK-SAME: capture(ByRef) bounds(%[[BOUNDS_A0_BOXCHAR]]) -> !fir.ref<!fir.boxchar<1>> {name = ""}
|
||||
!CHECK: omp.target map_entries(%[[A0_MAP]] -> %[[TGT_A0:.*]], %[[A1_MAP]] -> %[[TGT_A1:.*]], %[[A1_BOXCHAR_MAP]] -> %[[TGT_A1_BOXCHAR:.*]], %[[A0_BOXCHAR_MAP]] -> %[[TGT_A0_BOXCHAR:.*]] : !fir.ref<!fir.char<1,?>>, !fir.ref<!fir.char<1,?>>, !fir.ref<!fir.boxchar<1>>, !fir.ref<!fir.boxchar<1>>) {
|
||||
!CHECK: %[[TGT_A0_BC_LD:.*]] = fir.load %[[TGT_A0_BOXCHAR]] : !fir.ref<!fir.boxchar<1>>
|
||||
!CHECK: %[[TGT_A1_BC_LD:.*]] = fir.load %[[TGT_A1_BOXCHAR]] : !fir.ref<!fir.boxchar<1>>
|
||||
|
@ -3,24 +3,31 @@
|
||||
module mod
|
||||
implicit none
|
||||
contains
|
||||
subroutine routine(a)
|
||||
subroutine routine_box(a)
|
||||
implicit none
|
||||
real(4), allocatable, optional, intent(inout) :: a(:)
|
||||
integer(4) :: i
|
||||
|
||||
!$omp target teams distribute parallel do shared(a)
|
||||
do i=1,10
|
||||
a(i) = i + a(i)
|
||||
end do
|
||||
do i=1,10
|
||||
a(i) = i + a(i)
|
||||
end do
|
||||
|
||||
end subroutine routine
|
||||
end subroutine routine_box
|
||||
subroutine routine_boxchar(a)
|
||||
character(len=*), optional, intent(in) :: a
|
||||
character(len=4) :: b
|
||||
!$omp target map(from: b)
|
||||
b = a
|
||||
!$omp end target
|
||||
end subroutine routine_boxchar
|
||||
end module mod
|
||||
|
||||
! CHECK-LABEL: func.func @_QMmodProutine(
|
||||
! CHECK-LABEL: func.func @_QMmodProutine_box(
|
||||
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {fir.bindc_name = "a", fir.optional}) {
|
||||
! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>>
|
||||
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
|
||||
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<allocatable, intent_inout, optional>, uniq_name = "_QMmodFroutineEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
|
||||
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<allocatable, intent_inout, optional>, uniq_name = "_QMmodFroutine_boxEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
|
||||
! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_2]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> i1
|
||||
! CHECK: %[[VAL_9:.*]]:5 = fir.if %[[VAL_8]] -> (index, index, index, index, index) {
|
||||
! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
|
||||
@ -44,3 +51,45 @@ end module mod
|
||||
! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
|
||||
! CHECK: fir.store %[[VAL_24]] to %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
|
||||
! CHECK: }
|
||||
|
||||
|
||||
! CHECK-LABEL: func.func @_QMmodProutine_boxchar(
|
||||
! CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1> {fir.bindc_name = "a", fir.optional}) {
|
||||
! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.boxchar<1>
|
||||
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
|
||||
! CHECK: %[[VAL_2:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<intent_in, optional>, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
! CHECK: %[[VAL_4:.*]] = arith.constant 4 : index
|
||||
! CHECK: %[[VAL_5:.*]] = fir.alloca !fir.char<1,4> {bindc_name = "b", uniq_name = "_QMmodFroutine_boxcharEb"}
|
||||
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_4]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>)
|
||||
! CHECK: %[[VAL_7:.*]] = omp.map.info var_ptr(%[[VAL_6]]#1 : !fir.ref<!fir.char<1,4>>, !fir.char<1,4>) map_clauses(from) capture(ByRef) -> !fir.ref<!fir.char<1,4>> {name = "b"}
|
||||
! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_3]]#1 : (!fir.ref<!fir.char<1,?>>) -> i1
|
||||
! CHECK: %[[VAL_9:.*]] = arith.constant 0 : index
|
||||
! CHECK: %[[VAL_10:.*]] = arith.constant 1 : index
|
||||
! CHECK: %[[VAL_11:.*]]:2 = fir.if %[[VAL_8]] -> (index, index) {
|
||||
! CHECK: %[[VAL_12:.*]]:2 = fir.unboxchar %[[VAL_3]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
! CHECK: fir.result %[[VAL_12]]#1, %[[VAL_10]] : index, index
|
||||
! CHECK: } else {
|
||||
! CHECK: fir.result %[[VAL_9]], %[[VAL_9]] : index, index
|
||||
! CHECK: }
|
||||
! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_14:.*]]#0, %[[VAL_10]] : index
|
||||
! CHECK: %[[VAL_15:.*]] = omp.map.bounds lower_bound(%[[VAL_9]] : index) upper_bound(%[[VAL_13]] : index) extent(%[[VAL_14]]#0 : index) stride(%[[VAL_14]]#1 : index) start_idx(%[[VAL_9]] : index) {stride_in_bytes = true}
|
||||
! CHECK: %[[VAL_16:.*]] = omp.map.info var_ptr(%[[VAL_3]]#1 : !fir.ref<!fir.char<1,?>>, !fir.char<1,?>) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) bounds(%[[VAL_15]]) -> !fir.ref<!fir.char<1,?>> {name = "a"}
|
||||
! CHECK: fir.store %[[ARG0]] to %[[VAL_0]] : !fir.ref<!fir.boxchar<1>>
|
||||
! CHECK: %[[VAL_17:.*]] = arith.constant 0 : index
|
||||
! CHECK: %[[VAL_18:.*]] = arith.constant 1 : index
|
||||
! CHECK: %[[VAL_19:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_19]]#1, %[[VAL_18]] : index
|
||||
! CHECK: %[[VAL_21:.*]] = omp.map.bounds lower_bound(%[[VAL_17]] : index) upper_bound(%[[VAL_20]] : index) extent(%[[VAL_19]]#1 : index) stride(%[[VAL_18]] : index) start_idx(%[[VAL_17]] : index) {stride_in_bytes = true}
|
||||
! CHECK: %[[VAL_22:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) bounds(%[[VAL_21]]) -> !fir.ref<!fir.boxchar<1>> {name = ""}
|
||||
! CHECK: omp.target map_entries(%[[VAL_7]] -> %[[VAL_23:.*]], %[[VAL_16]] -> %[[VAL_24:.*]], %[[VAL_22]] -> %[[VAL_25:.*]] : !fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,?>>, !fir.ref<!fir.boxchar<1>>) {
|
||||
! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_25]] : !fir.ref<!fir.boxchar<1>>
|
||||
! CHECK: %[[VAL_27:.*]]:2 = fir.unboxchar %[[VAL_26]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
! CHECK: %[[VAL_28:.*]] = arith.constant 4 : index
|
||||
! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_23]] typeparams %[[VAL_28]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>)
|
||||
! CHECK: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_24]] typeparams %[[VAL_27]]#1 {fortran_attrs = #fir.var_attrs<intent_in, optional>, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
! CHECK: hlfir.assign %[[VAL_30]]#0 to %[[VAL_29]]#0 : !fir.boxchar<1>, !fir.ref<!fir.char<1,4>>
|
||||
! CHECK: omp.terminator
|
||||
! CHECK: }
|
||||
! CHECK: return
|
||||
! CHECK: }
|
||||
|
@ -333,3 +333,62 @@ func.func @_QPreuse_alloca(%arg0: !fir.box<!fir.array<?xf64>> {fir.bindc_name =
|
||||
// CHECK: }
|
||||
// CHECK: return
|
||||
|
||||
|
||||
|
||||
omp.private {type = firstprivate} @boxchar.privatizer : !fir.boxchar<1> copy {
|
||||
^bb0(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>):
|
||||
omp.yield(%arg0 : !fir.boxchar<1>)
|
||||
}
|
||||
func.func @_QPrealtest(%arg0: !fir.boxchar<1>) {
|
||||
%0 = fir.alloca !fir.boxchar<1>
|
||||
%1 = fir.dummy_scope : !fir.dscope
|
||||
%2:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
%3:2 = hlfir.declare %2#0 typeparams %2#1 dummy_scope %1 {uniq_name = "a0"}: (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
fir.store %3#0 to %0 : !fir.ref<!fir.boxchar<1>>
|
||||
%4 = fir.load %0 : !fir.ref<!fir.boxchar<1>>
|
||||
%5:2 = fir.unboxchar %4 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
%c0 = arith.constant 0 : index
|
||||
%c1 = arith.constant 1 : index
|
||||
%6:2 = fir.unboxchar %4 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
%7 = arith.subi %6#1, %c1 : index
|
||||
%8 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%7 : index) extent(%6#1 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true}
|
||||
%9 = omp.map.info var_ptr(%0 : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) bounds(%8) -> !fir.ref<!fir.boxchar<1>>
|
||||
omp.target map_entries(%9 -> %arg1 : !fir.ref<!fir.boxchar<1>>) private(@boxchar.privatizer %3#0 -> %arg2 [map_idx=0] : !fir.boxchar<1>) {
|
||||
%10:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
%11:2 = hlfir.declare %10#0 typeparams %10#1 {uniq_name = "tgt_a0"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: omp.private {type = firstprivate} @boxchar.privatizer : !fir.boxchar<1> copy {
|
||||
// CHECK: ^bb0(%[[VAL_0:.*]]: !fir.boxchar<1>, %[[VAL_1:.*]]: !fir.boxchar<1>):
|
||||
// CHECK: omp.yield(%[[VAL_0]] : !fir.boxchar<1>)
|
||||
// CHECK: }
|
||||
|
||||
// CHECK-LABEL: func.func @_QPrealtest(
|
||||
// CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1>) {
|
||||
// CHECK: %[[VAL_0:.*]] = fir.alloca !fir.boxchar<1>
|
||||
// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
|
||||
// CHECK: %[[VAL_2:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 dummy_scope %[[VAL_1]] {uniq_name = "a0"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
// CHECK: fir.store %[[VAL_3]]#0 to %[[VAL_0]] : !fir.ref<!fir.boxchar<1>>
|
||||
// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.boxchar<1>>
|
||||
// CHECK: %[[VAL_5:.*]]:2 = fir.unboxchar %[[VAL_4]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
// CHECK: %[[VAL_6:.*]] = arith.constant 0 : index
|
||||
// CHECK: %[[VAL_7:.*]] = arith.constant 1 : index
|
||||
// CHECK: %[[VAL_8:.*]]:2 = fir.unboxchar %[[VAL_4]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
// CHECK: %[[VAL_9:.*]] = arith.subi %[[VAL_8]]#1, %[[VAL_7]] : index
|
||||
// CHECK: %[[VAL_10:.*]] = omp.map.bounds lower_bound(%[[VAL_6]] : index) upper_bound(%[[VAL_9]] : index) extent(%[[VAL_8]]#1 : index) stride(%[[VAL_7]] : index) start_idx(%[[VAL_6]] : index) {stride_in_bytes = true}
|
||||
// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.boxchar<1>>
|
||||
// CHECK: %[[VAL_12:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
|
||||
// CHECK: %[[VAL_13:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref<!fir.boxchar<1>>, !fir.char<1,?>) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%[[VAL_12]] : !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>) bounds(%[[VAL_10]]) -> !fir.ref<!fir.boxchar<1>>
|
||||
// CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%[[VAL_13]] : [0] : !fir.ref<!fir.boxchar<1>>) -> !fir.ref<!fir.boxchar<1>>
|
||||
// CHECK: omp.target map_entries(%[[VAL_14]] -> %[[VAL_15:.*]], %[[VAL_13]] -> %[[VAL_16:.*]] : !fir.ref<!fir.boxchar<1>>, !fir.ref<!fir.boxchar<1>>) private(@boxchar.privatizer %[[VAL_3]]#0 -> %[[VAL_17:.*]] [map_idx=0] : !fir.boxchar<1>) {
|
||||
// CHECK: %[[VAL_18:.*]]:2 = fir.unboxchar %[[VAL_17]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
|
||||
// CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]]#0 typeparams %[[VAL_18]]#1 {uniq_name = "tgt_a0"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
|
||||
// CHECK: omp.terminator
|
||||
// CHECK: }
|
||||
// CHECK: return
|
||||
// CHECK: }
|
||||
|
Loading…
x
Reference in New Issue
Block a user