[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/bhandarkar-pranav approved this pull request. Thanks for the changes @TIFitis. LGTM https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
TIFitis wrote: > Thank you again Akash, LGTM minus some NFC suggestions. Please wait for > @bhandarkar-pranav's approval before merging. Thanks a lot for the quick review. I've incorporated your suggestions, let me know if you want any further changes to the test or other parts. https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,44 @@
+// RUN: fir-opt --omp-automap-to-target-data %s | FileCheck %s
+// Test OMP AutomapToTargetData pass.
+
+module {
+ fir.global
+ @_QMtestEarr{omp.declare_target = #omp.declaretarget} target
+ : !fir.box>>
+
+ func.func @automap() {
+%c0 = arith.constant 0 : index
+%c10 = arith.constant 10 : i32
+%addr = fir.address_of(@_QMtestEarr) :
!fir.ref>>>
+%decl:2 = hlfir.declare %addr {fortran_attrs = #fir.var_attrs, uniq_name = "_QMtestEarr"} :
(!fir.ref>>>) ->
(!fir.ref>>>,
!fir.ref>>>)
+%idx = fir.convert %c10 : (i32) -> index
+%cond = arith.cmpi sgt, %idx, %c0 : index
+%n = arith.select %cond, %idx, %c0 : index
+%mem = fir.allocmem !fir.array, %n {fir.must_be_heap = true}
+%shape = fir.shape %n : (index) -> !fir.shape<1>
+%box = fir.embox %mem(%shape) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %box to %decl#0 :
!fir.ref>>>
+%ld = fir.load %decl#0 : !fir.ref>>>
+%base = fir.box_addr %ld : (!fir.box>>) ->
!fir.heap>
+fir.freemem %base : !fir.heap>
+%undef = fir.zero_bits !fir.heap>
+%sh0 = fir.shape %c0 : (index) -> !fir.shape<1>
+%empty = fir.embox %undef(%sh0) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %empty to %decl#0 :
!fir.ref>>>
+return
+ }
+}
+
+// CHECK: fir.global @[[AUTOMAP:.*]] {{{.*}} automap = true
+// CHECK-LABEL: func.func @automap()
+// CHECK: %[[AUTOMAP_ADDR:.*]] = fir.address_of(@[[AUTOMAP]])
+// CHECK: %[[AUTOMAP_DECL:.*]]:2 = hlfir.declare %[[AUTOMAP_ADDR]]
+// CHECK: fir.allocmem
+// CHECK: fir.store {{.*}} to %[[AUTOMAP_DECL]]#0
+// CHECK: %[[ENTER_MAP:.*]] = omp.map.info
var_ptr(%[[AUTOMAP_DECL]]#0 {{.*}} map_clauses(to) capture(ByCopy)
+// CHECK: omp.target_enter_data map_entries(%[[ENTER_MAP]]
TIFitis wrote:
Done.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/TIFitis updated
https://github.com/llvm/llvm-project/pull/151989
>From e9b6766c5fbfd25b5acfc686cbdc41f8dd727b03 Mon Sep 17 00:00:00 2001
From: Akash Banerjee
Date: Thu, 31 Jul 2025 19:48:15 +0100
Subject: [PATCH 1/3] [MLIR][OpenMP] Add a new AutomapToTargetData conversion
pass in FIR
Add a new AutomapToTargetData pass. This gathers the declare target enter
variables which have the AUTOMAP modifier.
And adds omp.declare_target_enter/exit mapping directives for fir.alloca and
fir.free oeprations on the AUTOMAP enabled variables.
---
.../include/flang/Optimizer/OpenMP/Passes.td | 11 ++
.../Optimizer/OpenMP/AutomapToTargetData.cpp | 171 ++
flang/lib/Optimizer/OpenMP/CMakeLists.txt | 1 +
flang/lib/Optimizer/Passes/Pipelines.cpp | 12 +-
.../Transforms/omp-automap-to-target-data.fir | 40
.../fortran/declare-target-automap.f90| 36
6 files changed, 265 insertions(+), 6 deletions(-)
create mode 100644 flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
create mode 100644 flang/test/Transforms/omp-automap-to-target-data.fir
create mode 100644 offload/test/offloading/fortran/declare-target-automap.f90
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td
b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 704faf0ccd856..0bff58f0f6394 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -112,4 +112,15 @@ def GenericLoopConversionPass
];
}
+def AutomapToTargetDataPass
+: Pass<"omp-automap-to-target-data", "::mlir::ModuleOp"> {
+ let summary = "Insert OpenMP target data operations for AUTOMAP variables";
+ let description = [{
+Inserts `omp.target_enter_data` and `omp.target_exit_data` operations to
+map variables marked with the `AUTOMAP` modifier when their allocation
+or deallocation is detected in the FIR.
+ }];
+ let dependentDialects = ["mlir::omp::OpenMPDialect"];
+}
+
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES
diff --git a/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
new file mode 100644
index 0..c4937f1e90ee3
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,44 @@
+// RUN: fir-opt --omp-automap-to-target-data %s | FileCheck %s
+// Test OMP AutomapToTargetData pass.
+
+module {
+ fir.global
+ @_QMtestEarr{omp.declare_target = #omp.declaretarget} target
+ : !fir.box>>
+
+ func.func @automap() {
+%c0 = arith.constant 0 : index
+%c10 = arith.constant 10 : i32
+%addr = fir.address_of(@_QMtestEarr) :
!fir.ref>>>
+%decl:2 = hlfir.declare %addr {fortran_attrs = #fir.var_attrs, uniq_name = "_QMtestEarr"} :
(!fir.ref>>>) ->
(!fir.ref>>>,
!fir.ref>>>)
+%idx = fir.convert %c10 : (i32) -> index
+%cond = arith.cmpi sgt, %idx, %c0 : index
+%n = arith.select %cond, %idx, %c0 : index
+%mem = fir.allocmem !fir.array, %n {fir.must_be_heap = true}
+%shape = fir.shape %n : (index) -> !fir.shape<1>
+%box = fir.embox %mem(%shape) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %box to %decl#0 :
!fir.ref>>>
+%ld = fir.load %decl#0 : !fir.ref>>>
+%base = fir.box_addr %ld : (!fir.box>>) ->
!fir.heap>
+fir.freemem %base : !fir.heap>
+%undef = fir.zero_bits !fir.heap>
+%sh0 = fir.shape %c0 : (index) -> !fir.shape<1>
+%empty = fir.embox %undef(%sh0) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %empty to %decl#0 :
!fir.ref>>>
+return
+ }
+}
+
+// CHECK: fir.global @[[AUTOMAP:.*]] {{{.*}} automap = true
+// CHECK-LABEL: func.func @automap()
+// CHECK: %[[AUTOMAP_ADDR:.*]] = fir.address_of(@[[AUTOMAP]])
+// CHECK: %[[AUTOMAP_DECL:.*]]:2 = hlfir.declare %[[AUTOMAP_ADDR]]
+// CHECK: fir.allocmem
+// CHECK: fir.store {{.*}} to %[[AUTOMAP_DECL]]#0
+// CHECK: %[[ENTER_MAP:.*]] = omp.map.info
var_ptr(%[[AUTOMAP_DECL]]#0 {{.*}} map_clauses(to) capture(ByCopy)
+// CHECK: omp.target_enter_data map_entries(%[[ENTER_MAP]]
skatrak wrote:
Nit: Is it possible to make these `CHECK-NEXT`, so that we are sure to not
introduce any uses of the global before it has been mapped? Same comment for
the `omp.target_exit_data` and `fir.freemem` below.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,44 @@
+// RUN: fir-opt --omp-automap-to-target-data %s | FileCheck %s
+// Test OMP AutomapToTargetData pass.
+
+module {
+ fir.global
+ @_QMtestEarr{omp.declare_target = #omp.declaretarget} target
+ : !fir.box>>
+
+ func.func @automap() {
+%c0 = arith.constant 0 : index
+%c10 = arith.constant 10 : i32
+%addr = fir.address_of(@_QMtestEarr) :
!fir.ref>>>
+%decl:2 = hlfir.declare %addr {fortran_attrs = #fir.var_attrs, uniq_name = "_QMtestEarr"} :
(!fir.ref>>>) ->
(!fir.ref>>>,
!fir.ref>>>)
+%idx = fir.convert %c10 : (i32) -> index
+%cond = arith.cmpi sgt, %idx, %c0 : index
+%n = arith.select %cond, %idx, %c0 : index
+%mem = fir.allocmem !fir.array, %n {fir.must_be_heap = true}
+%shape = fir.shape %n : (index) -> !fir.shape<1>
+%box = fir.embox %mem(%shape) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %box to %decl#0 :
!fir.ref>>>
+%ld = fir.load %decl#0 : !fir.ref>>>
+%base = fir.box_addr %ld : (!fir.box>>) ->
!fir.heap>
+fir.freemem %base : !fir.heap>
+%undef = fir.zero_bits !fir.heap>
+%sh0 = fir.shape %c0 : (index) -> !fir.shape<1>
+%empty = fir.embox %undef(%sh0) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %empty to %decl#0 :
!fir.ref>>>
+return
+ }
+}
+
+// CHECK: fir.global @[[AUTOMAP:.*]] {{{.*}} automap = true
+// CHECK-LABEL: func.func @automap()
+// CHECK: %[[AUTOMAP_ADDR:.*]] = fir.address_of(@[[AUTOMAP]])
+// CHECK: %[[AUTOMAP_DECL:.*]]:2 = hlfir.declare %[[AUTOMAP_ADDR]]
+// CHECK: fir.allocmem
+// CHECK: fir.store {{.*}} to %[[AUTOMAP_DECL]]#0
skatrak wrote:
Nit: I'd suggest capturing the value returned from `fir.allocmem` and checking
it's the same one passed to `fir.store` and `fir.freemem`.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -72,6 +77,36 @@ struct EntryBlockArgs {
/// \param [in] region - Empty region in which to create the entry block.
mlir::Block *genEntryBlock(
mlir::OpBuilder &builder, const EntryBlockArgs &args, mlir::Region
®ion);
+
+// Returns true if the variable has a dynamic size and therefore requires
+// bounds operations to describe its extents.
+static bool needsBoundsOps(mlir::Value var) {
skatrak wrote:
I think that these new functions shouldn't be `static`, and that their
definition belongs in OpenMP-utils.cpp.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,130 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "flang/Support/OpenMP-utils.h"
+
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/Pass/Pass.h"
+
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+using namespace Fortran::common::openmp;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::DenseSet &allocmems,
+ llvm::DenseSet &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+allocmems.insert(storeOp);
+
+ if (auto loadOp = dyn_cast(refUser))
+for (Operation *loadUser : loadOp.getResult().getUsers())
+ if (auto boxAddrOp = dyn_cast(loadUser))
+for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())
+ if (auto freememOp = dyn_cast(boxAddrUser))
+freemems.insert(loadOp);
+}
+ }
+
+ void runOnOperation() override {
+ModuleOp module = getOperation()->getParentOfType();
+if (!module)
+ module = dyn_cast(getOperation());
+if (!module)
+ return;
+
+// Build FIR builder for helper utilities.
+fir::KindMapping kindMap = fir::getKindMapping(module);
+fir::FirOpBuilder builder{module, std::move(kindMap)};
+
+// Collect global variables with AUTOMAP flag.
+llvm::DenseSet automapGlobals;
+module.walk([&](fir::GlobalOp globalOp) {
+ if (auto iface =
+ dyn_cast(globalOp.getOperation()))
+if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap() &&
+iface.getDeclareTargetDeviceType() !=
+omp::DeclareTargetDeviceType::host)
+ automapGlobals.insert(globalOp);
+});
+
+auto addMapInfo = [&](auto globalOp, auto memOp) {
+ builder.setInsertionPointAfter(memOp);
+ SmallVector bounds;
+ if (needsBoundsOps(memOp.getMemref()))
+genBoundsOps(builder, memOp.getMemref(), bounds);
+
+ omp::TargetEnterExitUpdateDataOperands clauses;
+ mlir::omp::MapInfoOp mapInfo = mlir::omp::MapInfoOp::create(
+ builder, memOp.getLoc(), memOp.getMemref().getType(),
+ memOp.getMemref(),
+ TypeAttr::get(fir::unwrapRefType(memOp.getMemref().getType())),
+ builder.getIntegerAttr(
+ builder.getIntegerType(64, false),
+ static_cast(
+ isa(memOp)
+ ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO
+ : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE)),
+ builder.getAttr(
+ omp::VariableCaptureKind::ByCopy),
+ /*var_ptr_ptr=*/mlir::Value{},
+ /*members=*/SmallVector{},
+ /*members_index=*/ArrayAttr{}, bounds,
+ /*mapperId=*/mlir::FlatSymbolRefAttr(), globalOp.getSymNameAttr(),
+ builder.getBoolAttr(false));
+ clauses.mapVars.push_back(mapInfo);
+ isa(memOp)
+ ? builder.create(memOp.getLoc(), clauses)
+ : builder.create(memOp.getLoc(), clauses);
+};
+
+for (fir::GlobalOp globalOp : automapGlobals) {
+ if (auto uses = globalOp.getSymbolUses(module.getOperation())) {
+llvm::DenseSet allocmemStores;
+llvm::DenseSet freememloads;
skatrak wrote:
```suggestion
llvm::DenseSet freememLoads;
```
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bra
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,44 @@
+// RUN: fir-opt --omp-automap-to-target-data %s | FileCheck %s
+// Test OMP AutomapToTargetData pass.
+
+module {
+ fir.global
+ @_QMtestEarr{omp.declare_target = #omp.declaretarget} target
+ : !fir.box>>
+
+ func.func @automap() {
skatrak wrote:
```suggestion
func.func @automap() {
```
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -72,6 +77,36 @@ struct EntryBlockArgs {
/// \param [in] region - Empty region in which to create the entry block.
mlir::Block *genEntryBlock(
mlir::OpBuilder &builder, const EntryBlockArgs &args, mlir::Region
®ion);
+
+// Returns true if the variable has a dynamic size and therefore requires
+// bounds operations to describe its extents.
+static bool needsBoundsOps(mlir::Value var) {
+ assert(mlir::isa(var.getType()) &&
+ "only pointer like types expected");
+ mlir::Type t = fir::unwrapRefType(var.getType());
+ if (mlir::Type inner = fir::dyn_cast_ptrOrBoxEleTy(t)) {
+return fir::hasDynamicSize(inner);
+ }
skatrak wrote:
```suggestion
if (mlir::Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
return fir::hasDynamicSize(inner);
```
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/skatrak approved this pull request. Thank you again Akash, LGTM minus some NFC suggestions. Please wait for @bhandarkar-pranav's approval before merging. https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/skatrak edited https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
TIFitis wrote:
I've moved both as static functions to
_flang/include/flang/Support/OpenMP-utils.h_. Let me know if that's alright.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,40 @@
+// RUN: fir-opt --omp-automap-to-target-data %s | FileCheck %s
+// Test OMP AutomapToTargetData pass.
+
+module {
+ fir.global
+ @_QMtestEarr{omp.declare_target = #omp.declaretarget} target
+ : !fir.box>>
+
+ func.func @automap() {
+%c0 = arith.constant 0 : index
+%c10 = arith.constant 10 : i32
+%addr = fir.address_of(@_QMtestEarr) :
!fir.ref>>>
+%decl:2 = hlfir.declare %addr {fortran_attrs = #fir.var_attrs, uniq_name = "_QMtestEarr"} :
(!fir.ref>>>) ->
(!fir.ref>>>,
!fir.ref>>>)
+%idx = fir.convert %c10 : (i32) -> index
+%cond = arith.cmpi sgt, %idx, %c0 : index
+%n = arith.select %cond, %idx, %c0 : index
+%mem = fir.allocmem !fir.array, %n {fir.must_be_heap = true}
+%shape = fir.shape %n : (index) -> !fir.shape<1>
+%box = fir.embox %mem(%shape) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %box to %decl#0 :
!fir.ref>>>
+%ld = fir.load %decl#0 : !fir.ref>>>
+%base = fir.box_addr %ld : (!fir.box>>) ->
!fir.heap>
+fir.freemem %base : !fir.heap>
+%undef = fir.zero_bits !fir.heap>
+%sh0 = fir.shape %c0 : (index) -> !fir.shape<1>
+%empty = fir.embox %undef(%sh0) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %empty to %decl#0 :
!fir.ref>>>
+return
+ }
+}
+
+// CHECK-LABEL: func.func @automap()
+// CHECK: fir.allocmem
+// CHECK: fir.store
+// CHECK: omp.map.info {{.*}}map_clauses(to)
+// CHECK: omp.target_enter_data
+// CHECK: omp.map.info {{.*}}map_clauses(delete)
+// CHECK: omp.target_exit_data
+// CHECK: fir.freemem
TIFitis wrote:
I've updated the test to make sure it's mapping the automap global.
The test checks that the `target_enter_data` succeeds the `allocmem` operation
and the `target_exit_data` precedes the `freemem` operation which should imply
any other use of the global in between would remain intact.
Let me know if you're happy with the updated test.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/TIFitis updated
https://github.com/llvm/llvm-project/pull/151989
>From e9b6766c5fbfd25b5acfc686cbdc41f8dd727b03 Mon Sep 17 00:00:00 2001
From: Akash Banerjee
Date: Thu, 31 Jul 2025 19:48:15 +0100
Subject: [PATCH 1/2] [MLIR][OpenMP] Add a new AutomapToTargetData conversion
pass in FIR
Add a new AutomapToTargetData pass. This gathers the declare target enter
variables which have the AUTOMAP modifier.
And adds omp.declare_target_enter/exit mapping directives for fir.alloca and
fir.free oeprations on the AUTOMAP enabled variables.
---
.../include/flang/Optimizer/OpenMP/Passes.td | 11 ++
.../Optimizer/OpenMP/AutomapToTargetData.cpp | 171 ++
flang/lib/Optimizer/OpenMP/CMakeLists.txt | 1 +
flang/lib/Optimizer/Passes/Pipelines.cpp | 12 +-
.../Transforms/omp-automap-to-target-data.fir | 40
.../fortran/declare-target-automap.f90| 36
6 files changed, 265 insertions(+), 6 deletions(-)
create mode 100644 flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
create mode 100644 flang/test/Transforms/omp-automap-to-target-data.fir
create mode 100644 offload/test/offloading/fortran/declare-target-automap.f90
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td
b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 704faf0ccd856..0bff58f0f6394 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -112,4 +112,15 @@ def GenericLoopConversionPass
];
}
+def AutomapToTargetDataPass
+: Pass<"omp-automap-to-target-data", "::mlir::ModuleOp"> {
+ let summary = "Insert OpenMP target data operations for AUTOMAP variables";
+ let description = [{
+Inserts `omp.target_enter_data` and `omp.target_exit_data` operations to
+map variables marked with the `AUTOMAP` modifier when their allocation
+or deallocation is detected in the FIR.
+ }];
+ let dependentDialects = ["mlir::omp::OpenMPDialect"];
+}
+
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES
diff --git a/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
new file mode 100644
index 0..c4937f1e90ee3
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/TIFitis updated
https://github.com/llvm/llvm-project/pull/151989
>From e9b6766c5fbfd25b5acfc686cbdc41f8dd727b03 Mon Sep 17 00:00:00 2001
From: Akash Banerjee
Date: Thu, 31 Jul 2025 19:48:15 +0100
Subject: [PATCH 1/2] [MLIR][OpenMP] Add a new AutomapToTargetData conversion
pass in FIR
Add a new AutomapToTargetData pass. This gathers the declare target enter
variables which have the AUTOMAP modifier.
And adds omp.declare_target_enter/exit mapping directives for fir.alloca and
fir.free oeprations on the AUTOMAP enabled variables.
---
.../include/flang/Optimizer/OpenMP/Passes.td | 11 ++
.../Optimizer/OpenMP/AutomapToTargetData.cpp | 171 ++
flang/lib/Optimizer/OpenMP/CMakeLists.txt | 1 +
flang/lib/Optimizer/Passes/Pipelines.cpp | 12 +-
.../Transforms/omp-automap-to-target-data.fir | 40
.../fortran/declare-target-automap.f90| 36
6 files changed, 265 insertions(+), 6 deletions(-)
create mode 100644 flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
create mode 100644 flang/test/Transforms/omp-automap-to-target-data.fir
create mode 100644 offload/test/offloading/fortran/declare-target-automap.f90
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td
b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 704faf0ccd856..0bff58f0f6394 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -112,4 +112,15 @@ def GenericLoopConversionPass
];
}
+def AutomapToTargetDataPass
+: Pass<"omp-automap-to-target-data", "::mlir::ModuleOp"> {
+ let summary = "Insert OpenMP target data operations for AUTOMAP variables";
+ let description = [{
+Inserts `omp.target_enter_data` and `omp.target_exit_data` operations to
+map variables marked with the `AUTOMAP` modifier when their allocation
+or deallocation is detected in the FIR.
+ }];
+ let dependentDialects = ["mlir::omp::OpenMPDialect"];
+}
+
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES
diff --git a/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
new file mode 100644
index 0..c4937f1e90ee3
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/skatrak edited https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -316,13 +316,13 @@ void createOpenMPFIRPassPipeline(mlir::PassManager &pm, pm.addPass(flangomp::createDoConcurrentConversionPass( opts.doConcurrentMappingKind == DoConcurrentMappingKind::DCMK_Device)); - // The MapsForPrivatizedSymbols pass needs to run before - // MapInfoFinalizationPass because the former creates new - // MapInfoOp instances, typically for descriptors. - // MapInfoFinalizationPass adds MapInfoOp instances for the descriptors - // underlying data which is necessary to access the data on the offload - // target device. + // The MapsForPrivatizedSymbols and AutomapToTargetDataPass pass needs to run skatrak wrote: ```suggestion // The MapsForPrivatizedSymbols and AutomapToTargetDataPass pass need to run ``` https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+allocmems.push_back(storeOp);
+
+ if (auto loadOp = dyn_cast(refUser))
+for (Operation *loadUser : loadOp.getResult().getUsers())
+ if (auto boxAddrOp = dyn_cast(loadUser))
+for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())
+ if (auto freememOp = dyn_cast(boxAddrUser))
+freemems.push_back(loadOp);
+}
+ }
+
+ void runOnOperation() override {
+ModuleOp module = getOperation()->getParentOfType();
+if (!module)
+ module = dyn_cast(getOperation());
+if (!module)
+ return;
+
+// Build FIR builder for helper utilities.
+fir::KindMapping kindMap = fir::getKindMapping(module);
+fir::FirOpBuilder builder{module, std::move(kindMap)};
+
+// Collect global variables with AUTOMAP flag.
+llvm::DenseSet automapGlobals;
+module.walk([&](fir::GlobalOp globalOp) {
+ if (auto iface =
+ dyn_cast(globalOp.getOperation()))
+if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap())
+ automapGlobals.insert(globalOp);
+});
+
+for (fir::GlobalOp globalOp : automapGlobals)
+ if (auto uses = globalOp.getSymbolUses(module.getOperation()))
+for (auto &x : *uses)
skatrak wrote:
Nit: Use braces here:
[link](https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements).
> Similarly, braces should be used when a single-statement body is complex
> enough that it becomes difficult to see where the block containing the
> following statement began.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -316,13 +316,13 @@ void createOpenMPFIRPassPipeline(mlir::PassManager &pm, pm.addPass(flangomp::createDoConcurrentConversionPass( opts.doConcurrentMappingKind == DoConcurrentMappingKind::DCMK_Device)); - // The MapsForPrivatizedSymbols pass needs to run before - // MapInfoFinalizationPass because the former creates new - // MapInfoOp instances, typically for descriptors. - // MapInfoFinalizationPass adds MapInfoOp instances for the descriptors - // underlying data which is necessary to access the data on the offload - // target device. + // The MapsForPrivatizedSymbols and AutomapToTargetDataPass pass needs to run + // before MapInfoFinalizationPass because the former creates new MapInfoOp skatrak wrote: ```suggestion // before MapInfoFinalizationPass because they create new MapInfoOp ``` https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,40 @@
+// RUN: fir-opt --omp-automap-to-target-data %s | FileCheck %s
+// Test OMP AutomapToTargetData pass.
+
+module {
+ fir.global
+ @_QMtestEarr{omp.declare_target = #omp.declaretarget} target
+ : !fir.box>>
+
+ func.func @automap() {
+%c0 = arith.constant 0 : index
+%c10 = arith.constant 10 : i32
+%addr = fir.address_of(@_QMtestEarr) :
!fir.ref>>>
+%decl:2 = hlfir.declare %addr {fortran_attrs = #fir.var_attrs, uniq_name = "_QMtestEarr"} :
(!fir.ref>>>) ->
(!fir.ref>>>,
!fir.ref>>>)
+%idx = fir.convert %c10 : (i32) -> index
+%cond = arith.cmpi sgt, %idx, %c0 : index
+%n = arith.select %cond, %idx, %c0 : index
+%mem = fir.allocmem !fir.array, %n {fir.must_be_heap = true}
+%shape = fir.shape %n : (index) -> !fir.shape<1>
+%box = fir.embox %mem(%shape) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %box to %decl#0 :
!fir.ref>>>
+%ld = fir.load %decl#0 : !fir.ref>>>
+%base = fir.box_addr %ld : (!fir.box>>) ->
!fir.heap>
+fir.freemem %base : !fir.heap>
+%undef = fir.zero_bits !fir.heap>
+%sh0 = fir.shape %c0 : (index) -> !fir.shape<1>
+%empty = fir.embox %undef(%sh0) : (!fir.heap>,
!fir.shape<1>) -> !fir.box>>
+fir.store %empty to %decl#0 :
!fir.ref>>>
+return
+ }
+}
+
+// CHECK-LABEL: func.func @automap()
+// CHECK: fir.allocmem
+// CHECK: fir.store
+// CHECK: omp.map.info {{.*}}map_clauses(to)
+// CHECK: omp.target_enter_data
+// CHECK: omp.map.info {{.*}}map_clauses(delete)
+// CHECK: omp.target_exit_data
+// CHECK: fir.freemem
skatrak wrote:
Nit: I think we should also test how values defined by these ops are passed to
the other ops, not just checking that the expected ops are there. Also it would
be good to check that uses of the global variable are placed between the
`omp.target_enter_data` and `omp.target_exit_data`.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
skatrak wrote:
I agree. Maybe flang/include/flang/Support/OpenMP-utils.h and
flang/lib/Support/OpenMP-utils.cpp could be where this logic can be shared
between lowering and this pass.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+allocmems.push_back(storeOp);
+
+ if (auto loadOp = dyn_cast(refUser))
+for (Operation *loadUser : loadOp.getResult().getUsers())
+ if (auto boxAddrOp = dyn_cast(loadUser))
+for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())
+ if (auto freememOp = dyn_cast(boxAddrUser))
+freemems.push_back(loadOp);
+}
+ }
+
+ void runOnOperation() override {
+ModuleOp module = getOperation()->getParentOfType();
+if (!module)
+ module = dyn_cast(getOperation());
+if (!module)
+ return;
+
+// Build FIR builder for helper utilities.
+fir::KindMapping kindMap = fir::getKindMapping(module);
+fir::FirOpBuilder builder{module, std::move(kindMap)};
+
+// Collect global variables with AUTOMAP flag.
+llvm::DenseSet automapGlobals;
+module.walk([&](fir::GlobalOp globalOp) {
+ if (auto iface =
+ dyn_cast(globalOp.getOperation()))
+if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap())
skatrak wrote:
I think this is missing a check for the declare target type:
`iface.getDeclareTargetDeviceType()`. Otherwise, this results in mapping
`declare target device_type(host)` globals.
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+allocmems.push_back(storeOp);
+
+ if (auto loadOp = dyn_cast(refUser))
+for (Operation *loadUser : loadOp.getResult().getUsers())
+ if (auto boxAddrOp = dyn_cast(loadUser))
+for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())
+ if (auto freememOp = dyn_cast(boxAddrUser))
+freemems.push_back(loadOp);
+}
+ }
+
+ void runOnOperation() override {
+ModuleOp module = getOperation()->getParentOfType();
+if (!module)
+ module = dyn_cast(getOperation());
+if (!module)
+ return;
+
+// Build FIR builder for helper utilities.
+fir::KindMapping kindMap = fir::getKindMapping(module);
+fir::FirOpBuilder builder{module, std::move(kindMap)};
+
+// Collect global variables with AUTOMAP flag.
+llvm::DenseSet automapGlobals;
+module.walk([&](fir::GlobalOp globalOp) {
+ if (auto iface =
+ dyn_cast(globalOp.getOperation()))
+if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap())
+ automapGlobals.insert(globalOp);
+});
+
+for (fir::GlobalOp globalOp : automapGlobals)
+ if (auto uses = globalOp.getSymbolUses(module.getOperation()))
+for (auto &x : *uses)
+ if (auto addrOp = dyn_cast(x.getUser())) {
+llvm::SmallVector allocstores;
+llvm::SmallVector freememloads;
skatrak wrote:
```suggestion
llvm::SmallVector allocmemStores;
llvm::SmallVector freememLoads;
```
https://github.com/llvm/llvm-project/pull/151989
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+allocmems.push_back(storeOp);
+
+ if (auto loadOp = dyn_cast(refUser))
+for (Operation *loadUser : loadOp.getResult().getUsers())
+ if (auto boxAddrOp = dyn_cast(loadUser))
+for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())
+ if (auto freememOp = dyn_cast(boxAddrUser))
+freemems.push_back(loadOp);
+}
+ }
+
+ void runOnOperation() override {
+ModuleOp module = getOperation()->getParentOfType();
+if (!module)
+ module = dyn_cast(getOperation());
+if (!module)
+ return;
+
+// Build FIR builder for helper utilities.
+fir::KindMapping kindMap = fir::getKindMapping(module);
+fir::FirOpBuilder builder{module, std::move(kindMap)};
+
+// Collect global variables with AUTOMAP flag.
+llvm::DenseSet automapGlobals;
+module.walk([&](fir::GlobalOp globalOp) {
+ if (auto iface =
+ dyn_cast(globalOp.getOperation()))
+if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap())
+ automapGlobals.insert(globalOp);
+});
+
+for (fir::GlobalOp globalOp : automapGlobals)
+ if (auto uses = globalOp.getSymbolUses(module.getOperation()))
+for (auto &x : *uses)
+ if (auto addrOp = dyn_cast(x.getUser())) {
+llvm::SmallVector allocstores;
+llvm::SmallVector freememloads;
+findRelatedAllocmemFreemem(addrOp, allocstores, freememloads);
skatrak wrote:
Would it be possible to first gather all stores and loads for all uses and then
process them? That way we wouldn't have to allocate/deallocate these lists for
each use. Something like:
```c++
for (fir::GlobalOp globalOp : automapGlobals) {
if (auto uses = globalOp.getSymbolUses(module.getOperation())) {
llvm::SmallVector allocmemStores;
llvm::SmallVector freememLoads;
for (auto &x : *uses)
if (auto addrOp = dyn_cast(x.getUser()))
fi
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+allocmems.push_back(storeOp);
+
+ if (auto loadOp = dyn_cast(refUser))
+for (Operation *loadUser : loadOp.getResult().getUsers())
+ if (auto boxAddrOp = dyn_cast(loadUser))
+for (Operation *boxAddrUser : boxAddrOp.getResult().getUsers())
+ if (auto freememOp = dyn_cast(boxAddrUser))
+freemems.push_back(loadOp);
+}
+ }
+
+ void runOnOperation() override {
+ModuleOp module = getOperation()->getParentOfType();
+if (!module)
+ module = dyn_cast(getOperation());
+if (!module)
+ return;
+
+// Build FIR builder for helper utilities.
+fir::KindMapping kindMap = fir::getKindMapping(module);
+fir::FirOpBuilder builder{module, std::move(kindMap)};
+
+// Collect global variables with AUTOMAP flag.
+llvm::DenseSet automapGlobals;
+module.walk([&](fir::GlobalOp globalOp) {
+ if (auto iface =
+ dyn_cast(globalOp.getOperation()))
+if (iface.isDeclareTarget() && iface.getDeclareTargetAutomap())
+ automapGlobals.insert(globalOp);
+});
+
+for (fir::GlobalOp globalOp : automapGlobals)
+ if (auto uses = globalOp.getSymbolUses(module.getOperation()))
+for (auto &x : *uses)
+ if (auto addrOp = dyn_cast(x.getUser())) {
+llvm::SmallVector allocstores;
+llvm::SmallVector freememloads;
+findRelatedAllocmemFreemem(addrOp, allocstores, freememloads);
+
+for (auto storeOp : allocstores) {
skatrak wrote:
There's quite some code duplication between these two loops. I think it's worth
refactoring into a lambda or template function.
```c++
auto processTargetDataClauses = [&](auto op,
llvm::omp::OpenMPOffloadMappingFlags flags) ->
omp::TargetEnterExitUpdateDataOperands {
...
};
for (auto storeOp : allocmemStores) {
auto clauses = processLoadStore(storeOp);
builder.create(storeOp.getLoc(), clauses);
}
for (au
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/skatrak commented: Thank you Akash, a couple of minor comments from me. https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/TIFitis edited https://github.com/llvm/llvm-project/pull/151989 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
llvmbot wrote:
@llvm/pr-subscribers-flang-fir-hlfir
Author: Akash Banerjee (TIFitis)
Changes
Add a new AutomapToTargetData pass. This gathers the declare target enter
variables which have the AUTOMAP modifier. And adds
omp.declare_target_enter/exit mapping directives for fir.alloca and fir.free
oeprations on the AUTOMAP enabled variables.
Automap Ref: OpenMP 6.0 section 7.9.7.
---
Full diff: https://github.com/llvm/llvm-project/pull/151989.diff
6 Files Affected:
- (modified) flang/include/flang/Optimizer/OpenMP/Passes.td (+11)
- (added) flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp (+171)
- (modified) flang/lib/Optimizer/OpenMP/CMakeLists.txt (+1)
- (modified) flang/lib/Optimizer/Passes/Pipelines.cpp (+6-6)
- (added) flang/test/Transforms/omp-automap-to-target-data.fir (+40)
- (added) offload/test/offloading/fortran/declare-target-automap.f90 (+36)
``diff
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td
b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 704faf0ccd856..0bff58f0f6394 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -112,4 +112,15 @@ def GenericLoopConversionPass
];
}
+def AutomapToTargetDataPass
+: Pass<"omp-automap-to-target-data", "::mlir::ModuleOp"> {
+ let summary = "Insert OpenMP target data operations for AUTOMAP variables";
+ let description = [{
+Inserts `omp.target_enter_data` and `omp.target_exit_data` operations to
+map variables marked with the `AUTOMAP` modifier when their allocation
+or deallocation is detected in the FIR.
+ }];
+ let dependentDialects = ["mlir::omp::OpenMPDialect"];
+}
+
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES
diff --git a/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
new file mode 100644
index 0..c4937f1e90ee3
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::AddrOfOp addressOfOp,
+ llvm::SmallVector &allocmems,
+ llvm::SmallVector &freemems) {
+assert(addressOfOp->hasOneUse() && "op must have single use");
+
+auto declaredRef =
+cast(*addressOfOp->getUsers().begin())->getResult(0);
+
+for (Operation *refUser : declaredRef.getUsers()) {
+ if (auto storeOp = dyn_cast(refUser))
+if (auto emboxOp = storeOp.getValue().getDefiningOp())
+ if (auto allocmemOp =
+ emboxOp.getOperand(0).getDefiningOp())
+
[llvm-branch-commits] [flang] [llvm] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass in FIR (PR #151989)
https://github.com/TIFitis created
https://github.com/llvm/llvm-project/pull/151989
Add a new AutomapToTargetData pass. This gathers the declare target enter
variables which have the AUTOMAP modifier. And adds
omp.declare_target_enter/exit mapping directives for fir.alloca and fir.free
oeprations on the AUTOMAP enabled variables.
Automap Ref: OpenMP 6.0 section 7.9.7.
>From 9f050593054e3c4d01cd17a5f6c918386ab3896e Mon Sep 17 00:00:00 2001
From: Akash Banerjee
Date: Thu, 31 Jul 2025 19:48:15 +0100
Subject: [PATCH] [MLIR][OpenMP] Add a new AutomapToTargetData conversion pass
in FIR
Add a new AutomapToTargetData pass. This gathers the declare target enter
variables which have the AUTOMAP modifier.
And adds omp.declare_target_enter/exit mapping directives for fir.alloca and
fir.free oeprations on the AUTOMAP enabled variables.
---
.../include/flang/Optimizer/OpenMP/Passes.td | 11 ++
.../Optimizer/OpenMP/AutomapToTargetData.cpp | 171 ++
flang/lib/Optimizer/OpenMP/CMakeLists.txt | 1 +
flang/lib/Optimizer/Passes/Pipelines.cpp | 12 +-
.../Transforms/omp-automap-to-target-data.fir | 40
.../fortran/declare-target-automap.f90| 36
6 files changed, 265 insertions(+), 6 deletions(-)
create mode 100644 flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
create mode 100644 flang/test/Transforms/omp-automap-to-target-data.fir
create mode 100644 offload/test/offloading/fortran/declare-target-automap.f90
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td
b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 704faf0ccd856..0bff58f0f6394 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -112,4 +112,15 @@ def GenericLoopConversionPass
];
}
+def AutomapToTargetDataPass
+: Pass<"omp-automap-to-target-data", "::mlir::ModuleOp"> {
+ let summary = "Insert OpenMP target data operations for AUTOMAP variables";
+ let description = [{
+Inserts `omp.target_enter_data` and `omp.target_exit_data` operations to
+map variables marked with the `AUTOMAP` modifier when their allocation
+or deallocation is detected in the FIR.
+ }];
+ let dependentDialects = ["mlir::omp::OpenMPDialect"];
+}
+
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES
diff --git a/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
new file mode 100644
index 0..c4937f1e90ee3
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/AutomapToTargetData.cpp
@@ -0,0 +1,171 @@
+//===- AutomapToTargetData.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
+//
+//===--===//
+
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include
+#include
+
+namespace flangomp {
+#define GEN_PASS_DEF_AUTOMAPTOTARGETDATAPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+using namespace mlir;
+
+namespace {
+class AutomapToTargetDataPass
+: public flangomp::impl::AutomapToTargetDataPassBase<
+ AutomapToTargetDataPass> {
+ // Returns true if the variable has a dynamic size and therefore requires
+ // bounds operations to describe its extents.
+ bool needsBoundsOps(Value var) {
+assert(isa(var.getType()) &&
+ "only pointer like types expected");
+Type t = fir::unwrapRefType(var.getType());
+if (Type inner = fir::dyn_cast_ptrOrBoxEleTy(t))
+ return fir::hasDynamicSize(inner);
+return fir::hasDynamicSize(t);
+ }
+
+ // Generate MapBoundsOp operations for the variable if required.
+ void genBoundsOps(fir::FirOpBuilder &builder, Value var,
+SmallVectorImpl &boundsOps) {
+Location loc = var.getLoc();
+fir::factory::AddrAndBoundsInfo info =
+fir::factory::getDataOperandBaseAddr(builder, var,
+ /*isOptional=*/false, loc);
+fir::ExtendedValue exv =
+hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr},
+/*contiguousHint=*/true)
+.first;
+SmallVector tmp =
+fir::factory::genImplicitBoundsOps(
+builder, info, exv, /*dataExvIsAssumedSize=*/false, loc);
+llvm::append_range(boundsOps, tmp);
+ }
+
+ void findRelatedAllocmemFreemem(fir::Add
