[flang-commits] [flang] [Flang][OpenMP] Split host op and function filtering (PR #184786)
Sergio Afonso via flang-commits
flang-commits at lists.llvm.org
Thu Mar 5 04:49:38 PST 2026
https://github.com/skatrak created https://github.com/llvm/llvm-project/pull/184786
The function filtering pass, intended to remove host-only functions from a target device MLIR module on an OpenMP offloading application, also removes any remaining host operations placed within functions containing an `omp.target` region.
One problem with this approach is that the function filtering pass runs relatively early, so followup passes can end up introducing new host operations that would not be caught in advance. Specifically, there is a known case where the `LowerWorkdistribute` pass can add `omp.target_data` operations that then trigger an assertion during MLIR to LLVM IR translation.
By splitting the host op deletion logic into its own pass, we can delay it to run after `LowerWorkdistribute`, preventing these transformations from producing an invalid target device MLIR module. The logic of the new pass and associated test have been tweaked to properly handle FIR.
Fixes #180503
>From ce181e3a1b9a27209da149f7464ea4366d4d9311 Mon Sep 17 00:00:00 2001
From: Sergio Afonso <Sergio.AfonsoFumero at amd.com>
Date: Thu, 5 Mar 2026 12:32:21 +0000
Subject: [PATCH] [Flang][OpenMP] Split host op and function filtering
The function filtering pass, intended to remove host-only functions from
a target device MLIR module on an OpenMP offloading application, also
removes any remaining host operations placed within functions containing an
`omp.target` region.
One problem with this approach is that the function filtering pass runs
relatively early, so followup passes can end up introducing new host
operations that would not be caught in advance. Specifically, there is a
known case where the `LowerWorkdistribute` pass can add `omp.target_data`
operations that then trigger an assertion during MLIR to LLVM IR
translation.
By splitting the host op deletion logic into its own pass, we can delay
it to run after `LowerWorkdistribute`, preventing these transformations
from producing an invalid target device MLIR module. The logic of the
new pass and associated test have been tweaked to properly handle FIR.
Fixes: #180503.
---
.../include/flang/Optimizer/OpenMP/Passes.td | 21 +
flang/lib/Optimizer/OpenMP/CMakeLists.txt | 1 +
.../Optimizer/OpenMP/FunctionFiltering.cpp | 346 ---------------
.../lib/Optimizer/OpenMP/HostOpFiltering.cpp | 409 ++++++++++++++++++
flang/lib/Optimizer/Passes/Pipelines.cpp | 1 +
flang/test/Fir/basic-program.fir | 1 +
.../OpenMP/declare-target-link-tarop-cap.f90 | 19 +-
flang/test/Lower/OpenMP/host-eval.f90 | 4 +-
.../OpenMP/function-filtering-host-ops.mlir | 271 ++++++------
9 files changed, 592 insertions(+), 481 deletions(-)
create mode 100644 flang/lib/Optimizer/OpenMP/HostOpFiltering.cpp
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 9ec159e1ba1e0..102936f17c2e4 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -57,6 +57,27 @@ def FunctionFilteringPass : Pass<"omp-function-filtering"> {
];
}
+def HostOpFilteringPass : Pass<"omp-host-op-filtering"> {
+ let summary = "Filters out host-only operations from any remaining host "
+ "functions after filtering when compiling for a target device.";
+ let description = [{
+ Removes operations from host functions that are not placed inside of an
+ `omp.target` region when compiling for the target device.
+
+ It must run after any passes that might introduce new host operations,
+ especially if they belong to the 'omp' dialect, like `LowerWorkdistribute`.
+ This ensures all potentially problematic host operations are accounted for
+ prior to LLVM IR translation.
+
+ This pass works at the FIR level of abstraction.
+ }];
+ let dependentDialects = [
+ "mlir::arith::ArithDialect",
+ "mlir::func::FuncDialect",
+ "fir::FIROpsDialect"
+ ];
+}
+
def DoConcurrentConversionPass : Pass<"omp-do-concurrent-conversion", "mlir::ModuleOp"> {
let summary = "Map `DO CONCURRENT` loops to OpenMP worksharing loops.";
diff --git a/flang/lib/Optimizer/OpenMP/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
index db29e93b71dad..f25e95f041d20 100644
--- a/flang/lib/Optimizer/OpenMP/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
@@ -5,6 +5,7 @@ add_flang_library(FlangOpenMPTransforms
DoConcurrentConversion.cpp
FunctionFiltering.cpp
GenericLoopConversion.cpp
+ HostOpFiltering.cpp
MapsForPrivatizedSymbols.cpp
MapInfoFinalization.cpp
DeleteUnreachableTargets.cpp
diff --git a/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp b/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp
index 472d6a9f08a6e..c166b1f93e3c7 100644
--- a/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp
+++ b/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp
@@ -14,16 +14,13 @@
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
-#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Optimizer/OpenMP/Passes.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
#include "mlir/IR/BuiltinOps.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/TypeSwitch.h"
namespace flangomp {
#define GEN_PASS_DEF_FUNCTIONFILTERINGPASS
@@ -68,41 +65,6 @@ checkDeviceImplementationStatus(omp::OffloadModuleInterface offloadModule) {
});
}
-/// Add an operation to one of the output sets to be later rewritten.
-template <typename OpTy>
-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 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,
- llvm::SetVector<omp::MapInfoOp> &rewrites) {
- for (Value member : mapOp.getMembers())
- collectRewrite(cast<omp::MapInfoOp>(member.getDefiningOp()), rewrites);
-
- 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.
-///
-/// 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>(
- cast<BlockArgument>(value).getOwner()->getParentOp())) ||
- rewrites.contains(value))
- return;
-
- rewrites.insert(value);
-}
-
namespace {
class FunctionFilteringPass
: public flangomp::impl::FunctionFilteringPassBase<FunctionFilteringPass> {
@@ -172,11 +134,6 @@ class FunctionFilteringPass
return WalkResult::skip();
}
- if (failed(rewriteHostFunction(funcOp))) {
- funcOp.emitOpError() << "could not be rewritten for target device";
- return WalkResult::interrupt();
- }
-
if (declareTargetOp)
declareTargetOp.setDeclareTarget(
declareType, omp::DeclareTargetCaptureClause::to,
@@ -187,308 +144,5 @@ class FunctionFilteringPass
checkDeviceImplementationStatus(op);
}
-
-private:
- /// 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.
- /// - \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.
- /// - \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 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
- /// operations will be discarded, as they aren't runnable by the target
- /// device.
- /// - \c omp.map.info operations associated to these target regions are
- /// preserved. These are moved above all \c omp.target and sorted to
- /// satisfy dependencies among them.
- /// - \c bounds arguments are removed from \c omp.map.info operations.
- /// - \c var_ptr and \c var_ptr_ptr arguments of \c omp.map.info are
- /// handled as follows:
- /// - \c var_ptr_ptr is expected to be defined by a \c fir.box_offset
- /// 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
- /// 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.
- 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();
- }
-
- // 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);
- }
- }
- return WalkResult::advance();
- });
-
- // 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(funcOp);
- Operation *newOp = builder.cloneWithoutRegions(funcOp);
- Block &block = newOp->getRegion(0).emplaceBlock();
-
- llvm::SmallVector<Location> locs;
- locs.reserve(region.getNumArguments());
- llvm::transform(region.getArguments(), std::back_inserter(locs),
- [](const BlockArgument &arg) { return arg.getLoc(); });
- block.addArguments(region.getArgumentTypes(), locs);
-
- for (auto [oldArg, newArg] :
- llvm::zip_equal(region.getArguments(), block.getArguments()))
- oldArg.replaceAllUsesWith(newArg);
-
- // 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 (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);
- for (Value threadLimit : targetOp.getThreadLimitVars())
- collectRewrite(threadLimit, rewriteValues);
- }
-
- // 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, declareOps);
- else
- collectRewrite(mapOp.getVarPtr(), rewriteValues);
-
- if (Value varPtrPtr = mapOp.getVarPtrPtr()) {
- if (auto boxOffset = llvm::dyn_cast_if_present<fir::BoxOffsetOp>(
- varPtrPtr.getDefiningOp()))
- collectRewrite(boxOffset, boxOffsets);
- else
- return mapOp->emitOpError() << "var_ptr_ptr rewrite only supported "
- "if defined by fir.box_offset";
- }
-
- // Bounds are not used during target device codegen.
- mapOp.getBoundsMutable().clear();
- mapOp->moveBefore(&block, block.end());
- }
-
- // Create a temporary marker to simplify the op moving process below.
- builder.setInsertionPointToStart(&block);
- auto marker = fir::UndefOp::create(builder, builder.getUnknownLoc(),
- builder.getNoneType());
- builder.setInsertionPoint(marker);
-
- // Handle dependencies of hlfir.declare ops.
- for (hlfir::DeclareOp declareOp : declareOps) {
- collectRewrite(declareOp.getMemref(), rewriteValues);
-
- if (declareOp.getStorage())
- collectRewrite(declareOp.getStorage(), rewriteValues);
-
- // Shape and typeparams aren't needed for target device codegen, but
- // removing them would break verifiers.
- Value zero;
- if (declareOp.getShape() || !declareOp.getTypeparams().empty())
- zero = arith::ConstantOp::create(builder, declareOp.getLoc(),
- builder.getI64IntegerAttr(0));
-
- if (auto shape = declareOp.getShape()) {
- // The pre-cg rewrite pass requires the shape to be defined by one of
- // fir.shape, fir.shapeshift or fir.shift, so we need to make sure it's
- // still defined by one of these after this pass.
- Operation *shapeOp = shape.getDefiningOp();
- llvm::SmallVector<Value> extents(shapeOp->getNumOperands(), zero);
- Value newShape =
- llvm::TypeSwitch<Operation *, Value>(shapeOp)
- .Case([&](fir::ShapeOp op) {
- return fir::ShapeOp::create(builder, op.getLoc(), extents);
- })
- .Case([&](fir::ShapeShiftOp op) {
- auto type = fir::ShapeShiftType::get(op.getContext(),
- extents.size() / 2);
- return fir::ShapeShiftOp::create(builder, op.getLoc(), type,
- extents);
- })
- .Case([&](fir::ShiftOp op) {
- auto type =
- fir::ShiftType::get(op.getContext(), extents.size());
- return fir::ShiftOp::create(builder, op.getLoc(), type,
- extents);
- })
- .Default([](Operation *op) {
- op->emitOpError()
- << "hlfir.declare shape expected to be one of: "
- "fir.shape, fir.shapeshift or fir.shift";
- return nullptr;
- });
-
- if (!newShape)
- return failure();
-
- declareOp.getShapeMutable().assign(newShape);
- }
-
- for (OpOperand &typeParam : declareOp.getTypeparamsMutable())
- typeParam.assign(zero);
-
- declareOp.getDummyScopeMutable().clear();
- }
-
- // We don't actually need the proper initialization, but rather just
- // maintain the basic form of these operands. Generally, we create 1-bit
- // placeholder allocas that we "typecast" to the expected type and replace
- // all uses. Using fir.undefined here instead is not possible because these
- // variables cannot be constants, as that would trigger different codegen
- // for target regions.
- for (Value value : rewriteValues) {
- Location loc = value.getLoc();
- Value rewriteValue;
- if (isa_and_present<arith::ConstantOp, fir::AddrOfOp>(
- value.getDefiningOp())) {
- // If it's defined by fir.address_of, then we need to keep that op as
- // well because it might be pointing to a 'declare target' global.
- // Constants can also trigger different codegen paths, so we keep them
- // as well.
- 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 = fir::AllocaOp::create(
- builder, loc, fir::CharacterType::getSingleton(ctx, kind));
- auto one = arith::ConstantOp::create(builder, loc, builder.getI32Type(),
- builder.getI32IntegerAttr(1));
- rewriteValue = fir::EmboxCharOp::create(builder, loc, boxCharType,
- placeholder, one);
- } else {
- Value placeholder =
- fir::AllocaOp::create(builder, loc, builder.getI1Type());
- rewriteValue =
- fir::ConvertOp::create(builder, loc, value.getType(), placeholder);
- }
- value.replaceAllUsesWith(rewriteValue);
- }
-
- // Move omp.map.info dependencies.
- for (hlfir::DeclareOp declareOp : declareOps)
- declareOp->moveBefore(marker);
-
- // The box_ref argument of fir.box_offset is expected to be the same value
- // that was passed as var_ptr to the corresponding omp.map.info, so we don't
- // need to handle its defining op here.
- for (fir::BoxOffsetOp boxOffset : boxOffsets)
- boxOffset->moveBefore(marker);
-
- marker->erase();
-
- // Move target operations to the end of the new block.
- for (omp::TargetOp targetOp : targetOps)
- targetOp->moveBefore(&block, block.end());
-
- // Add terminator to the new block.
- builder.setInsertionPointToEnd(&block);
- llvm::SmallVector<Value> returnValues;
- returnValues.reserve(funcOp.getNumResults());
- for (auto type : funcOp.getResultTypes())
- returnValues.push_back(
- fir::UndefOp::create(builder, funcOp.getLoc(), type));
-
- func::ReturnOp::create(builder, funcOp.getLoc(), returnValues);
-
- // Replace old region (now missing ops) with the new one and remove the
- // temporary operation clone.
- region.takeBody(newOp->getRegion(0));
- newOp->erase();
- return success();
- }
};
} // namespace
diff --git a/flang/lib/Optimizer/OpenMP/HostOpFiltering.cpp b/flang/lib/Optimizer/OpenMP/HostOpFiltering.cpp
new file mode 100644
index 0000000000000..4648ed8ddc7ea
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/HostOpFiltering.cpp
@@ -0,0 +1,409 @@
+//===- HostOpFiltering.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements transforms to filter out host-only operations from
+// any remaining host functions when compiling for a target device.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/OpenMP/Passes.h"
+
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+namespace flangomp {
+#define GEN_PASS_DEF_HOSTOPFILTERINGPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+/// Add an operation to one of the output sets to be later rewritten.
+template <typename OpTy>
+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 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,
+ llvm::SetVector<omp::MapInfoOp> &rewrites) {
+ for (Value member : mapOp.getMembers())
+ collectRewrite(cast<omp::MapInfoOp>(member.getDefiningOp()), rewrites);
+
+ 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.
+///
+/// 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>(
+ cast<BlockArgument>(value).getOwner()->getParentOp())) ||
+ rewrites.contains(value))
+ return;
+
+ rewrites.insert(value);
+}
+
+namespace {
+class HostOpFilteringPass
+ : public flangomp::impl::HostOpFilteringPassBase<HostOpFilteringPass> {
+public:
+ HostOpFilteringPass() = default;
+
+ void runOnOperation() override {
+ MLIRContext *context = &getContext();
+ OpBuilder opBuilder(context);
+ auto op = dyn_cast<omp::OffloadModuleInterface>(getOperation());
+ if (!op || !op.getIsTargetDevice())
+ return;
+
+ op->walk<WalkOrder::PreOrder>([&](func::FuncOp funcOp) {
+ omp::DeclareTargetDeviceType declareType =
+ omp::DeclareTargetDeviceType::host;
+ auto declareTargetOp =
+ dyn_cast<omp::DeclareTargetInterface>(funcOp.getOperation());
+ if (declareTargetOp && declareTargetOp.isDeclareTarget())
+ declareType = declareTargetOp.getDeclareTargetDeviceType();
+
+ // Only process host function definitions.
+ if (funcOp.isExternal() ||
+ declareType != omp::DeclareTargetDeviceType::host)
+ return WalkResult::advance();
+
+ if (failed(rewriteHostFunction(funcOp))) {
+ funcOp.emitOpError() << "could not filter host-only operations";
+ return WalkResult::interrupt();
+ }
+ return WalkResult::advance();
+ });
+ }
+
+private:
+ /// 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, after HLFIR to FIR lowering, and it performs the following
+ /// mutations:
+ /// - Replace all values returned by the function with \c fir.undefined.
+ /// - \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.
+ /// - \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 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
+ /// operations will be discarded, as they aren't runnable by the target
+ /// device.
+ /// - \c omp.map.info operations associated to these target regions are
+ /// preserved. These are moved above all \c omp.target and sorted to
+ /// satisfy dependencies among them.
+ /// - \c bounds arguments are removed from \c omp.map.info operations.
+ /// - \c var_ptr and \c var_ptr_ptr arguments of \c omp.map.info are
+ /// handled as follows:
+ /// - \c var_ptr_ptr is expected to be defined by a \c fir.box_offset
+ /// operation which is preserved. Otherwise, the pass will fail.
+ /// - \c var_ptr can be defined by a \c fir.declare which is also
+ /// preserved. Its \c memref argument is replaced by a placeholder or
+ /// 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.
+ 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();
+ }
+
+ // 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 a fir.declare, the uses of all users of that
+ // entry block argument that are themselves fir.declare are replaced
+ // by the value produced by the outer one.
+ //
+ // This prevents this pass from producing chains of fir.declare of the
+ // type:
+ // %0 = ...
+ // %1 = fir.declare %0
+ // %2 = fir.declare %1...
+ // %3 = omp.map.info var_ptr(%2 ...
+ if (auto outerDeclare = varPtr.getDefiningOp<fir::DeclareOp>())
+ for (Operation *user : blockArg.getUsers())
+ if (isa<fir::DeclareOp>(user))
+ user->replaceAllUsesWith(outerDeclare);
+
+ // All remaining uses of the entry block argument are replaced with
+ // the var_ptr initialization value.
+ blockArg.replaceAllUsesWith(varPtr);
+ }
+ }
+ return WalkResult::advance();
+ });
+
+ // 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(funcOp);
+ Operation *newOp = builder.cloneWithoutRegions(funcOp);
+ Block &block = newOp->getRegion(0).emplaceBlock();
+
+ llvm::SmallVector<Location> locs;
+ locs.reserve(region.getNumArguments());
+ llvm::transform(region.getArguments(), std::back_inserter(locs),
+ [](const BlockArgument &arg) { return arg.getLoc(); });
+ block.addArguments(region.getArgumentTypes(), locs);
+
+ for (auto [oldArg, newArg] :
+ llvm::zip_equal(region.getArguments(), block.getArguments()))
+ oldArg.replaceAllUsesWith(newArg);
+
+ // 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 (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);
+ for (Value threadLimit : targetOp.getThreadLimitVars())
+ collectRewrite(threadLimit, rewriteValues);
+ }
+
+ // Move omp.map.info ops to the new block and collect dependencies.
+ llvm::SetVector<fir::DeclareOp> declareOps;
+ llvm::SetVector<fir::BoxOffsetOp> boxOffsets;
+ for (omp::MapInfoOp mapOp : mapInfos) {
+ if (auto declareOp = dyn_cast_if_present<fir::DeclareOp>(
+ mapOp.getVarPtr().getDefiningOp()))
+ collectRewrite(declareOp, declareOps);
+ else
+ collectRewrite(mapOp.getVarPtr(), rewriteValues);
+
+ if (Value varPtrPtr = mapOp.getVarPtrPtr()) {
+ if (auto boxOffset = llvm::dyn_cast_if_present<fir::BoxOffsetOp>(
+ varPtrPtr.getDefiningOp()))
+ collectRewrite(boxOffset, boxOffsets);
+ else
+ return mapOp->emitOpError() << "var_ptr_ptr rewrite only supported "
+ "if defined by fir.box_offset";
+ }
+
+ // Bounds are not used during target device codegen.
+ mapOp.getBoundsMutable().clear();
+ mapOp->moveBefore(&block, block.end());
+ }
+
+ // Create a temporary marker to simplify the op moving process below.
+ builder.setInsertionPointToStart(&block);
+ auto marker = fir::UndefOp::create(builder, builder.getUnknownLoc(),
+ builder.getNoneType());
+ builder.setInsertionPoint(marker);
+
+ // Handle dependencies of fir.declare ops.
+ for (fir::DeclareOp declareOp : declareOps) {
+ // FIR: memref, shape, typeparams, dummy_scope, storage, storage_offset,
+ // uniq_name, fortran_attrs, data_attr, dummy_arg_no
+ // HLFIR: skip_rebox
+ collectRewrite(declareOp.getMemref(), rewriteValues);
+
+ if (declareOp.getStorage())
+ collectRewrite(declareOp.getStorage(), rewriteValues);
+
+ // Shape and typeparams aren't needed for target device codegen, but
+ // removing them would break verifiers.
+ Value zero;
+ if (declareOp.getShape() || !declareOp.getTypeparams().empty())
+ zero = arith::ConstantOp::create(builder, declareOp.getLoc(),
+ builder.getI64IntegerAttr(0));
+
+ if (auto shape = declareOp.getShape()) {
+ // The pre-cg rewrite pass requires the shape to be defined by one of
+ // fir.shape, fir.shapeshift or fir.shift, so we need to make sure it's
+ // still defined by one of these after this pass.
+ Operation *shapeOp = shape.getDefiningOp();
+ llvm::SmallVector<Value> extents(shapeOp->getNumOperands(), zero);
+ Value newShape =
+ llvm::TypeSwitch<Operation *, Value>(shapeOp)
+ .Case([&](fir::ShapeOp op) {
+ return fir::ShapeOp::create(builder, op.getLoc(), extents);
+ })
+ .Case([&](fir::ShapeShiftOp op) {
+ auto type = fir::ShapeShiftType::get(op.getContext(),
+ extents.size() / 2);
+ return fir::ShapeShiftOp::create(builder, op.getLoc(), type,
+ extents);
+ })
+ .Case([&](fir::ShiftOp op) {
+ auto type =
+ fir::ShiftType::get(op.getContext(), extents.size());
+ return fir::ShiftOp::create(builder, op.getLoc(), type,
+ extents);
+ })
+ .Default([](Operation *op) {
+ op->emitOpError()
+ << "fir.declare shape expected to be one of: "
+ "fir.shape, fir.shapeshift or fir.shift";
+ return nullptr;
+ });
+
+ if (!newShape)
+ return failure();
+
+ declareOp.getShapeMutable().assign(newShape);
+ }
+
+ for (OpOperand &typeParam : declareOp.getTypeparamsMutable())
+ typeParam.assign(zero);
+
+ declareOp.getDummyScopeMutable().clear();
+ }
+
+ // We don't actually need the proper initialization, but rather just
+ // maintain the basic form of these operands. Generally, we create 1-bit
+ // placeholder allocas that we "typecast" to the expected type and replace
+ // all uses. Using fir.undefined here instead is not possible because these
+ // variables cannot be constants, as that would trigger different codegen
+ // for target regions.
+ for (Value value : rewriteValues) {
+ Location loc = value.getLoc();
+ Value rewriteValue;
+ if (isa_and_present<arith::ConstantOp, fir::AddrOfOp>(
+ value.getDefiningOp())) {
+ // If it's defined by fir.address_of, then we need to keep that op as
+ // well because it might be pointing to a 'declare target' global.
+ // Constants can also trigger different codegen paths, so we keep them
+ // as well.
+ 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 = fir::AllocaOp::create(
+ builder, loc, fir::CharacterType::getSingleton(ctx, kind));
+ auto one = arith::ConstantOp::create(builder, loc, builder.getI32Type(),
+ builder.getI32IntegerAttr(1));
+ rewriteValue = fir::EmboxCharOp::create(builder, loc, boxCharType,
+ placeholder, one);
+ } else {
+ Value placeholder =
+ fir::AllocaOp::create(builder, loc, builder.getI1Type());
+ rewriteValue =
+ fir::ConvertOp::create(builder, loc, value.getType(), placeholder);
+ }
+ value.replaceAllUsesWith(rewriteValue);
+ }
+
+ // Move omp.map.info dependencies.
+ for (fir::DeclareOp declareOp : declareOps)
+ declareOp->moveBefore(marker);
+
+ // The box_ref argument of fir.box_offset is expected to be the same value
+ // that was passed as var_ptr to the corresponding omp.map.info, so we don't
+ // need to handle its defining op here.
+ for (fir::BoxOffsetOp boxOffset : boxOffsets)
+ boxOffset->moveBefore(marker);
+
+ marker->erase();
+
+ // Move target operations to the end of the new block.
+ for (omp::TargetOp targetOp : targetOps)
+ targetOp->moveBefore(&block, block.end());
+
+ // Add terminator to the new block.
+ builder.setInsertionPointToEnd(&block);
+ llvm::SmallVector<Value> returnValues;
+ returnValues.reserve(funcOp.getNumResults());
+ for (auto type : funcOp.getResultTypes())
+ returnValues.push_back(
+ fir::UndefOp::create(builder, funcOp.getLoc(), type));
+
+ func::ReturnOp::create(builder, funcOp.getLoc(), returnValues);
+
+ // Replace old region (now missing ops) with the new one and remove the
+ // temporary operation clone.
+ region.takeBody(newOp->getRegion(0));
+ newOp->erase();
+ return success();
+ }
+};
+} // namespace
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index bb1ad84523c82..51c0fa2cae63e 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -318,6 +318,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
if (enableOpenMP != EnableOpenMP::None) {
pm.addPass(flangomp::createLowerWorkshare());
pm.addPass(flangomp::createLowerWorkdistribute());
+ pm.addPass(flangomp::createHostOpFilteringPass());
}
if (enableOpenMP == EnableOpenMP::Simd)
pm.addPass(flangomp::createSimdOnlyPass());
diff --git a/flang/test/Fir/basic-program.fir b/flang/test/Fir/basic-program.fir
index 5f84395b36037..0e7ffbe1a4ee7 100644
--- a/flang/test/Fir/basic-program.fir
+++ b/flang/test/Fir/basic-program.fir
@@ -80,6 +80,7 @@ func.func @_QQmain() {
// PASSES-NEXT: ConvertHLFIRtoFIR
// PASSES-NEXT: LowerWorkshare
// PASSES-NEXT: LowerWorkdistribute
+// PASSES-NEXT: HostOpFilteringPass
// PASSES-NEXT: CSE
// PASSES-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
// PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
diff --git a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90
index e4e7bc902bff5..ffb54aee2b747 100644
--- a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90
+++ b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90
@@ -1,7 +1,7 @@
-!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefixes=BOTH,HOST
-!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-device %s -o - | FileCheck %s --check-prefixes=BOTH,DEVICE
-!RUN: bbc -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefixes=BOTH,HOST
-!RUN: bbc -emit-hlfir -fopenmp -fopenmp-is-target-device %s -o - | FileCheck %s --check-prefixes=BOTH,DEVICE
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-device %s -o - | FileCheck %s
+!RUN: bbc -emit-hlfir -fopenmp %s -o - | FileCheck %s
+!RUN: bbc -emit-hlfir -fopenmp -fopenmp-is-target-device %s -o - | FileCheck %s
program test_link
@@ -20,14 +20,13 @@ program test_link
integer, pointer :: test_ptr2
!$omp declare target link(test_ptr2)
- !BOTH-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<i32>, i32) map_clauses(implicit, tofrom) capture(ByRef) -> !fir.ref<i32> {name = "test_int"}
+ !CHECK: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<i32>, i32) map_clauses(implicit, tofrom) capture(ByRef) -> !fir.ref<i32> {name = "test_int"}
!$omp target
test_int = test_int + 1
!$omp end target
- !HOST-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.array<3xi32>>, !fir.array<3xi32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{%.*}}) -> !fir.ref<!fir.array<3xi32>> {name = "test_array_1d"}
- !DEVICE-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.array<3xi32>>, !fir.array<3xi32>) map_clauses(implicit, tofrom) capture(ByRef) -> !fir.ref<!fir.array<3xi32>> {name = "test_array_1d"}
+ !CHECK: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.array<3xi32>>, !fir.array<3xi32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{%.*}}) -> !fir.ref<!fir.array<3xi32>> {name = "test_array_1d"}
!$omp target
do i = 1,3
test_array_1d(i) = i * 2
@@ -36,18 +35,18 @@ program test_link
allocate(test_ptr1)
test_ptr1 = 1
- !BOTH-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(always, implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr1"}
+ !CHECK: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(always, implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr1"}
!$omp target
test_ptr1 = test_ptr1 + 1
!$omp end target
- !BOTH-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<i32>, i32) map_clauses(implicit, tofrom) capture(ByRef) -> !fir.ref<i32> {name = "test_target"}
+ !CHECK: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<i32>, i32) map_clauses(implicit, tofrom) capture(ByRef) -> !fir.ref<i32> {name = "test_target"}
!$omp target
test_target = test_target + 1
!$omp end target
- !BOTH-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(always, implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr2"}
+ !CHECK: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(always, implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr2"}
test_ptr2 => test_target
!$omp target
test_ptr2 = test_ptr2 + 1
diff --git a/flang/test/Lower/OpenMP/host-eval.f90 b/flang/test/Lower/OpenMP/host-eval.f90
index 7a9c08895189d..3bd873009530c 100644
--- a/flang/test/Lower/OpenMP/host-eval.f90
+++ b/flang/test/Lower/OpenMP/host-eval.f90
@@ -1,6 +1,6 @@
! The "thread_limit" clause was added to the "target" construct in OpenMP 5.1.
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s --check-prefixes=BOTH,HOST
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 -fopenmp-is-target-device %s -o - | FileCheck %s --check-prefixes=BOTH,DEVICE
+! RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s --check-prefixes=BOTH,HOST
+! RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -fopenmp-is-target-device %s -o - | FileCheck %s --check-prefixes=BOTH,DEVICE
! BOTH-LABEL: func.func @_QPteams
subroutine teams()
diff --git a/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir b/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir
index 9be258dc800d9..069e16abfe7d7 100644
--- a/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir
+++ b/flang/test/Transforms/OpenMP/function-filtering-host-ops.mlir
@@ -1,6 +1,10 @@
-// RUN: fir-opt --omp-function-filtering %s | FileCheck %s
+// RUN: fir-opt --omp-host-op-filtering %s | FileCheck %s
module attributes {omp.is_target_device = true} {
+ // CHECK-LABEL: func.func private @external
+ // CHECK-NOT: return
+ func.func private @external()
+
// CHECK-LABEL: func.func @basic_checks
// CHECK-SAME: (%[[ARG:.*]]: !fir.ref<i32>) -> (i32, f32)
func.func @basic_checks(%arg: !fir.ref<i32>) -> (i32, f32) {
@@ -12,23 +16,23 @@ module attributes {omp.is_target_device = true} {
func.call @foo() : () -> ()
- %0:2 = hlfir.declare %arg {uniq_name = "arg"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %0 = fir.declare %arg {uniq_name = "arg"} : (!fir.ref<i32>) -> !fir.ref<i32>
%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>)
+ %1 = fir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> !fir.ref<i32>
%alloc = fir.alloca i32
- %2:2 = hlfir.declare %alloc {uniq_name = "alloc"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %2 = fir.declare %alloc {uniq_name = "alloc"} : (!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: %[[ALLOC_DECL:.*]] = fir.declare %[[ALLOC]] {uniq_name = "alloc"}
+ // CHECK-NEXT: %[[ARG_DECL:.*]] = fir.declare %[[ARG]] {uniq_name = "arg"}
+ // CHECK-NEXT: %[[GLOBAL_DECL:.*]] = fir.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: %[[MAP2:.*]] = omp.map.info var_ptr(%[[ALLOC_DECL]]{{.*}})
+ // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[ARG_DECL]]{{.*}})
+ // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL]]{{.*}})
// CHECK-NEXT: %[[MAP3:.*]] = omp.map.info var_ptr(%[[ALLOC]]{{.*}})
- %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>
+ %m0 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m1 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m2 = omp.map.info var_ptr(%2 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
%m3 = omp.map.info var_ptr(%alloc : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK-NEXT: omp.target has_device_addr(%[[MAP2]] -> {{.*}} : {{.*}}) map_entries(%[[MAP0]] -> {{.*}}, %[[MAP1]] -> {{.*}}, %[[MAP3]] -> {{.*}} : {{.*}})
@@ -47,9 +51,9 @@ module attributes {omp.is_target_device = true} {
}
// 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>
+ %m4 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m5 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m6 = omp.map.info var_ptr(%2 : !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-NOT: omp.target_data
@@ -62,13 +66,13 @@ module attributes {omp.is_target_device = true} {
// 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>
+ %m8 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(to) capture(ByRef) -> !fir.ref<i32>
omp.target_enter_data map_entries(%m8 : !fir.ref<i32>)
- %m9 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(from) capture(ByRef) -> !fir.ref<i32>
+ %m9 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(from) capture(ByRef) -> !fir.ref<i32>
omp.target_exit_data map_entries(%m9 : !fir.ref<i32>)
- %m10 = omp.map.info var_ptr(%2#1 : !fir.ref<i32>, !fir.ref<i32>) map_clauses(to) capture(ByRef) -> !fir.ref<i32>
+ %m10 = omp.map.info var_ptr(%2 : !fir.ref<i32>, !fir.ref<i32>) map_clauses(to) capture(ByRef) -> !fir.ref<i32>
omp.target_update map_entries(%m10 : !fir.ref<i32>)
// CHECK-NOT: func.call
@@ -85,26 +89,26 @@ module attributes {omp.is_target_device = true} {
func.func @allocatable_array(%allocatable: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %array: !fir.ref<!fir.array<9xi32>>) {
// CHECK-NEXT: %[[ZERO:.*]] = arith.constant 0 : i64
// CHECK-NEXT: %[[SHAPE:.*]] = fir.shape %[[ZERO]] : (i64) -> !fir.shape<1>
- // CHECK-NEXT: %[[ALLOCATABLE_DECL:.*]]:2 = hlfir.declare %[[ALLOCATABLE]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "allocatable"} : ([[ALLOCATABLE_TYPE]]) -> ([[ALLOCATABLE_TYPE]], [[ALLOCATABLE_TYPE]])
- // CHECK-NEXT: %[[ARRAY_DECL:.*]]:2 = hlfir.declare %[[ARRAY]](%[[SHAPE]]) {uniq_name = "array"} : ([[ARRAY_TYPE]], !fir.shape<1>) -> ([[ARRAY_TYPE]], [[ARRAY_TYPE]])
- // CHECK-NEXT: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[ALLOCATABLE_DECL]]#1 base_addr : ([[ALLOCATABLE_TYPE]]) -> [[VAR_PTR_PTR_TYPE:.*]]
- // CHECK-NEXT: %[[MAP_ALLOCATABLE:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_DECL]]#1 : [[ALLOCATABLE_TYPE]], f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAR_PTR_PTR]] : [[VAR_PTR_PTR_TYPE]]) -> [[VAR_PTR_PTR_TYPE]]
- // CHECK-NEXT: %[[MAP_ARRAY:.*]] = omp.map.info var_ptr(%[[ARRAY_DECL]]#1 : [[ARRAY_TYPE]], !fir.array<9xi32>) map_clauses(tofrom) capture(ByRef) -> [[ARRAY_TYPE]]
+ // CHECK-NEXT: %[[ALLOCATABLE_DECL:.*]] = fir.declare %[[ALLOCATABLE]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "allocatable"} : ([[ALLOCATABLE_TYPE]]) -> [[ALLOCATABLE_TYPE]]
+ // CHECK-NEXT: %[[ARRAY_DECL:.*]] = fir.declare %[[ARRAY]](%[[SHAPE]]) {uniq_name = "array"} : ([[ARRAY_TYPE]], !fir.shape<1>) -> [[ARRAY_TYPE]]
+ // CHECK-NEXT: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[ALLOCATABLE_DECL]] base_addr : ([[ALLOCATABLE_TYPE]]) -> [[VAR_PTR_PTR_TYPE:.*]]
+ // CHECK-NEXT: %[[MAP_ALLOCATABLE:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_DECL]] : [[ALLOCATABLE_TYPE]], f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAR_PTR_PTR]] : [[VAR_PTR_PTR_TYPE]]) -> [[VAR_PTR_PTR_TYPE]]
+ // CHECK-NEXT: %[[MAP_ARRAY:.*]] = omp.map.info var_ptr(%[[ARRAY_DECL]] : [[ARRAY_TYPE]], !fir.array<9xi32>) map_clauses(tofrom) capture(ByRef) -> [[ARRAY_TYPE]]
// CHECK-NEXT: omp.target map_entries(%[[MAP_ALLOCATABLE]] -> %{{.*}}, %[[MAP_ARRAY]] -> %{{.*}} : [[VAR_PTR_PTR_TYPE]], [[ARRAY_TYPE]])
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c8 = arith.constant 8 : index
%c9 = arith.constant 9 : index
- %0:2 = hlfir.declare %allocatable {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "allocatable"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
+ %0 = fir.declare %allocatable {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "allocatable"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
%1 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c8 : index) extent(%c9 : index) stride(%c1 : index) start_idx(%c1 : index)
- %2 = fir.box_offset %0#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
- %m0 = omp.map.info var_ptr(%0#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%2 : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) bounds(%1) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
+ %2 = fir.box_offset %0 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
+ %m0 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%2 : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) bounds(%1) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
%3 = fir.shape %c9 : (index) -> !fir.shape<1>
- %4:2 = hlfir.declare %array(%3) {uniq_name = "array"} : (!fir.ref<!fir.array<9xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<9xi32>>, !fir.ref<!fir.array<9xi32>>)
+ %4 = fir.declare %array(%3) {uniq_name = "array"} : (!fir.ref<!fir.array<9xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<9xi32>>
%5 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c8 : index) extent(%c9 : index) stride(%c1 : index) start_idx(%c1 : index)
- %6 = omp.map.info var_ptr(%4#1 : !fir.ref<!fir.array<9xi32>>, !fir.array<9xi32>) map_clauses(tofrom) capture(ByRef) bounds(%5) -> !fir.ref<!fir.array<9xi32>>
+ %6 = omp.map.info var_ptr(%4 : !fir.ref<!fir.array<9xi32>>, !fir.array<9xi32>) map_clauses(tofrom) capture(ByRef) bounds(%5) -> !fir.ref<!fir.array<9xi32>>
omp.target map_entries(%m0 -> %arg0, %6 -> %arg1 : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>, !fir.ref<!fir.array<9xi32>>) {
omp.terminator
@@ -118,10 +122,10 @@ module attributes {omp.is_target_device = true} {
// CHECK-NEXT: %[[ZERO]] = arith.constant 0 : i64
%0 = fir.dummy_scope : !fir.dscope
%c1 = arith.constant 1 : index
- // CHECK-NEXT: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] typeparams %[[ZERO]] {uniq_name = "x"} : ([[X_TYPE]], i64) -> ([[X_TYPE]], [[X_TYPE]])
- %3:2 = hlfir.declare %x typeparams %c1 dummy_scope %0 {uniq_name = "x"} : (!fir.ref<!fir.char<1>>, index, !fir.dscope) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
- // CHECK-NEXT: %[[MAP:.*]] = omp.map.info var_ptr(%[[X_DECL]]#1 : [[X_TYPE]], !fir.char<1>) map_clauses(tofrom) capture(ByRef) -> [[X_TYPE]]
- %map = omp.map.info var_ptr(%3#1 : !fir.ref<!fir.char<1>>, !fir.char<1>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.char<1>>
+ // CHECK-NEXT: %[[X_DECL:.*]] = fir.declare %[[X]] typeparams %[[ZERO]] {uniq_name = "x"} : ([[X_TYPE]], i64) -> [[X_TYPE]]
+ %3 = fir.declare %x typeparams %c1 dummy_scope %0 {uniq_name = "x"} : (!fir.ref<!fir.char<1>>, index, !fir.dscope) -> !fir.ref<!fir.char<1>>
+ // CHECK-NEXT: %[[MAP:.*]] = omp.map.info var_ptr(%[[X_DECL]] : [[X_TYPE]], !fir.char<1>) map_clauses(tofrom) capture(ByRef) -> [[X_TYPE]]
+ %map = omp.map.info var_ptr(%3 : !fir.ref<!fir.char<1>>, !fir.char<1>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.char<1>>
// CHECK-NEXT: omp.target map_entries(%[[MAP]] -> %{{.*}})
omp.target map_entries(%map -> %arg0 : !fir.ref<!fir.char<1>>) {
omp.terminator
@@ -136,17 +140,18 @@ module attributes {omp.is_target_device = true} {
// CHECK-NEXT: %[[ALLOCA:.*]] = fir.convert %[[PLACEHOLDER]] : (!fir.ref<i1>) -> !fir.ref<[[X_TYPE]]>
%0 = fir.alloca !fir.box<!fir.array<*:f32>>
%1 = fir.dummy_scope : !fir.dscope
- %2:2 = hlfir.declare %x dummy_scope %1 {uniq_name = "x"} : (!fir.box<!fir.array<*:f32>>, !fir.dscope) -> (!fir.box<!fir.array<*:f32>>, !fir.box<!fir.array<*:f32>>)
- %3 = fir.box_addr %2#1 : (!fir.box<!fir.array<*:f32>>) -> !fir.ref<!fir.array<*:f32>>
- fir.store %2#1 to %0 : !fir.ref<!fir.box<!fir.array<*:f32>>>
+ %2 = fir.declare %x dummy_scope %1 {uniq_name = "x"} : (!fir.box<!fir.array<*:f32>>, !fir.dscope) -> !fir.box<!fir.array<*:f32>>
+ %3 = fir.rebox_assumed_rank %2 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ %4 = fir.box_addr %3 : (!fir.box<!fir.array<*:f32>>) -> !fir.ref<!fir.array<*:f32>>
+ fir.store %3 to %0 : !fir.ref<!fir.box<!fir.array<*:f32>>>
// CHECK-NEXT: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[ALLOCA]] base_addr : (!fir.ref<[[X_TYPE]]>) -> [[VAR_PTR_PTR_TYPE:.*]]
- %4 = fir.box_offset %0 base_addr : (!fir.ref<!fir.box<!fir.array<*:f32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>
+ %5 = fir.box_offset %0 base_addr : (!fir.ref<!fir.box<!fir.array<*:f32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>
// CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref<[[X_TYPE]]>, !fir.array<*:f32>) {{.*}} var_ptr_ptr(%[[VAR_PTR_PTR]] : [[VAR_PTR_PTR_TYPE]]) -> [[VAR_PTR_PTR_TYPE]]
- %5 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.array<*:f32>>>, !fir.array<*:f32>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%4 : !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>
+ %6 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.array<*:f32>>>, !fir.array<*:f32>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%5 : !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>
// CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref<[[X_TYPE]]>, !fir.box<!fir.array<*:f32>>) {{.*}} members(%[[MAP0]] : [0] : [[VAR_PTR_PTR_TYPE]]) -> !fir.ref<!fir.array<*:f32>>
- %6 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.array<*:f32>>>, !fir.box<!fir.array<*:f32>>) map_clauses(to) capture(ByRef) members(%5 : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>) -> !fir.ref<!fir.array<*:f32>>
+ %7 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.array<*:f32>>>, !fir.box<!fir.array<*:f32>>) map_clauses(to) capture(ByRef) members(%6 : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>) -> !fir.ref<!fir.array<*:f32>>
// CHECK-NEXT: omp.target map_entries(%[[MAP1]] -> %{{.*}}, %[[MAP0]] -> {{.*}})
- omp.target map_entries(%6 -> %arg1, %5 -> %arg2 : !fir.ref<!fir.array<*:f32>>, !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>) {
+ omp.target map_entries(%7 -> %arg1, %6 -> %arg2 : !fir.ref<!fir.array<*:f32>>, !fir.llvm_ptr<!fir.ref<!fir.array<*:f32>>>) {
omp.terminator
}
return
@@ -161,7 +166,7 @@ module attributes {omp.is_target_device = true} {
// CHECK-NEXT: %[[ALLOCA_X:.*]] = fir.convert %[[PLACEHOLDER_X]] : (!fir.ref<i1>) -> [[X_TYPE]]
%0 = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>>
%1 = fir.dummy_scope : !fir.dscope
- %2:2 = hlfir.declare %x dummy_scope %1 {fortran_attrs = #fir.var_attrs<contiguous, pointer>, uniq_name = "x"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+ %2 = fir.declare %x dummy_scope %1 {fortran_attrs = #fir.var_attrs<contiguous, pointer>, uniq_name = "x"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
%3 = fir.load %2#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
fir.store %3 to %0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
@@ -180,26 +185,27 @@ module attributes {omp.is_target_device = true} {
%9:3 = fir.box_dims %3, %c0_2 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
%10 = fir.shape_shift %9#0, %9#1 : (index, index) -> !fir.shapeshift<1>
- // CHECK-NEXT: %[[Y_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_Y]](%[[SHAPE]]) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "y"} : ([[Y_TYPE]], !fir.shapeshift<1>) -> (!fir.box<!fir.array<?xi32>>, [[Y_TYPE]])
- %11:2 = hlfir.declare %8(%10) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "y"} : (!fir.ptr<!fir.array<?xi32>>, !fir.shapeshift<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ptr<!fir.array<?xi32>>)
+ // CHECK-NEXT: %[[Y_DECL:.*]] = fir.declare %[[ALLOCA_Y]](%[[SHAPE]]) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "y"} : ([[Y_TYPE]], !fir.shapeshift<1>) -> !fir.ptr<!fir.array<?xi32>>
+ %11 = fir.declare %8(%10) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "y"} : (!fir.ptr<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.ptr<!fir.array<?xi32>>
+ %12 = fir.embox %11(%10) : (!fir.ptr<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?xi32>>
%c1_3 = arith.constant 1 : index
%c0_4 = arith.constant 0 : index
- %12:3 = fir.box_dims %11#0, %c0_4 : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
+ %13:3 = fir.box_dims %12, %c0_4 : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
%c0_5 = arith.constant 0 : index
- %13 = arith.subi %12#1, %c1_3 : index
- %14 = omp.map.bounds lower_bound(%c0_5 : index) upper_bound(%13 : index) extent(%12#1 : index) stride(%12#2 : index) start_idx(%9#0 : index) {stride_in_bytes = true}
+ %14 = arith.subi %13#1, %c1_3 : index
+ %15 = omp.map.bounds lower_bound(%c0_5 : index) upper_bound(%14 : index) extent(%13#1 : index) stride(%13#2 : index) start_idx(%9#0 : index) {stride_in_bytes = true}
// CHECK-NEXT: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[ALLOCA_X]] base_addr : ([[X_TYPE]]) -> [[VAR_PTR_PTR_TYPE:.*]]
- // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[Y_DECL]]#1 : [[Y_TYPE]], i32) {{.*}} -> [[Y_TYPE]]
+ // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[Y_DECL]] : [[Y_TYPE]], i32) {{.*}} -> [[Y_TYPE]]
// CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[ALLOCA_X]] : [[X_TYPE]], i32) {{.*}} var_ptr_ptr(%[[VAR_PTR_PTR]] : [[VAR_PTR_PTR_TYPE]]) -> [[VAR_PTR_PTR_TYPE]]
// CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[ALLOCA_X]] : [[X_TYPE]], !fir.box<!fir.ptr<!fir.array<?xi32>>>) {{.*}} members(%[[MAP1]] : [0] : [[VAR_PTR_PTR_TYPE]]) -> [[X_TYPE]]
- %15 = omp.map.info var_ptr(%11#1 : !fir.ptr<!fir.array<?xi32>>, i32) map_clauses(tofrom) capture(ByRef) bounds(%14) -> !fir.ptr<!fir.array<?xi32>>
- %16 = fir.box_offset %0 base_addr : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
- %17 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%16 : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) bounds(%7) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
- %18 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.box<!fir.ptr<!fir.array<?xi32>>>) map_clauses(implicit, to) capture(ByRef) members(%17 : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %16 = omp.map.info var_ptr(%11 : !fir.ptr<!fir.array<?xi32>>, i32) map_clauses(tofrom) capture(ByRef) bounds(%15) -> !fir.ptr<!fir.array<?xi32>>
+ %17 = fir.box_offset %0 base_addr : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ %18 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%17 : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) bounds(%7) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ %19 = omp.map.info var_ptr(%0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.box<!fir.ptr<!fir.array<?xi32>>>) map_clauses(implicit, to) capture(ByRef) members(%18 : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
// CHECK-NEXT: omp.target map_entries(%[[MAP0]] -> %{{.*}}, %[[MAP2]] -> %{{.*}}, %[[MAP1]] -> {{.*}} : [[Y_TYPE]], [[X_TYPE]], [[VAR_PTR_PTR_TYPE]])
- omp.target map_entries(%15 -> %arg1, %18 -> %arg2, %17 -> %arg3 : !fir.ptr<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+ omp.target map_entries(%16 -> %arg1, %19 -> %arg2, %18 -> %arg3 : !fir.ptr<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
omp.terminator
}
return
@@ -208,27 +214,27 @@ module attributes {omp.is_target_device = true} {
// CHECK-LABEL: func.func @target_data
// 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-NEXT: %[[MAPPED_DECL:.*]] = fir.declare %[[MAPPED]] {uniq_name = "mapped"} : ([[MAPPED_TYPE]]) -> [[MAPPED_TYPE]]
+ // CHECK-NEXT: %[[USEDEVADDR_DECL:.*]] = fir.declare %[[USEDEVADDR]] {uniq_name = "usedevaddr"} : ([[USEDEVADDR_TYPE]]) -> [[USEDEVADDR_TYPE]]
+ // CHECK-NEXT: %[[USEDEVPTR_DECL:.*]] = fir.declare %[[USEDEVPTR]] {uniq_name = "usedevptr"} : ([[USEDEVPTR_TYPE]]) -> [[USEDEVPTR_TYPE]]
+ %0 = fir.declare %mapped {uniq_name = "mapped"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %1 = fir.declare %usedevaddr {uniq_name = "usedevaddr"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %2 = fir.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}>>
+
+ // CHECK-NEXT: %[[MAPPED_MAP:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]] : [[MAPPED_TYPE]], i32) map_clauses(tofrom) capture(ByRef) -> [[MAPPED_TYPE]]
+ // CHECK-NEXT: %[[USEDEVADDR_MAP:.*]] = omp.map.info var_ptr(%[[USEDEVADDR_DECL]] : [[USEDEVADDR_TYPE]], i32) map_clauses(tofrom) capture(ByRef) -> [[USEDEVADDR_TYPE]]
+ // CHECK-NEXT: %[[USEDEVPTR_MAP:.*]] = omp.map.info var_ptr(%[[USEDEVPTR_DECL]] : [[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 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m1 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(return_param) capture(ByRef) -> !fir.ref<i32>
+ %m2 = omp.map.info var_ptr(%2 : !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-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}>>) {
- %3:2 = hlfir.declare %arg0 {uniq_name = "usedevaddr"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
- %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}>>)
- %m3 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
- %m4 = omp.map.info var_ptr(%3#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
- %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}>>
+ %3 = fir.declare %arg0 {uniq_name = "usedevaddr"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %4 = fir.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}>>
+ %m3 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m4 = omp.map.info var_ptr(%3 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m5 = omp.map.info var_ptr(%4 : !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
func.call @foo() : () -> ()
@@ -248,14 +254,32 @@ module attributes {omp.is_target_device = true} {
return
}
+ // CHECK-LABEL: func.func @no_target
+ // CHECK-SAME: (%[[MAPPED:.*]]: !fir.ref<i32>)
+ func.func @no_target(%mapped: !fir.ref<i32>) {
+ // CHECK-NEXT: return
+ %0 = fir.declare %mapped {uniq_name = "mapped"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m0 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ omp.target_data map_entries(%m0 : !fir.ref<i32>) {
+ %m1 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ omp.target_data map_entries(%m1 : !fir.ref<i32>) {
+ func.call @foo() : () -> ()
+ omp.terminator
+ }
+ func.call @foo() : () -> ()
+ omp.terminator
+ }
+ return
+ }
+
// CHECK-LABEL: func.func @map_info_members
// CHECK-SAME: (%[[X:.*]]: [[X_TYPE:[^)]*]])
func.func @map_info_members(%x: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c9 = arith.constant 9 : index
- // CHECK-NEXT: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "x"} : ([[X_TYPE]]) -> ([[X_TYPE]], [[X_TYPE]])
- %23:2 = hlfir.declare %x {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "x"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
+ // CHECK-NEXT: %[[X_DECL:.*]] = fir.declare %[[X]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "x"} : ([[X_TYPE]]) -> [[X_TYPE]]
+ %23 = fir.declare %x {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "x"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
%63 = fir.load %23#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
%64:3 = fir.box_dims %63, %c0 : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
%65:3 = fir.box_dims %63, %c0 : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
@@ -264,12 +288,12 @@ module attributes {omp.is_target_device = true} {
%68 = fir.load %23#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
%69:3 = fir.box_dims %68, %c0 : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
%70 = omp.map.bounds lower_bound(%66 : index) upper_bound(%67 : index) extent(%69#1 : index) stride(%65#2 : index) start_idx(%64#0 : index) {stride_in_bytes = true}
- // CHECK-NEXT: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[X_DECL]]#1 base_addr : ([[X_TYPE]]) -> [[VAR_PTR_PTR_TYPE:.*]]
- %71 = fir.box_offset %23#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
- // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[X_DECL]]#1 : [[X_TYPE]], f32) {{.*}} var_ptr_ptr(%[[VAR_PTR_PTR]] : [[VAR_PTR_PTR_TYPE]]) -> [[VAR_PTR_PTR_TYPE]]
- %72 = omp.map.info var_ptr(%23#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%71 : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) bounds(%70) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
- // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[X_DECL]]#1 : [[X_TYPE]], !fir.box<!fir.heap<!fir.array<?xf32>>>) {{.*}} members(%[[MAP0]] : [0] : [[VAR_PTR_PTR_TYPE]]) -> [[X_TYPE]]
- %73 = omp.map.info var_ptr(%23#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.box<!fir.heap<!fir.array<?xf32>>>) map_clauses(to) capture(ByRef) members(%72 : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+ // CHECK-NEXT: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[X_DECL]] base_addr : ([[X_TYPE]]) -> [[VAR_PTR_PTR_TYPE:.*]]
+ %71 = fir.box_offset %23 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
+ // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[X_DECL]] : [[X_TYPE]], f32) {{.*}} var_ptr_ptr(%[[VAR_PTR_PTR]] : [[VAR_PTR_PTR_TYPE]]) -> [[VAR_PTR_PTR_TYPE]]
+ %72 = omp.map.info var_ptr(%23 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%71 : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) bounds(%70) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
+ // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[X_DECL]] : [[X_TYPE]], !fir.box<!fir.heap<!fir.array<?xf32>>>) {{.*}} members(%[[MAP0]] : [0] : [[VAR_PTR_PTR_TYPE]]) -> [[X_TYPE]]
+ %73 = omp.map.info var_ptr(%23 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.box<!fir.heap<!fir.array<?xf32>>>) map_clauses(to) capture(ByRef) members(%72 : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
// CHECK-NEXT: omp.target map_entries(%[[MAP1]] -> {{.*}}, %[[MAP0]] -> %{{.*}} : [[X_TYPE]], [[VAR_PTR_PTR_TYPE]])
omp.target map_entries(%73 -> %arg0, %72 -> %arg1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) {
omp.terminator
@@ -280,17 +304,17 @@ module attributes {omp.is_target_device = true} {
// CHECK-LABEL: func.func @control_flow
// CHECK-SAME: (%[[X:.*]]: [[X_TYPE:[^,]*]], %[[COND:.*]]: [[COND_TYPE:[^)]*]])
func.func @control_flow(%x: !fir.ref<i32>, %cond: !fir.ref<!fir.logical<4>>) {
- // CHECK-NEXT: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "x"} : ([[X_TYPE]]) -> ([[X_TYPE]], [[X_TYPE]])
- // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[X_DECL]]#1 : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
- // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[X_DECL]]#1 : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
- %x_decl:2 = hlfir.declare %x {uniq_name = "x"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
- %cond_decl:2 = hlfir.declare %cond {uniq_name = "cond"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+ // CHECK-NEXT: %[[X_DECL:.*]] = fir.declare %[[X]] {uniq_name = "x"} : ([[X_TYPE]]) -> [[X_TYPE]]
+ // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[X_DECL]] : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
+ // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[X_DECL]] : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
+ %x_decl = fir.declare %x {uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %cond_decl = fir.declare %cond {uniq_name = "cond"} : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>>
%0 = fir.load %cond_decl#0 : !fir.ref<!fir.logical<4>>
%1 = fir.convert %0 : (!fir.logical<4>) -> i1
cf.cond_br %1, ^bb1, ^bb2
^bb1: // pred: ^bb0
fir.call @foo() : () -> ()
- %m0 = omp.map.info var_ptr(%x_decl#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m0 = omp.map.info var_ptr(%x_decl : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK-NEXT: omp.target map_entries(%[[MAP0]] -> {{.*}} : [[X_TYPE]])
omp.target map_entries(%m0 -> %arg2 : !fir.ref<i32>) {
omp.terminator
@@ -302,7 +326,7 @@ module attributes {omp.is_target_device = true} {
// CHECK-NOT: omp.map.info
// 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>
+ %m1 = omp.map.info var_ptr(%x_decl : !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>>
@@ -310,7 +334,7 @@ module attributes {omp.is_target_device = true} {
cf.cond_br %9, ^bb1, ^bb2
^bb1: // pred: ^bb0
fir.call @foo() : () -> ()
- %m2 = omp.map.info var_ptr(%x_decl#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m2 = omp.map.info var_ptr(%x_decl : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK: omp.target map_entries(%[[MAP1]] -> {{.*}} : [[X_TYPE]])
omp.target map_entries(%m2 -> %arg2 : !fir.ref<i32>) {
omp.terminator
@@ -336,14 +360,14 @@ module attributes {omp.is_target_device = true} {
// CHECK-NEXT: %[[ALLOCA0:.*]] = fir.convert %[[PLACEHOLDER0]] : (!fir.ref<i1>) -> !fir.ref<i32>
// CHECK-NEXT: %[[PLACEHOLDER1:.*]] = fir.alloca i1
// CHECK-NEXT: %[[ALLOCA1:.*]] = fir.convert %[[PLACEHOLDER1]] : (!fir.ref<i1>) -> !fir.ref<i32>
- // CHECK-NEXT: %[[X_DECL0:.*]]:2 = hlfir.declare %[[ALLOCA0]] {uniq_name = "x"} : ([[X_TYPE]]) -> ([[X_TYPE]], [[X_TYPE]])
- // CHECK-NEXT: %[[X_DECL1:.*]]:2 = hlfir.declare %[[ALLOCA1]] {uniq_name = "x"} : ([[X_TYPE]]) -> ([[X_TYPE]], [[X_TYPE]])
- // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[X_DECL0]]#1 : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
- // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[X_DECL1]]#1 : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
- %x_decl:2 = hlfir.declare %x {uniq_name = "x"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ // CHECK-NEXT: %[[X_DECL0:.*]] = fir.declare %[[ALLOCA0]] {uniq_name = "x"} : ([[X_TYPE]]) -> [[X_TYPE]]
+ // CHECK-NEXT: %[[X_DECL1:.*]] = fir.declare %[[ALLOCA1]] {uniq_name = "x"} : ([[X_TYPE]]) -> [[X_TYPE]]
+ // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[X_DECL0]] : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
+ // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[X_DECL1]] : [[X_TYPE]], i32) {{.*}} -> [[X_TYPE]]
+ %x_decl = fir.declare %x {uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
omp.parallel private(@privatizer %x_decl#0 -> %arg0 : !fir.ref<i32>) {
- %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!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>
+ %0 = fir.declare %arg0 {uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m0 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK-NEXT: omp.target map_entries(%[[MAP0]] -> {{.*}} : [[X_TYPE]])
omp.target map_entries(%m0 -> %arg2 : !fir.ref<i32>) {
omp.terminator
@@ -352,16 +376,16 @@ module attributes {omp.is_target_device = true} {
}
// CHECK-NOT: omp.parallel
- // CHECK-NOT: hlfir.declare
+ // CHECK-NOT: fir.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>
+ omp.parallel private(@privatizer %x_decl -> %arg0 : !fir.ref<i32>) {
+ %1 = fir.declare %arg0 {uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m1 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
omp.target_data map_entries(%m1 : !fir.ref<i32>) {
- omp.parallel private(@privatizer %1#0 -> %arg1 : !fir.ref<i32>) {
- %2:2 = hlfir.declare %arg1 {uniq_name = "x"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
- %m2 = omp.map.info var_ptr(%2#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ omp.parallel private(@privatizer %1 -> %arg1 : !fir.ref<i32>) {
+ %2 = fir.declare %arg1 {uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m2 = omp.map.info var_ptr(%2 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK: omp.target map_entries(%[[MAP1]] -> {{.*}} : [[X_TYPE]])
omp.target map_entries(%m2 -> %arg2 : !fir.ref<i32>) {
omp.terminator
@@ -383,19 +407,19 @@ module attributes {omp.is_target_device = true} {
// CHECK-NEXT: %[[CONST:.*]] = arith.constant 1 : i32
// CHECK-NEXT: %[[GLOBAL:.*]] = fir.address_of(@global_scalar) : !fir.ref<i32>
%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"}
- // 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: %[[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: %[[GLOBAL_DECL0:.*]] = fir.declare %[[GLOBAL]] {uniq_name = "global_scalar"}
+ // CHECK-NEXT: %[[GLOBAL_DECL1:.*]] = fir.declare %[[GLOBAL]] {uniq_name = "global_scalar"}
+ // CHECK-NEXT: %[[GLOBAL_DECL2:.*]] = fir.declare %[[GLOBAL]] {uniq_name = "global_scalar"}
+ // CHECK-NEXT: %[[MAP0:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL0]] : !fir.ref<i32>, i32)
+ // CHECK-NEXT: %[[MAP1:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL1]] : !fir.ref<i32>, i32)
+ // CHECK-NEXT: %[[MAP2:.*]] = omp.map.info var_ptr(%[[GLOBAL_DECL2]] : !fir.ref<i32>, i32)
+ %0 = fir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m0 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK-NOT: omp.target_data
omp.target_data map_entries(%m0 : !fir.ref<i32>) {
- %1:2 = hlfir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
- %m1 = omp.map.info var_ptr(%0#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
- %m2 = omp.map.info var_ptr(%1#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %1 = fir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m1 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %m2 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !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
@@ -403,11 +427,11 @@ module attributes {omp.is_target_device = true} {
omp.terminator
}
// CHECK-NOT: fir.load
- // CHECK-NOT: hlfir.declare
+ // CHECK-NOT: fir.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>
+ %3 = fir.declare %global {uniq_name = "global_scalar"} : (!fir.ref<i32>) -> !fir.ref<i32>
+ %m3 = omp.map.info var_ptr(%3 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !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
@@ -464,15 +488,16 @@ module attributes {omp.is_target_device = true} {
%0 = fir.alloca !fir.boxchar<1>
%1 = fir.dummy_scope : !fir.dscope
%2:2 = fir.unboxchar %arg : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
- %3:2 = hlfir.declare %2#0 typeparams %2#1 dummy_scope %1 {uniq_name = "arg"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
- omp.target private(@boxchar_firstprivatizer %3#0 -> %arg3 [map_idx=0] : !fir.boxchar<1>) {
+ %3 = fir.declare %2#0 typeparams %2#1 dummy_scope %1 {uniq_name = "arg"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> !fir.ref<!fir.char<1,?>>
+ %4 = fir.emboxchar %3, %2#1 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
+ omp.target private(@boxchar_firstprivatizer %4 -> %arg3 [map_idx=0] : !fir.boxchar<1>) {
omp.terminator
}
return
}
- // CHECK-LABEL: func.func @hlfir_storage
- func.func @hlfir_storage(%i : index) {
+ // CHECK-LABEL: func.func @declare_storage
+ func.func @declare_storage(%i : index) {
// CHECK-NEXT: %[[PLACEHOLDER:.*]] = fir.alloca i1
// CHECK-NEXT: %[[VAR:.*]] = fir.convert %[[PLACEHOLDER]] : (!fir.ref<i1>) -> !fir.ref<i32>
// CHECK-NEXT: %[[GLOBAL:.*]] = fir.address_of(@block_) : !fir.ref<!fir.array<8xi8>>
@@ -480,10 +505,10 @@ module attributes {omp.is_target_device = true} {
%1 = fir.convert %0 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
%2 = fir.coordinate_of %1, %i : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<i32>
- // CHECK-NEXT: %[[DECL:.*]]:2 = hlfir.declare %[[VAR]] storage(%[[GLOBAL]][0])
- %4:2 = hlfir.declare %3 storage (%0[0]) {uniq_name = "a"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
- // CHECK-NEXT: %[[MAP:.*]] = omp.map.info var_ptr(%[[DECL]]#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
- %map = omp.map.info var_ptr(%4#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ // CHECK-NEXT: %[[DECL:.*]] = fir.declare %[[VAR]] storage(%[[GLOBAL]][0])
+ %4 = fir.declare %3 storage (%0[0]) {uniq_name = "a"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<i32>
+ // CHECK-NEXT: %[[MAP:.*]] = omp.map.info var_ptr(%[[DECL]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ %map = omp.map.info var_ptr(%4 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
// CHECK-NEXT: omp.target map_entries(%[[MAP]] -> %{{.*}} : !fir.ref<i32>)
omp.target map_entries(%map -> %arg0 : !fir.ref<i32>) {
omp.terminator
@@ -499,7 +524,7 @@ module attributes {omp.is_target_device = true} {
omp.private {type = firstprivate} @privatizer : i32 copy {
^bb0(%arg0: !fir.ref<i32>, %arg1: !fir.ref<i32>):
%0 = fir.load %arg0 : !fir.ref<i32>
- hlfir.assign %0 to %arg1 : i32, !fir.ref<i32>
+ fir.store %0 to %arg1 : !fir.ref<i32>
omp.yield(%arg1 : !fir.ref<i32>)
}
omp.declare_reduction @reduction : i32
More information about the flang-commits
mailing list