diff --git a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h index 8684299ab6792..b4c4cb562325f 100644 --- a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h +++ b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h @@ -17,6 +17,8 @@ #ifndef FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_ #define FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_ +#include "BoxValue.h" +#include "FIRBuilder.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/Todo.h" @@ -131,6 +133,31 @@ gatherBoundsOrBoundValues(fir::FirOpBuilder &builder, mlir::Location loc, } return values; } +template +mlir::Value +genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc, + fir::ExtendedValue dataExv, AddrAndBoundsInfo &info) { + // TODO: Handle info.isPresent. + if (auto boxCharType = + mlir::dyn_cast(info.addr.getType())) { + mlir::Type idxTy = builder.getIndexType(); + mlir::Type lenType = builder.getCharacterLengthType(); + mlir::Type refType = builder.getRefType(boxCharType.getEleTy()); + auto unboxed = + builder.create(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(loc, extent, one); + mlir::Type boundTy = builder.getType(); + return builder.create( + loc, boundTy, /*lower_bound=*/zero, + /*upper_bound=*/ub, /*extent=*/extent, /*stride=*/stride, + /*stride_in_bytes=*/true, /*start_idx=*/zero); + } + return mlir::Value{}; +} /// Generate the bounds operation from the descriptor information. template @@ -258,6 +285,10 @@ genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info, bounds = genBaseBoundsOps(builder, loc, dataExv, dataExvIsAssumedSize); } + if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType()))) { + bounds = {genBoundsOpFromBoxChar(builder, loc, + dataExv, info)}; + } return bounds; } diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index f099028c23323..ca6a7193fd26a 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -217,27 +217,8 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter, assert(args.isValid() && "invalid args"); fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); - auto bindSingleMapLike = [&converter, - &firOpBuilder](const semantics::Symbol &sym, - const mlir::BlockArgument &arg) { - // Clones the `bounds` placing them inside the entry block and returns - // them. - auto cloneBound = [&](mlir::Value bound) { - if (mlir::isMemoryEffectFree(bound.getDefiningOp())) { - mlir::Operation *clonedOp = firOpBuilder.clone(*bound.getDefiningOp()); - return clonedOp->getResult(0); - } - TODO(converter.getCurrentLocation(), - "target map-like clause operand unsupported bound type"); - }; - - auto cloneBounds = [cloneBound](llvm::ArrayRef bounds) { - llvm::SmallVector clonedBounds; - llvm::transform(bounds, std::back_inserter(clonedBounds), - [&](mlir::Value bound) { return cloneBound(bound); }); - return clonedBounds; - }; - + auto bindSingleMapLike = [&converter](const semantics::Symbol &sym, + const mlir::BlockArgument &arg) { fir::ExtendedValue extVal = converter.getSymbolExtendedValue(sym); auto refType = mlir::dyn_cast(arg.getType()); if (refType && fir::isa_builtin_cptr_type(refType.getElementType())) { @@ -245,31 +226,27 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter, } else { extVal.match( [&](const fir::BoxValue &v) { - converter.bindSymbol(sym, - fir::BoxValue(arg, cloneBounds(v.getLBounds()), - v.getExplicitParameters(), - v.getExplicitExtents())); + converter.bindSymbol(sym, fir::BoxValue(arg, v.getLBounds(), + v.getExplicitParameters(), + v.getExplicitExtents())); }, [&](const fir::MutableBoxValue &v) { converter.bindSymbol( - sym, fir::MutableBoxValue(arg, cloneBounds(v.getLBounds()), + sym, fir::MutableBoxValue(arg, v.getLBounds(), v.getMutableProperties())); }, [&](const fir::ArrayBoxValue &v) { - converter.bindSymbol( - sym, fir::ArrayBoxValue(arg, cloneBounds(v.getExtents()), - cloneBounds(v.getLBounds()), - v.getSourceBox())); + converter.bindSymbol(sym, fir::ArrayBoxValue(arg, v.getExtents(), + v.getLBounds(), + v.getSourceBox())); }, [&](const fir::CharArrayBoxValue &v) { - converter.bindSymbol( - sym, fir::CharArrayBoxValue(arg, cloneBound(v.getLen()), - cloneBounds(v.getExtents()), - cloneBounds(v.getLBounds()))); + converter.bindSymbol(sym, fir::CharArrayBoxValue(arg, v.getLen(), + v.getExtents(), + v.getLBounds())); }, [&](const fir::CharBoxValue &v) { - converter.bindSymbol( - sym, fir::CharBoxValue(arg, cloneBound(v.getLen()))); + converter.bindSymbol(sym, fir::CharBoxValue(arg, v.getLen())); }, [&](const fir::UnboxedValue &v) { converter.bindSymbol(sym, arg); }, [&](const auto &) { @@ -1371,14 +1348,13 @@ static void genBodyOfTargetOp( while (!valuesDefinedAbove.empty()) { for (mlir::Value val : valuesDefinedAbove) { mlir::Operation *valOp = val.getDefiningOp(); - assert(valOp != nullptr); // NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the // indices separately, as the alternative is to eventually map the Box, // which comes with a fairly large overhead comparatively. We could be // more robust about this and check using a BackwardsSlice to see if we // run the risk of mapping a box. - if (mlir::isMemoryEffectFree(valOp) && + if (valOp && mlir::isMemoryEffectFree(valOp) && !mlir::isa(valOp)) { mlir::Operation *clonedOp = valOp->clone(); entryBlock->push_front(clonedOp); @@ -1391,7 +1367,13 @@ static void genBodyOfTargetOp( valOp->replaceUsesWithIf(clonedOp, replace); } else { auto savedIP = firOpBuilder.getInsertionPoint(); - firOpBuilder.setInsertionPointAfter(valOp); + + if (valOp) + firOpBuilder.setInsertionPointAfter(valOp); + else + // This means val is a block argument + firOpBuilder.setInsertionPoint(targetOp); + auto copyVal = firOpBuilder.createTemporary(val.getLoc(), val.getType()); firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal); diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index 3fcb4b04a7b76..77d7bc64b4ed5 100644 --- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp +++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp @@ -47,6 +47,8 @@ #include #include +#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" @@ -550,7 +552,38 @@ class MapInfoFinalizationPass // iterations from previous function scopes. localBoxAllocas.clear(); - // First, walk `omp.map.info` ops to see if any record members should be + // First, walk `omp.map.info` ops to see if any of them have varPtrs + // with an underlying type of fir.char, i.e a character + // with dynamic length. If so, check if they need bounds added. + func->walk([&](mlir::omp::MapInfoOp op) { + if (!op.getBounds().empty()) + return; + + mlir::Value varPtr = op.getVarPtr(); + mlir::Type underlyingVarType = fir::unwrapRefType(varPtr.getType()); + + if (!fir::characterWithDynamicLen(underlyingVarType)) + return; + + 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}, + /*continguousHint=*/true) + .first; + builder.setInsertionPoint(op); + llvm::SmallVector boundsOps = + fir::factory::genImplicitBoundsOps( + builder, info, extendedValue, + /*dataExvIsAssumedSize=*/false, varPtr.getLoc()); + + op.getBoundsMutable().append(boundsOps); + }); + + // Next, walk `omp.map.info` ops to see if any record members should be // implicitly mapped. func->walk([&](mlir::omp::MapInfoOp op) { mlir::Type underlyingType = diff --git a/flang/test/Lower/OpenMP/map-character.f90 b/flang/test/Lower/OpenMP/map-character.f90 new file mode 100644 index 0000000000000..232c0a6361cb6 --- /dev/null +++ b/flang/test/Lower/OpenMP/map-character.f90 @@ -0,0 +1,47 @@ +! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s + +subroutine TestOfCharacter(a0, a1, l) + character(len=*), intent(in) :: a0 + character(len=*), intent(inout):: a1 + integer, intent(in) :: l + + !$omp target map(to:a0) map(from: a1) + a1 = a0 + !$omp end target +end subroutine TestOfCharacter + + +!CHECK: func.func @_QPtestofcharacter(%[[ARG0:.*]]: !fir.boxchar<1> {{.*}}, %[[ARG1:.*]]: !fir.boxchar<1> {{.*}} +!CHECK: %[[A0_BOXCHAR_ALLOCA:.*]] = fir.alloca !fir.boxchar<1> +!CHECK: %[[A1_BOXCHAR_ALLOCA:.*]] = fir.alloca !fir.boxchar<1> +!CHECK: %[[UNBOXED_ARG0:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +!CHECK: %[[A0_DECL:.*]]:2 = hlfir.declare %[[UNBOXED_ARG0]]#0 typeparams %[[UNBOXED_ARG0]]#1 dummy_scope {{.*}} -> (!fir.boxchar<1>, !fir.ref>) +!CHECK: %[[UNBOXED_ARG1:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +!CHECK: %[[A1_DECL:.*]]:2 = hlfir.declare %[[UNBOXED_ARG1]]#0 typeparams %[[UNBOXED_ARG1]]#1 dummy_scope {{.*}} -> (!fir.boxchar<1>, !fir.ref>) +!CHECK: %[[UNBOXED_A0_DECL:.*]]:2 = fir.unboxchar %[[A0_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref>, index) +!CHECK: %[[A0_LB:.*]] = arith.constant 0 : index +!CHECK: %[[A0_STRIDE:.*]] = arith.constant 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,?>) map_clauses(to) capture(ByRef) bounds(%[[A0_BOUNDS]]) -> !fir.ref> {name = "a0"} +!CHECK: %[[UNBOXED_A1_DECL:.*]]:2 = fir.unboxchar %[[A1_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref>, index) +!CHECK: %[[A1_LB:.*]] = arith.constant 0 : index +!CHECK: %[[A1_STRIDE:.*]] = arith.constant 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,?>) map_clauses(from) capture(ByRef) bounds(%[[A1_BOUNDS]]) -> !fir.ref> {name = "a1"} +!CHECK: fir.store %[[ARG1]] to %[[A1_BOXCHAR_ALLOCA]] : !fir.ref> +!CHECK: %[[A1_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) -> !fir.ref> {name = ""} +!CHECK: fir.store %[[ARG0]] to %[[A0_BOXCHAR_ALLOCA]] : !fir.ref> +!CHECK: %[[A0_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) -> !fir.ref> {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.ref>, !fir.ref>, !fir.ref>) { +!CHECK: %[[TGT_A0_BC_LD:.*]] = fir.load %[[TGT_A0_BOXCHAR]] : !fir.ref> +!CHECK: %[[TGT_A1_BC_LD:.*]] = fir.load %[[TGT_A1_BOXCHAR]] : !fir.ref> +!CHECK: %[[UNBOXED_TGT_A1:.*]]:2 = fir.unboxchar %[[TGT_A1_BC_LD]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +!CHECK: %[[UNBOXED_TGT_A0:.*]]:2 = fir.unboxchar %[[TGT_A0_BC_LD]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +!CHECK: %[[TGT_A0_DECL:.*]]:2 = hlfir.declare %[[TGT_A0]] typeparams %[[UNBOXED_TGT_A0]]#1 {{.*}} -> (!fir.boxchar<1>, !fir.ref>) +!CHECK: %[[TGT_A1_DECL:.*]]:2 = hlfir.declare %[[TGT_A1]] typeparams %[[UNBOXED_TGT_A1]]#1 {{.*}} -> (!fir.boxchar<1>, !fir.ref>) +