diff options
author | Sergio Afonso <safonsof@amd.com> | 2025-08-25 14:30:19 +0100 |
---|---|---|
committer | Sergio Afonso <safonsof@amd.com> | 2025-08-25 15:07:29 +0100 |
commit | a68678ff5d712e93e882a4925bcef13aafac0fa8 (patch) | |
tree | 38d36a393fec6f9d2d76f9c0f2925c461a191553 | |
parent | 30b7fd5427b890b72674610cf5181eb725575da2 (diff) | |
download | llvm-users/skatrak/map-rework-03-rm-host-ops.zip llvm-users/skatrak/map-rework-03-rm-host-ops.tar.gz llvm-users/skatrak/map-rework-03-rm-host-ops.tar.bz2 |
Remove omp.target[_{enter,exit}]_data and omp.targt_update operations from target device modulesusers/skatrak/map-rework-03-rm-host-ops
-rw-r--r-- | flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp | 361 | ||||
-rw-r--r-- | flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir | 101 |
2 files changed, 170 insertions, 292 deletions
diff --git a/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp b/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp index c6d3414..c80a3db 100644 --- a/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp +++ b/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp @@ -31,102 +31,39 @@ namespace flangomp { using namespace mlir; -/// Add an operation to one of the output sets to be later rewritten, based on -/// whether it is located within the given region. +/// Add an operation to the output set to be later rewritten. template <typename OpTy> -static void collectRewriteImpl(OpTy op, Region ®ion, - llvm::SetVector<OpTy> &rewrites, - llvm::SetVector<Operation *> *parentRewrites) { - if (rewrites.contains(op)) - return; - - if (!parentRewrites || region.isAncestor(op->getParentRegion())) - rewrites.insert(op); - else - parentRewrites->insert(op.getOperation()); -} - -template <typename OpTy> -static void collectRewrite(OpTy op, Region ®ion, - llvm::SetVector<OpTy> &rewrites, - llvm::SetVector<Operation *> *parentRewrites) { - collectRewriteImpl(op, region, rewrites, parentRewrites); +static void collectRewrite(OpTy op, llvm::SetVector<OpTy> &rewrites) { + rewrites.insert(op); } -/// Add an \c omp.map.info operation and all its members recursively to one of -/// the output sets to be later rewritten, based on whether they are located -/// within the given region. +/// Add an \c omp.map.info operation and all its members recursively to the +/// output set to be later rewritten. /// /// Dependencies across \c omp.map.info are maintained by ensuring dependencies /// are added to the output sets before operations based on them. template <> -void collectRewrite(omp::MapInfoOp mapOp, Region ®ion, - llvm::SetVector<omp::MapInfoOp> &rewrites, - llvm::SetVector<Operation *> *parentRewrites) { +void collectRewrite(omp::MapInfoOp mapOp, + llvm::SetVector<omp::MapInfoOp> &rewrites) { for (Value member : mapOp.getMembers()) - collectRewrite(cast<omp::MapInfoOp>(member.getDefiningOp()), region, - rewrites, parentRewrites); + collectRewrite(cast<omp::MapInfoOp>(member.getDefiningOp()), rewrites); - collectRewriteImpl(mapOp, region, rewrites, parentRewrites); + rewrites.insert(mapOp); } /// Add the given value to a sorted set if it should be replaced by a -/// placeholder when used as an operand that must remain for the device. The -/// used output set used will depend on whether the value is defined within the -/// given region. +/// placeholder when used as an operand that must remain for the device. /// -/// Values that are block arguments of \c omp.target_data and \c func.func -/// operations are skipped, since they will still be available after all -/// rewrites are completed. -static void collectRewrite(Value value, Region ®ion, - llvm::SetVector<Value> &rewrites, - llvm::SetVector<Value> *parentRewrites) { +/// Values that are block arguments of \c func.func operations are skipped, +/// since they will still be available after all rewrites are completed. +static void collectRewrite(Value value, llvm::SetVector<Value> &rewrites) { if ((isa<BlockArgument>(value) && - isa<func::FuncOp, omp::TargetDataOp>( + isa<func::FuncOp>( cast<BlockArgument>(value).getOwner()->getParentOp())) || rewrites.contains(value)) return; - if (!parentRewrites) { - rewrites.insert(value); - return; - } - - Region *definingRegion; - if (auto blockArg = dyn_cast<BlockArgument>(value)) - definingRegion = blockArg.getOwner()->getParent(); - else - definingRegion = value.getDefiningOp()->getParentRegion(); - - assert(definingRegion && "defining op/block must exist in a region"); - - if (region.isAncestor(definingRegion)) - rewrites.insert(value); - else - parentRewrites->insert(value); -} - -/// Add operations in \c childRewrites to one of the output sets based on -/// whether they are located within the given region. -template <typename OpTy> -static void -applyChildRewrites(Region ®ion, - const llvm::SetVector<Operation *> &childRewrites, - llvm::SetVector<OpTy> &rewrites, - llvm::SetVector<Operation *> *parentRewrites) { - for (Operation *rewrite : childRewrites) - if (auto op = dyn_cast<OpTy>(*rewrite)) - collectRewrite(op, region, rewrites, parentRewrites); -} - -/// Add values in \c childRewrites to one of the output sets based on -/// whether they are defined within the given region. -static void applyChildRewrites(Region ®ion, - const llvm::SetVector<Value> &childRewrites, - llvm::SetVector<Value> &rewrites, - llvm::SetVector<Value> *parentRewrites) { - for (Value value : childRewrites) - collectRewrite(value, region, rewrites, parentRewrites); + rewrites.insert(value); } namespace { @@ -191,12 +128,13 @@ public: // Remove the callOp callOp->erase(); } + if (!hasTargetRegion) { funcOp.erase(); return WalkResult::skip(); } - if (failed(rewriteHostRegion(funcOp.getRegion()))) { + if (failed(rewriteHostFunction(funcOp))) { funcOp.emitOpError() << "could not be rewritten for target device"; return WalkResult::interrupt(); } @@ -211,25 +149,25 @@ public: } private: - /// Rewrite the given host device region belonging to a function that contains - /// \c omp.target operations, to remove host-only operations that are not used - /// by device codegen. + /// Rewrite the given host device function containing \c omp.target + /// operations, to remove host-only operations that are not used by device + /// codegen. /// /// It is based on the expected form of the MLIR module as produced by Flang /// lowering and it performs the following mutations: /// - Replace all values returned by the function with \c fir.undefined. - /// - Operations taking map-like clauses (e.g. \c omp.target, - /// \c omp.target_data, etc) are moved to the end of the function. If they + /// - \c omp.target operations are moved to the end of the function. If they /// are nested inside of any other operations, they are hoisted out of - /// them. If the region belongs to \c omp.target_data, these operations - /// are hoisted to its top level, rather than to the parent function. - /// - \c device, \c if and \c depend clauses are removed from these target - /// functions. Values initializing other clauses are either replaced by + /// them. + /// - \c depend, \c device and \c if clauses are removed from these target + /// functions. Values used to initialize other clauses are replaced by /// placeholders as follows: /// - Values defined by block arguments are replaced by placeholders only - /// if they are not attached to \c func.func or \c omp.target_data - /// operations. In that case, they are kept unmodified. - /// - \c arith.constant and \c fir.address_of are maintained. + /// if they are not attached to the parent \c func.func operation. In + /// that case, they are passed unmodified. + /// - \c arith.constant and \c fir.address_of ops are maintained. + /// - Values of type \c fir.boxchar are replaced with a combination of + /// \c fir.alloca for a single bit and a \c fir.emboxchar. /// - Other values are replaced by a combination of an \c fir.alloca for a /// single bit and an \c fir.convert to the original type of the value. /// This can be done because the code eventually generated for these @@ -245,83 +183,67 @@ private: /// operation which is preserved. Otherwise, the pass will fail. /// - \c var_ptr can be defined by an \c hlfir.declare which is also /// preserved. Its \c memref argument is replaced by a placeholder or - /// maintained similarly to non-map clauses of target operations + /// maintained, similarly to non-map clauses of target operations /// described above. If it has \c shape or \c typeparams arguments, they /// are replaced by applicable constants. \c dummy_scope arguments /// are discarded. /// - Every other operation not located inside of an \c omp.target is /// removed. - /// - Whenever a value or operation that would otherwise be replaced with a - /// placeholder is defined outside of the region being rewritten, it is - /// added to the \c parentOpRewrites or \c parentValRewrites output - /// argument, to be later handled by the caller. This is only intended to - /// properly support nested \c omp.target_data and \c omp.target placed - /// inside of \c omp.target_data. When called for the main function, these - /// output arguments must not be set. - LogicalResult - rewriteHostRegion(Region ®ion, - llvm::SetVector<Operation *> *parentOpRewrites = nullptr, - llvm::SetVector<Value> *parentValRewrites = nullptr) { - // Extract parent op information. - auto [funcOp, targetDataOp] = [®ion]() { - Operation *parent = region.getParentOp(); - return std::make_tuple(dyn_cast<func::FuncOp>(parent), - dyn_cast<omp::TargetDataOp>(parent)); - }(); - assert((bool)funcOp != (bool)targetDataOp && - "region must be defined by either func.func or omp.target_data"); - assert((bool)parentOpRewrites == (bool)targetDataOp && - (bool)parentValRewrites == (bool)targetDataOp && - "parent rewrites must be passed iff rewriting omp.target_data"); - - // Collect operations that have mapping information associated to them. - llvm::SmallVector< - std::variant<omp::TargetOp, omp::TargetDataOp, omp::TargetEnterDataOp, - omp::TargetExitDataOp, omp::TargetUpdateOp>> - targetOps; - - // Sets to store pending rewrites marked by child omp.target_data ops. - llvm::SetVector<Operation *> childOpRewrites; - llvm::SetVector<Value> childValRewrites; - WalkResult result = region.walk<WalkOrder::PreOrder>([&](Operation *op) { + LogicalResult rewriteHostFunction(func::FuncOp funcOp) { + Region ®ion = funcOp.getRegion(); + + // Collect target operations inside of the function. + llvm::SmallVector<omp::TargetOp> targetOps; + region.walk<WalkOrder::PreOrder>([&](Operation *op) { // Skip the inside of omp.target regions, since these contain device code. if (auto targetOp = dyn_cast<omp::TargetOp>(op)) { targetOps.push_back(targetOp); return WalkResult::skip(); } - if (auto targetOp = dyn_cast<omp::TargetDataOp>(op)) { - // Recursively rewrite omp.target_data regions as well. - if (failed(rewriteHostRegion(targetOp.getRegion(), &childOpRewrites, - &childValRewrites))) { - targetOp.emitOpError() << "rewrite for target device failed"; - return WalkResult::interrupt(); + // Replace omp.target_data entry block argument uses with the value used + // to initialize the associated omp.map.info operation. This way, + // references are still valid once the omp.target operation has been + // extracted out of the omp.target_data region. + if (auto targetDataOp = dyn_cast<omp::TargetDataOp>(op)) { + llvm::SmallVector<std::pair<Value, BlockArgument>> argPairs; + cast<omp::BlockArgOpenMPOpInterface>(*targetDataOp) + .getBlockArgsPairs(argPairs); + for (auto [operand, blockArg] : argPairs) { + auto mapInfo = cast<omp::MapInfoOp>(operand.getDefiningOp()); + Value varPtr = mapInfo.getVarPtr(); + + // If the var_ptr operand of the omp.map.info op defining this entry + // block argument is an hlfir.declare, the uses of all users of that + // entry block argument that are themselves hlfir.declare are replaced + // by values produced by the outer one. + // + // This prevents this pass from producing chains of hlfir.declare of + // the type: + // %0 = ... + // %1:2 = hlfir.declare %0 + // %2:2 = hlfir.declare %1#1... + // %3 = omp.map.info var_ptr(%2#1 ... + if (auto outerDeclare = varPtr.getDefiningOp<hlfir::DeclareOp>()) + for (Operation *user : blockArg.getUsers()) + if (isa<hlfir::DeclareOp>(user)) + user->replaceAllUsesWith(outerDeclare); + + // All remaining uses of the entry block argument are replaced with + // the var_ptr initialization value. + blockArg.replaceAllUsesWith(varPtr); } - - targetOps.push_back(targetOp); - return WalkResult::skip(); } - - if (auto targetOp = dyn_cast<omp::TargetEnterDataOp>(op)) - targetOps.push_back(targetOp); - else if (auto targetOp = dyn_cast<omp::TargetExitDataOp>(op)) - targetOps.push_back(targetOp); - else if (auto targetOp = dyn_cast<omp::TargetUpdateOp>(op)) - targetOps.push_back(targetOp); - return WalkResult::advance(); }); - if (result.wasInterrupted()) - return failure(); - // Make a temporary clone of the parent operation with an empty region, // and update all references to entry block arguments to those of the new // region. Users will later either be moved to the new region or deleted // when the original region is replaced by the new. OpBuilder builder(&getContext()); - builder.setInsertionPointAfter(region.getParentOp()); - Operation *newOp = builder.cloneWithoutRegions(*region.getParentOp()); + builder.setInsertionPointAfter(funcOp); + Operation *newOp = builder.cloneWithoutRegions(funcOp); Block &block = newOp->getRegion(0).emplaceBlock(); llvm::SmallVector<Location> locs; @@ -334,85 +256,57 @@ private: llvm::zip_equal(region.getArguments(), block.getArguments())) oldArg.replaceAllUsesWith(newArg); - // Collect omp.map.info ops while satisfying interdependencies. This must be - // updated whenever operands to operations contained in targetOps change. + // Collect omp.map.info ops while satisfying interdependencies and remove + // operands that aren't used by target device codegen. + // + // This logic must be updated whenever operands to omp.target change. llvm::SetVector<Value> rewriteValues; llvm::SetVector<omp::MapInfoOp> mapInfos; - for (auto targetOp : targetOps) { - std::visit( - [&](auto op) { - // Variables unused by the device, present on all target ops. - op.getDeviceMutable().clear(); - op.getIfExprMutable().clear(); - - for (Value mapVar : op.getMapVars()) - collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), - region, mapInfos, parentOpRewrites); - - if constexpr (!std::is_same_v<decltype(op), omp::TargetDataOp>) { - // Variables unused by the device, present on all target ops - // except for omp.target_data. - op.getDependVarsMutable().clear(); - op.setDependKindsAttr(nullptr); - } - - if constexpr (std::is_same_v<decltype(op), omp::TargetOp>) { - assert(op.getHostEvalVars().empty() && - "unexpected host_eval in target device module"); - // TODO: Clear some of these operands rather than rewriting them, - // depending on whether they are needed by device codegen once - // support for them is fully implemented. - for (Value allocVar : op.getAllocateVars()) - collectRewrite(allocVar, region, rewriteValues, - parentValRewrites); - for (Value allocVar : op.getAllocatorVars()) - collectRewrite(allocVar, region, rewriteValues, - parentValRewrites); - for (Value inReduction : op.getInReductionVars()) - collectRewrite(inReduction, region, rewriteValues, - parentValRewrites); - for (Value isDevPtr : op.getIsDevicePtrVars()) - collectRewrite(isDevPtr, region, rewriteValues, - parentValRewrites); - for (Value mapVar : op.getHasDeviceAddrVars()) - collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), - region, mapInfos, parentOpRewrites); - for (Value privateVar : op.getPrivateVars()) - collectRewrite(privateVar, region, rewriteValues, - parentValRewrites); - if (Value threadLimit = op.getThreadLimit()) - collectRewrite(threadLimit, region, rewriteValues, - parentValRewrites); - } else if constexpr (std::is_same_v<decltype(op), - omp::TargetDataOp>) { - for (Value mapVar : op.getUseDeviceAddrVars()) - collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), - region, mapInfos, parentOpRewrites); - for (Value mapVar : op.getUseDevicePtrVars()) - collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), - region, mapInfos, parentOpRewrites); - } - }, - targetOp); + for (omp::TargetOp targetOp : targetOps) { + assert(targetOp.getHostEvalVars().empty() && + "unexpected host_eval in target device module"); + + // Variables unused by the device. + targetOp.getDependVarsMutable().clear(); + targetOp.setDependKindsAttr(nullptr); + targetOp.getDeviceMutable().clear(); + targetOp.getIfExprMutable().clear(); + + // TODO: Clear some of these operands rather than rewriting them, + // depending on whether they are needed by device codegen once support for + // them is fully implemented. + for (Value allocVar : targetOp.getAllocateVars()) + collectRewrite(allocVar, rewriteValues); + for (Value allocVar : targetOp.getAllocatorVars()) + collectRewrite(allocVar, rewriteValues); + for (Value inReduction : targetOp.getInReductionVars()) + collectRewrite(inReduction, rewriteValues); + for (Value isDevPtr : targetOp.getIsDevicePtrVars()) + collectRewrite(isDevPtr, rewriteValues); + for (Value mapVar : targetOp.getHasDeviceAddrVars()) + collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), mapInfos); + for (Value mapVar : targetOp.getMapVars()) + collectRewrite(cast<omp::MapInfoOp>(mapVar.getDefiningOp()), mapInfos); + for (Value privateVar : targetOp.getPrivateVars()) + collectRewrite(privateVar, rewriteValues); + if (Value threadLimit = targetOp.getThreadLimit()) + collectRewrite(threadLimit, rewriteValues); } - applyChildRewrites(region, childOpRewrites, mapInfos, parentOpRewrites); - // Move omp.map.info ops to the new block and collect dependencies. llvm::SetVector<hlfir::DeclareOp> declareOps; llvm::SetVector<fir::BoxOffsetOp> boxOffsets; for (omp::MapInfoOp mapOp : mapInfos) { if (auto declareOp = dyn_cast_if_present<hlfir::DeclareOp>( mapOp.getVarPtr().getDefiningOp())) - collectRewrite(declareOp, region, declareOps, parentOpRewrites); + collectRewrite(declareOp, declareOps); else - collectRewrite(mapOp.getVarPtr(), region, rewriteValues, - parentValRewrites); + collectRewrite(mapOp.getVarPtr(), rewriteValues); if (Value varPtrPtr = mapOp.getVarPtrPtr()) { if (auto boxOffset = llvm::dyn_cast_if_present<fir::BoxOffsetOp>( varPtrPtr.getDefiningOp())) - collectRewrite(boxOffset, region, boxOffsets, parentOpRewrites); + collectRewrite(boxOffset, boxOffsets); else return mapOp->emitOpError() << "var_ptr_ptr rewrite only supported " "if defined by fir.box_offset"; @@ -423,9 +317,6 @@ private: mapOp->moveBefore(&block, block.end()); } - applyChildRewrites(region, childOpRewrites, declareOps, parentOpRewrites); - applyChildRewrites(region, childOpRewrites, boxOffsets, parentOpRewrites); - // Create a temporary marker to simplify the op moving process below. builder.setInsertionPointToStart(&block); auto marker = builder.create<fir::UndefOp>(builder.getUnknownLoc(), @@ -434,8 +325,7 @@ private: // Handle dependencies of hlfir.declare ops. for (hlfir::DeclareOp declareOp : declareOps) { - collectRewrite(declareOp.getMemref(), region, rewriteValues, - parentValRewrites); + collectRewrite(declareOp.getMemref(), rewriteValues); // Shape and typeparams aren't needed for target device codegen, but // removing them would break verifiers. @@ -492,8 +382,6 @@ private: // Using fir.undefined here instead is not possible because these variables // cannot be constants, as that would trigger different codegen for target // regions. - applyChildRewrites(region, childValRewrites, rewriteValues, - parentValRewrites); for (Value value : rewriteValues) { Location loc = value.getLoc(); Value rewriteValue; @@ -504,6 +392,20 @@ private: if (isa_and_present<arith::ConstantOp, fir::AddrOfOp>( value.getDefiningOp())) { rewriteValue = builder.clone(*value.getDefiningOp())->getResult(0); + } else if (auto boxCharType = + dyn_cast<fir::BoxCharType>(value.getType())) { + // !fir.boxchar types cannot be directly obtained by converting a + // !fir.ref<i1>, as they aren't reference types. Since they can appear + // representing some `target firstprivate` clauses, we need to create + // a special case here based on creating a placeholder fir.emboxchar op. + MLIRContext *ctx = &getContext(); + fir::KindTy kind = boxCharType.getKind(); + auto placeholder = builder.create<fir::AllocaOp>( + loc, fir::CharacterType::getSingleton(ctx, kind)); + auto one = builder.create<arith::ConstantOp>( + loc, builder.getI32Type(), builder.getI32IntegerAttr(1)); + rewriteValue = builder.create<fir::EmboxCharOp>(loc, boxCharType, + placeholder, one); } else { Value placeholder = builder.create<fir::AllocaOp>(loc, builder.getI1Type()); @@ -526,23 +428,18 @@ private: marker->erase(); // Move target operations to the end of the new block. - for (auto targetOp : targetOps) - std::visit([&block](auto op) { op->moveBefore(&block, block.end()); }, - targetOp); + for (omp::TargetOp targetOp : targetOps) + targetOp->moveBefore(&block, block.end()); // Add terminator to the new block. builder.setInsertionPointToEnd(&block); - if (funcOp) { - llvm::SmallVector<Value> returnValues; - returnValues.reserve(funcOp.getNumResults()); - for (auto type : funcOp.getResultTypes()) - returnValues.push_back( - builder.create<fir::UndefOp>(funcOp.getLoc(), type)); - - builder.create<func::ReturnOp>(funcOp.getLoc(), returnValues); - } else { - builder.create<omp::TerminatorOp>(targetDataOp.getLoc()); - } + llvm::SmallVector<Value> returnValues; + returnValues.reserve(funcOp.getNumResults()); + for (auto type : funcOp.getResultTypes()) + returnValues.push_back( + builder.create<fir::UndefOp>(funcOp.getLoc(), type)); + + builder.create<func::ReturnOp>(funcOp.getLoc(), returnValues); // Replace old region (now missing ops) with the new one and remove the // temporary operation clone. diff --git a/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir b/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir index 4d8975d..d6fc3e2 100644 --- a/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir +++ b/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir @@ -12,28 +12,20 @@ module attributes {omp.is_target_device = true} { func.call @foo() : () -> () - // CHECK-NEXT: %[[ARG_DECL:.*]]:2 = hlfir.declare %[[ARG]] {uniq_name = "arg"} %0:2 = hlfir.declare %arg {uniq_name = "arg"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) - - // CHECK-NEXT: %[[GLOBAL_DECL:.*]]:2 = hlfir.declare %[[GLOBAL]] {uniq_name = "global_scalar"} %global = fir.address_of(@global_scalar) : !fir.ref<i32> %1:2 = hlfir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) - - // CHECK-NEXT: %[[ALLOC_DECL:.*]]:2 = hlfir.declare %[[ALLOC]] {uniq_name = "alloc"} %alloc = fir.alloca i32 %2:2 = hlfir.declare %alloc {uniq_name = "alloc"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) + // CHECK-NEXT: %[[ALLOC_DECL:.*]]:2 = hlfir.declare %[[ALLOC]] {uniq_name = "alloc"} + // CHECK-NEXT: %[[ARG_DECL:.*]]:2 = hlfir.declare %[[ARG]] {uniq_name = "arg"} + // CHECK-NEXT: %[[GLOBAL_DECL:.*]]:2 = hlfir.declare %[[GLOBAL]] {uniq_name = "global_scalar"} + + // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[ALLOC_DECL]]#1{{.*}}) // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[ARG_DECL]]#1{{.*}}) // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL]]#1{{.*}}) // CHECK-NEXT: %[[MAP3:.*]] = omp.map.info var_ptr(%[[ALLOC]]{{.*}}) - // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[ALLOC_DECL]]#1{{.*}}) - // CHECK-NEXT: %[[MAP4:.*]] = omp.map.info var_ptr(%[[ARG_DECL]]#1{{.*}}) - // CHECK-NEXT: %[[MAP5:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL]]#1{{.*}}) - // CHECK-NEXT: %[[MAP6:.*]] = omp.map.info var_ptr(%[[ALLOC_DECL]]#1{{.*}}) - // CHECK-NEXT: %[[MAP7:.*]] = omp.map.info var_ptr(%[[ALLOC]]{{.*}}) - // CHECK-NEXT: %[[MAP8:.*]] = omp.map.info var_ptr(%[[ARG_DECL]]#1{{.*}}) - // CHECK-NEXT: %[[MAP9:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL]]#1{{.*}}) - // CHECK-NEXT: %[[MAP10:.*]] = omp.map.info var_ptr(%[[ALLOC_DECL]]#1{{.*}}) %m0 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> %m1 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> %m2 = omp.map.info var_ptr(%2#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> @@ -54,21 +46,22 @@ module attributes {omp.is_target_device = true} { omp.terminator } + // CHECK-NOT: omp.map.info %m4 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> %m5 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> %m6 = omp.map.info var_ptr(%2#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> %m7 = omp.map.info var_ptr(%alloc : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK: omp.target_data map_entries(%[[MAP4]], %[[MAP5]], %[[MAP6]], %[[MAP7]] : {{.*}}) + // CHECK-NOT: omp.target_data omp.target_data map_entries(%m4, %m5, %m6, %m7 : !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>) { // CHECK-NOT: func.call func.call @foo() : () -> () omp.terminator } - // CHECK: omp.target_enter_data map_entries(%[[MAP8]] : {{.*}}) - // CHECK-NEXT: omp.target_exit_data map_entries(%[[MAP9]] : {{.*}}) - // CHECK-NEXT: omp.target_update map_entries(%[[MAP10]] : {{.*}}) + // CHECK-NOT: omp.target_enter_data + // CHECK-NOT: omp.target_exit_data + // CHECK-NOT: omp.target_update %m8 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(to) capture(ByRef) -> !fir.ref<i32> omp.target_enter_data map_entries(%m8 : !fir.ref<i32>) @@ -216,23 +209,25 @@ module attributes {omp.is_target_device = true} { // CHECK-SAME: (%[[MAPPED:.*]]: [[MAPPED_TYPE:[^)]*]], %[[USEDEVADDR:.*]]: [[USEDEVADDR_TYPE:[^)]*]], %[[USEDEVPTR:.*]]: [[USEDEVPTR_TYPE:[^)]*]]) func.func @target_data(%mapped: !fir.ref<i32>, %usedevaddr: !fir.ref<i32>, %usedevptr: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) { // CHECK-NEXT: %[[MAPPED_DECL:.*]]:2 = hlfir.declare %[[MAPPED]] {uniq_name = "mapped"} : ([[MAPPED_TYPE]]) -> ([[MAPPED_TYPE]], [[MAPPED_TYPE]]) + // CHECK-NEXT: %[[USEDEVADDR_DECL:.*]]:2 = hlfir.declare %[[USEDEVADDR]] {uniq_name = "usedevaddr"} : ([[USEDEVADDR_TYPE]]) -> ([[USEDEVADDR_TYPE]], [[USEDEVADDR_TYPE]]) + // CHECK-NEXT: %[[USEDEVPTR_DECL:.*]]:2 = hlfir.declare %[[USEDEVPTR]] {uniq_name = "usedevptr"} : ([[USEDEVPTR_TYPE]]) -> ([[USEDEVPTR_TYPE]], [[USEDEVPTR_TYPE]]) %0:2 = hlfir.declare %mapped {uniq_name = "mapped"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) %1:2 = hlfir.declare %usedevaddr {uniq_name = "usedevaddr"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) %2:2 = hlfir.declare %usedevptr {uniq_name = "usedevptr"} : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) -> (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) + + // CHECK-NEXT: %[[MAPPED_MAP:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]]#1 : [[MAPPED_TYPE]], i32) map_clauses(tofrom) capture(ByRef) -> [[MAPPED_TYPE]] + // CHECK-NEXT: %[[USEDEVADDR_MAP:.*]] = omp.map.info var_ptr(%[[USEDEVADDR_DECL]]#1 : [[USEDEVADDR_TYPE]], i32) map_clauses(tofrom) capture(ByRef) -> [[USEDEVADDR_TYPE]] + // CHECK-NEXT: %[[USEDEVPTR_MAP:.*]] = omp.map.info var_ptr(%[[USEDEVPTR_DECL]]#1 : [[USEDEVPTR_TYPE]], !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(tofrom) capture(ByRef) -> [[USEDEVPTR_TYPE]] %m0 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> %m1 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(return_param) capture(ByRef) -> !fir.ref<i32> %m2 = omp.map.info var_ptr(%2#1 : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(return_param) capture(ByRef) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>> - // CHECK: omp.target_data map_entries(%{{.*}}) use_device_addr(%{{.*}} -> %[[USEDEVADDR_ARG:.*]] : [[USEDEVADDR_TYPE]]) use_device_ptr(%{{.*}} -> %[[USEDEVPTR_ARG:.*]] : [[USEDEVPTR_TYPE]]) + + // CHECK-NOT: omp.target_data omp.target_data map_entries(%m0 : !fir.ref<i32>) use_device_addr(%m1 -> %arg0 : !fir.ref<i32>) use_device_ptr(%m2 -> %arg1 : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) { - // CHECK-NEXT: %[[USEDEVADDR_DECL:.*]]:2 = hlfir.declare %[[USEDEVADDR_ARG]] {uniq_name = "usedevaddr"} : ([[USEDEVADDR_TYPE]]) -> ([[USEDEVADDR_TYPE]], [[USEDEVADDR_TYPE]]) %3:2 = hlfir.declare %arg0 {uniq_name = "usedevaddr"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) - // CHECK-NEXT: %[[USEDEVPTR_DECL:.*]]:2 = hlfir.declare %[[USEDEVPTR_ARG]] {uniq_name = "usedevptr"} : ([[USEDEVPTR_TYPE]]) -> ([[USEDEVPTR_TYPE]], [[USEDEVPTR_TYPE]]) %4:2 = hlfir.declare %arg1 {uniq_name = "usedevptr"} : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) -> (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) - // CHECK-NEXT: %[[MAPPED_MAP:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]]#1 : [[MAPPED_TYPE]], i32) map_clauses(tofrom) capture(ByRef) -> [[MAPPED_TYPE]] %m3 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: %[[USEDEVADDR_MAP:.*]] = omp.map.info var_ptr(%[[USEDEVADDR_DECL]]#1 : [[USEDEVADDR_TYPE]], i32) map_clauses(tofrom) capture(ByRef) -> [[USEDEVADDR_TYPE]] %m4 = omp.map.info var_ptr(%3#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: %[[USEDEVPTR_MAP:.*]] = omp.map.info var_ptr(%[[USEDEVPTR_DECL]]#1 : [[USEDEVPTR_TYPE]], !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(tofrom) capture(ByRef) -> [[USEDEVPTR_TYPE]] %m5 = omp.map.info var_ptr(%4#1 : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>> // CHECK-NOT: func.call @@ -303,11 +298,11 @@ module attributes {omp.is_target_device = true} { fir.call @foo() : () -> () cf.br ^bb2 ^bb2: // 2 preds: ^bb0, ^bb1 - fir.call @foo() : () -> () - %m1 = omp.map.info var_ptr(%x_decl#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> // CHECK-NOT: fir.call // CHECK-NOT: omp.map.info - // CHECK: omp.target_data map_entries(%[[MAP1]] : [[X_TYPE]]) + // CHECK-NOT: omp.target_data + fir.call @foo() : () -> () + %m1 = omp.map.info var_ptr(%x_decl#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> omp.target_data map_entries(%m1 : !fir.ref<i32>) { fir.call @foo() : () -> () %8 = fir.load %cond_decl#0 : !fir.ref<!fir.logical<4>> @@ -315,9 +310,8 @@ module attributes {omp.is_target_device = true} { cf.cond_br %9, ^bb1, ^bb2 ^bb1: // pred: ^bb0 fir.call @foo() : () -> () - // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[X_DECL]]#1 : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]] %m2 = omp.map.info var_ptr(%x_decl#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: omp.target map_entries(%[[MAP2]] -> {{.*}} : [[X_TYPE]]) + // CHECK: omp.target map_entries(%[[MAP1]] -> {{.*}} : [[X_TYPE]]) omp.target map_entries(%m2 -> %arg2 : !fir.ref<i32>) { omp.terminator } @@ -357,22 +351,18 @@ module attributes {omp.is_target_device = true} { omp.terminator } + // CHECK-NOT: omp.parallel + // CHECK-NOT: hlfir.declare + // CHECK-NOT: omp.map.info + // CHECK-NOT: omp.target_data omp.parallel private(@privatizer %x_decl#0 -> %arg0 : !fir.ref<i32>) { %1:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) %m1 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NOT: omp.parallel - // CHECK-NOT: hlfir.declare - // CHECK-NOT: omp.map.info - // CHECK: omp.target_data map_entries(%[[MAP1]] : [[X_TYPE]]) omp.target_data map_entries(%m1 : !fir.ref<i32>) { omp.parallel private(@privatizer %1#0 -> %arg1 : !fir.ref<i32>) { - // CHECK-NEXT: %[[PLACEHOLDER2:.*]] = fir.alloca i1 - // CHECK-NEXT: %[[ALLOCA2:.*]] = fir.convert %[[PLACEHOLDER2]] : (!fir.ref<i1>) -> !fir.ref<i32> - // CHECK-NEXT: %[[X_DECL2:.*]]:2 = hlfir.declare %[[ALLOCA2]] {uniq_name = "x"} : ([[X_TYPE]]) -> ([[X_TYPE]], [[X_TYPE]]) %2:2 = hlfir.declare %arg1 {uniq_name = "x"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) - // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[X_DECL2]]#1 : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]] %m2 = omp.map.info var_ptr(%2#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: omp.target map_entries(%[[MAP2]] -> {{.*}} : [[X_TYPE]]) + // CHECK: omp.target map_entries(%[[MAP1]] -> {{.*}} : [[X_TYPE]]) omp.target map_entries(%m2 -> %arg2 : !fir.ref<i32>) { omp.terminator } @@ -395,19 +385,18 @@ module attributes {omp.is_target_device = true} { %global = fir.address_of(@global_scalar) : !fir.ref<i32> // CHECK-NEXT: %[[GLOBAL_DECL0:.*]]:2 = hlfir.declare %[[GLOBAL]] {uniq_name = "global_scalar"} // CHECK-NEXT: %[[GLOBAL_DECL1:.*]]:2 = hlfir.declare %[[GLOBAL]] {uniq_name = "global_scalar"} - %0:2 = hlfir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) + // CHECK-NEXT: %[[GLOBAL_DECL2:.*]]:2 = hlfir.declare %[[GLOBAL]] {uniq_name = "global_scalar"} // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL0]]#1 : !fir.ref<i32>, i32) - // CHECK-NEXT: %[[MAP3:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL1]]#1 : !fir.ref<i32>, i32) + // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL1]]#1 : !fir.ref<i32>, i32) + // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL2]]#1 : !fir.ref<i32>, i32) + %0:2 = hlfir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) %m0 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: omp.target_data map_entries(%[[MAP0]] : !fir.ref<i32>) + // CHECK-NOT: omp.target_data omp.target_data map_entries(%m0 : !fir.ref<i32>) { - // CHECK-NEXT: %[[GLOBAL_DECL2:.*]]:2 = hlfir.declare %[[GLOBAL]] {uniq_name = "global_scalar"} %1:2 = hlfir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) - // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL0]]#1 : !fir.ref<i32>, i32) %m1 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL2]]#1 : !fir.ref<i32>, i32) %m2 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK-NEXT: omp.target map_entries(%[[MAP1]] -> %{{.*}}, %[[MAP2]] -> {{.*}} : !fir.ref<i32>, !fir.ref<i32>) + // CHECK-NEXT: omp.target map_entries(%[[MAP0]] -> %{{.*}}, %[[MAP1]] -> {{.*}} : !fir.ref<i32>, !fir.ref<i32>) omp.target map_entries(%m1 -> %arg0, %m2 -> %arg1 : !fir.ref<i32>, !fir.ref<i32>) { omp.terminator } @@ -415,10 +404,11 @@ module attributes {omp.is_target_device = true} { } // CHECK-NOT: fir.load // CHECK-NOT: hlfir.declare + // CHECK-NOT: omp.map.info %2 = fir.load %global : !fir.ref<i32> %3:2 = hlfir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) %m3 = omp.map.info var_ptr(%3#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK: omp.target thread_limit(%[[THREAD_LIMIT]] : i32) map_entries(%[[MAP3]] -> %{{.*}} : !fir.ref<i32>) + // CHECK: omp.target thread_limit(%[[THREAD_LIMIT]] : i32) map_entries(%[[MAP2]] -> %{{.*}} : !fir.ref<i32>) omp.target thread_limit(%2 : i32) map_entries(%m3 -> %arg0 : !fir.ref<i32>) { omp.terminator } @@ -438,11 +428,11 @@ module attributes {omp.is_target_device = true} { // CHECK-SAME: (%[[REF:.*]]: !fir.ref<i32>, %[[INT:.*]]: i32, %[[BOOL:.*]]: i1) func.func @all_non_map_clauses(%ref: !fir.ref<i32>, %int: i32, %bool: i1) { %m0 = omp.map.info var_ptr(%ref : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> - // CHECK: omp.target_data map_entries({{[^)]*}}) { + // CHECK-NOT: omp.target_data omp.target_data device(%int : i32) if(%bool) map_entries(%m0 : !fir.ref<i32>) { omp.terminator } - // CHECK: omp.target allocate({{[^)]*}}) thread_limit({{[^)]*}}) in_reduction({{[^)]*}}) private({{[^)]*}}) { + // CHECK-NEXT: omp.target allocate({{[^)]*}}) thread_limit({{[^)]*}}) in_reduction({{[^)]*}}) private({{[^)]*}}) { omp.target allocate(%ref : !fir.ref<i32> -> %ref : !fir.ref<i32>) depend(taskdependin -> %ref : !fir.ref<i32>) device(%int : i32) if(%bool) thread_limit(%int : i32) @@ -450,26 +440,17 @@ module attributes {omp.is_target_device = true} { private(@privatizer %ref -> %arg1 : !fir.ref<i32>) { omp.terminator } - // CHECK: omp.target_enter_data - // CHECK-NOT: depend - // CHECK-NOT: device - // CHECK-NOT: if + // CHECK-NOT: omp.target_enter_data omp.target_enter_data depend(taskdependin -> %ref : !fir.ref<i32>) device(%int : i32) if(%bool) - // CHECK-NEXT: omp.target_exit_data - // CHECK-NOT: depend - // CHECK-NOT: device - // CHECK-NOT: if + // CHECK-NOT: omp.target_exit_data omp.target_exit_data depend(taskdependin -> %ref : !fir.ref<i32>) device(%int : i32) if(%bool) - // CHECK-NEXT: omp.target_update - // CHECK-NOT: depend - // CHECK-NOT: device - // CHECK-NOT: if + // CHECK-NOT: omp.target_update omp.target_update depend(taskdependin -> %ref : !fir.ref<i32>) device(%int : i32) if(%bool) - // CHECK-NEXT: return + // CHECK: return return } |