[Mlir-commits] [flang] [mlir] [RFC][mlir] Introduced unit SideEffects::Resource. (PR #178291)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Jan 27 12:54:37 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-core
Author: Slava Zakharin (vzakhari)
<details>
<summary>Changes</summary>
Related to https://discourse.llvm.org/t/does-memalloc-effect-allow-reordering/89136
Some of the FIR and OpenACC dialect operations imply certain ordering constraints
that cannot be practically implemented using def-use chain, so the dialects
use Allocate/Read/Write memory effects on dedicated resources to guarantee
the ordering of the operations when any MLIR transformations are applied.
Such a representation currently prevents several MLIR optimizations,
and this PR is trying to address this.
For example, in OpenACC dialect [acc.set](https://github.com/llvm/llvm-project/blob/e7780836e1d37e34bce003e0d9308fceb34506a2/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td#L3473) is the operation that writes
`CurrentDeviceIdResource` resource implemented by OpenACC runtime library.
Other OpenACC operations, like [acc.parallel](https://github.com/llvm/llvm-project/blob/e7780836e1d37e34bce003e0d9308fceb34506a2/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td#L1676) may read from this resource,
so the ordering of these operations must be preserved during any MLIR transformations.
At the same time, it should be legal to, for example, apply CSE to loads around `acc.set`,
which is not currently done because `acc.set` is considered to write to an unknown location
and may clobber the loads' location. As long as the `CurrentDeviceIdResource` cannot be
directly accessed in MLIR via any location, a write to this resource must be not considered
as clobberring for any load from any location.
I propose introducing special kind of resources called `unit` that cannot be accessed
via any location (`mlir::Value`) and must only be affected as a whole at the operation
level. This restriction allows disambiguating other effects from the effects on the
`unit` resources allowing optimizations.
Another example of such a resource is a `DebuggingResource` in [HL]FIR dialect:
```
%scope1 = fir.dummy_scope
%decl1 = fir.declare ... dummy_scope %scope1
%decl2 = fir.declare ... dummy_scope %scope1
%scope2 = fir.dummy_scope
%decl3 = fir.declare ... dummy_scope %scope2
```
The `fir.dummy_scope` operations must preserve their order. The `fir.declare`
operations must preserve their order relative to `fir.dummy_scope` (e.g.
`%scope2` cannot be moved before `%decl1/2`), but `%decl1` and `%decl2`
may be reordered relative to each other if needed. None of the operations
can be removed (because they are used to generate debugging information
and convey Fortran aliasing rules to later MLIR stages).
In order to represent such ordering constraints, `fir.dummy_scope`
reads and writes `DebuggingResource`, and `fir.declare` only reads it.
This patch does not solve one remaining issue that `fir.declare`
can be removed as "trivially dead" if its result is unused (note that
we have to keep such operations for debugging information as well).
I keep using Allocate effect for `fir.declare` to make it non-trivially dead,
but I think we need a better solution.
This patch also demonstrates how the unit effects can be handled by MLIR
optimizations by supporting them in CSE, AffineAnalysis and AliasAnalysis.
---
Patch is 41.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178291.diff
15 Files Affected:
- (modified) flang/include/flang/Optimizer/Dialect/FIROps.h (+14)
- (modified) flang/include/flang/Optimizer/Dialect/FIROps.td (+16-5)
- (modified) flang/include/flang/Optimizer/HLFIR/HLFIROps.td (+10-1)
- (modified) flang/include/flang/Optimizer/Support/InitFIR.h (+1)
- (modified) flang/lib/Optimizer/Analysis/AliasAnalysis.cpp (+5)
- (added) flang/test/Transforms/affine-parallelize.fir (+14)
- (added) flang/test/Transforms/cse.fir (+23)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACC.h (+22)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td (+2-1)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+58-40)
- (modified) mlir/include/mlir/Interfaces/SideEffectInterfaces.h (+153-50)
- (modified) mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp (+7)
- (modified) mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp (+21-2)
- (modified) mlir/lib/Transforms/CSE.cpp (+41)
- (modified) mlir/test/lib/Dialect/Test/CMakeLists.txt (+1)
``````````diff
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h
index 4651f2bb8038e..f11abd96ffcc5 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.h
@@ -51,12 +51,26 @@ static constexpr llvm::StringRef getNormalizedLowerBoundAttrName() {
struct DebuggingResource
: public mlir::SideEffects::Resource::Base<DebuggingResource> {
mlir::StringRef getName() final { return "DebuggingResource"; }
+ /// DebuggingResource is a unit resource allowing to keep order
+ /// of operations that affect debug information generation.
+ bool isUnitResource() const final { return true; }
+ /// This is a synthetic resource that is parallel-safe,
+ /// i.e. a presence of an operation that reads/writes this resource
+ /// does not prevent parallelization.
+ mlir::SideEffects::Resource::UnitProperties getUnitProperties() const final {
+ return mlir::SideEffects::Resource::UnitProperties::ParallelSafe;
+ }
};
/// Model operations which read from/write to volatile memory
struct VolatileMemoryResource
: public mlir::SideEffects::Resource::Base<VolatileMemoryResource> {
mlir::StringRef getName() final { return "VolatileMemoryResource"; }
+ /// VolatileMemoryResource is a unit resource allowing to keep order
+ /// of volatile memory accesses relative to each other.
+ /// Note that it is not parallel-safe, i.e. it is not allowed
+ /// to parallelize code with volatile memory accesses.
+ bool isUnitResource() const final { return true; }
};
class CoordinateIndicesAdaptor;
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 30f5dcc37b0f3..ec2393fe37c28 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3160,7 +3160,8 @@ def fir_GlobalLenOp : fir_Op<"global_len", []> {
}
def fir_UseStmtOp
- : fir_Op<"use_stmt", [MemoryEffects<[MemWrite<DebuggingResource>]>]> {
+ : fir_Op<"use_stmt", [MemoryEffects<[MemRead<DebuggingResource>,
+ MemWrite<DebuggingResource>]>]> {
let summary = "Represents a Fortran USE statement";
let description = [{
This operation records a Fortran USE statement with its associated only/rename
@@ -3393,7 +3394,8 @@ def fir_IsPresentOp : fir_SimpleOp<"is_present", [NoMemoryEffect]> {
// is not used.
def fir_DeclareOp
: fir_Op<"declare", [AttrSizedOperandSegments,
- MemoryEffects<[MemAlloc<DebuggingResource>]>,
+ MemoryEffects<[MemAlloc<DebuggingResource>,
+ MemRead<DebuggingResource>]>,
DeclareOpInterfaceMethods<
fir_FortranVariableStorageOpInterface>,
fir_FortranObjectViewOpInterface]> {
@@ -3424,6 +3426,14 @@ def fir_DeclareOp
If these operands are absent, then the storage of the declared variable
is only known to start where the memref operand points to.
+ A read from a synthetic DebuggingResource allows reordering
+ fir.declare operations relative to each other, but prevents
+ their reordering relative to the fir.dummy_scope operations
+ which define the procedure scope the variables are declared in.
+ The allocation effect on the DebuggingResource is used to prevent
+ classifying the operation as trivially dead when its result
+ is unused (we still need fir.declare to generate debug information).
+
Example:
CHARACTER(n), OPTIONAL, TARGET :: c(10:, 20:)
@@ -3515,8 +3525,9 @@ def fir_BoxOffsetOp : fir_Op<"box_offset", [NoMemoryEffect]> {
];
}
-def fir_DummyScopeOp : fir_Op<"dummy_scope",
- [MemoryEffects<[MemWrite<DebuggingResource>]>]> {
+def fir_DummyScopeOp
+ : fir_Op<"dummy_scope", [MemoryEffects<[MemRead<DebuggingResource>,
+ MemWrite<DebuggingResource>]>]> {
let summary = "Define a scope for dummy arguments";
let description = [{
@@ -3588,7 +3599,7 @@ def fir_DummyScopeOp : fir_Op<"dummy_scope",
`test`, the two inlined instances of `inner` must use two different
fir.dummy_scope operations for their fir.declare ops. This
two distinct fir.dummy_scope must remain distinct during the optimizations.
- This is guaranteed by the write memory effect on the DebuggingResource.
+ This is guaranteed by the read/write memory effect on the DebuggingResource.
}];
let results = (outs fir_DummyScopeType);
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index e0d309ff73b30..8f6eeec7d9b54 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -37,7 +37,8 @@ class hlfir_Op<string mnemonic, list<Trait> traits>
// don't want to remove it as dead code
def hlfir_DeclareOp
: hlfir_Op<"declare", [AttrSizedOperandSegments,
- MemoryEffects<[MemAlloc<DebuggingResource>]>,
+ MemoryEffects<[MemAlloc<DebuggingResource>,
+ MemRead<DebuggingResource>]>,
DeclareOpInterfaceMethods<
fir_FortranVariableStorageOpInterface>,
fir_FortranObjectViewOpInterface]> {
@@ -78,6 +79,14 @@ def hlfir_DeclareOp
result are known to be the same descriptors (the input descriptor is known
to already have the correct attributes and lower bounds).
+ A read from a synthetic DebuggingResource allows reordering
+ fir.declare operations relative to each other, but prevents
+ their reordering relative to the fir.dummy_scope operations
+ which define the procedure scope the variables are declared in.
+ The allocation effect on the DebuggingResource is used to prevent
+ classifying the operation as trivially dead when its result
+ is unused (we still need hlfir.declare to generate debug information).
+
Example:
CHARACTER(n) :: c(10:n, 20:n)
diff --git a/flang/include/flang/Optimizer/Support/InitFIR.h b/flang/include/flang/Optimizer/Support/InitFIR.h
index d77d82feddd84..831bea265fc6c 100644
--- a/flang/include/flang/Optimizer/Support/InitFIR.h
+++ b/flang/include/flang/Optimizer/Support/InitFIR.h
@@ -128,6 +128,7 @@ inline void registerMLIRPassesForFortranTools() {
mlir::affine::registerAffineLoopInvariantCodeMotionPass();
mlir::affine::registerAffineLoopTilingPass();
mlir::affine::registerAffineDataCopyGenerationPass();
+ mlir::affine::registerAffineParallelizePass();
mlir::registerMem2RegPass();
mlir::registerLowerAffinePass();
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 4234a72192f31..dbc7668571e5e 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -568,6 +568,11 @@ ModRefResult AliasAnalysis::getModRef(Operation *op, Value location) {
if (isa<MemoryEffects::Allocate, MemoryEffects::Free>(effect.getEffect()))
continue;
+ // A unit resource cannot be addressed through any location,
+ // so we can ignore the unit resources.
+ if (effect.getResource() && effect.getResource()->isUnitResource())
+ continue;
+
// Check for an alias between the effect and our memory location.
AliasResult aliasResult = AliasResult::MayAlias;
if (Value effectValue = effect.getValue())
diff --git a/flang/test/Transforms/affine-parallelize.fir b/flang/test/Transforms/affine-parallelize.fir
new file mode 100644
index 0000000000000..6635b7beced3d
--- /dev/null
+++ b/flang/test/Transforms/affine-parallelize.fir
@@ -0,0 +1,14 @@
+// RUN: fir-opt %s -affine-parallelize | FileCheck %s
+
+// Check that a read/write to a unit DebuggingResource
+// by fir.dummy_scope does not prevent parallelization:
+func.func @write_to_debugging_resource() {
+ %cst = arith.constant 0.0 : f32
+ affine.for %i = 0 to 100 {
+ %m = memref.alloc() : memref<1xf32>
+ affine.store %cst, %m[0] : memref<1xf32>
+ %scope = fir.dummy_scope : !fir.dscope
+ }
+ // CHECK: affine.parallel
+ return
+}
diff --git a/flang/test/Transforms/cse.fir b/flang/test/Transforms/cse.fir
new file mode 100644
index 0000000000000..d4bd638ae4811
--- /dev/null
+++ b/flang/test/Transforms/cse.fir
@@ -0,0 +1,23 @@
+// RUN: fir-opt -cse %s | FileCheck %s
+
+// Verify that fir.dummy_scope writing to the DebuggingResource
+// does not prevent CSE for the two fir.load's:
+// CHECK-LABEL: func.func @dummy_scope(
+// CHECK-SAME: %[[ARG0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<f32>,
+// CHECK-SAME: %[[ARG1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<f32>) -> (f32, f32) {
+// CHECK: %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[DECLARE_0:.*]] = fir.declare %[[ARG0]] dummy_scope %[[DUMMY_SCOPE_0]] {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+// CHECK: %[[LOAD_0:.*]] = fir.load %[[DECLARE_0]] : !fir.ref<f32>
+// CHECK: %[[DUMMY_SCOPE_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[DECLARE_1:.*]] = fir.declare %[[ARG1]] dummy_scope %[[DUMMY_SCOPE_1]] {uniq_name = "y"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+// CHECK: return %[[LOAD_0]], %[[LOAD_0]] : f32, f32
+// CHECK: }
+func.func @dummy_scope(%arg0: !fir.ref<f32>, %arg1: !fir.ref<f32>) -> (f32, f32) {
+ %scope1 = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %scope1 {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %1 = fir.load %0 : !fir.ref<f32>
+ %scope2 = fir.dummy_scope : !fir.dscope
+ %2 = fir.declare %arg1 dummy_scope %scope2 {uniq_name = "y"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %3 = fir.load %0 : !fir.ref<f32>
+ return %1, %3 : f32, f32
+}
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index 84fbf2c3d936c..d9013235e1258 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -211,16 +211,38 @@ static constexpr StringLiteral getCombinedConstructsAttrName() {
struct RuntimeCounters
: public mlir::SideEffects::Resource::Base<RuntimeCounters> {
mlir::StringRef getName() final { return "AccRuntimeCounters"; }
+ /// RuntimeCounters is a unit resource implemented by OpenACC
+ /// runtime library. It allows keeping order of OpenACC data operations
+ /// relative to each other (because they cannot be reordered
+ /// without specific analysis taking OpenACC semantics into account).
+ bool isUnitResource() const final { return true; }
+ /// The runtime implementation of the runtime counters is parallel-safe.
+ mlir::SideEffects::Resource::UnitProperties getUnitProperties() const final {
+ return mlir::SideEffects::Resource::UnitProperties::ParallelSafe;
+ }
};
struct ConstructResource
: public mlir::SideEffects::Resource::Base<ConstructResource> {
mlir::StringRef getName() final { return "AccConstructResource"; }
+ /// ConstructResource is a synthetic unit resource that allows
+ /// keeping order of OpenACC constructs relative to each other.
+ /// The OpenACC dialect's construct operations usually read
+ /// and write this resource so that a construct is not deleted
+ /// if it is postdominated by another construct (and has no other
+ /// side effects otherwise).
+ bool isUnitResource() const final { return true; }
+ // TBD: define if this resource is parallel-safe.
};
struct CurrentDeviceIdResource
: public mlir::SideEffects::Resource::Base<CurrentDeviceIdResource> {
mlir::StringRef getName() final { return "AccCurrentDeviceIdResource"; }
+ /// CurrentDeviceIdResource is a unit resource implemented by OpenACC
+ /// runtime library. It allows keeping order of OpenACC operations
+ /// that may read and write the current device id.
+ bool isUnitResource() const final { return true; }
+ // TBD: define if this resource is parallel-safe.
};
} // namespace acc
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
index ee249bb7c3c99..cd4c06f16ab3f 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
@@ -30,7 +30,8 @@ def OpenACC_KernelEnvironmentOp
NoTerminator,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getSuccessorInputs"]>,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "Decomposition of compute constructs to capture data mapping "
"and asynchronous behavior information";
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 0a146db767760..b36b278c88edb 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -1669,10 +1669,11 @@ def OpenACC_ParallelOp
[AttrSizedOperandSegments, AutomaticAllocationScope,
RecursiveMemoryEffects,
DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
- DeclareOpInterfaceMethods<RegionBranchOpInterface,
- ["getSuccessorInputs"]>,
+ DeclareOpInterfaceMethods<
+ RegionBranchOpInterface, ["getSuccessorInputs"]>,
OffloadRegionOpInterface,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "parallel construct";
let description = [{
@@ -1871,10 +1872,11 @@ def OpenACC_SerialOp
[AttrSizedOperandSegments, AutomaticAllocationScope,
RecursiveMemoryEffects,
DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
- DeclareOpInterfaceMethods<RegionBranchOpInterface,
- ["getSuccessorInputs"]>,
+ DeclareOpInterfaceMethods<
+ RegionBranchOpInterface, ["getSuccessorInputs"]>,
OffloadRegionOpInterface,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "serial construct";
let description = [{
@@ -2013,10 +2015,11 @@ def OpenACC_KernelsOp
[AttrSizedOperandSegments, AutomaticAllocationScope,
RecursiveMemoryEffects,
DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
- DeclareOpInterfaceMethods<RegionBranchOpInterface,
- ["getSuccessorInputs"]>,
+ DeclareOpInterfaceMethods<
+ RegionBranchOpInterface, ["getSuccessorInputs"]>,
OffloadRegionOpInterface,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "kernels construct";
let description = [{
@@ -2195,9 +2198,10 @@ def OpenACC_KernelsOp
def OpenACC_DataOp
: OpenACC_Op<
"data", [AttrSizedOperandSegments, RecursiveMemoryEffects,
- DeclareOpInterfaceMethods<RegionBranchOpInterface,
- ["getSuccessorInputs"]>,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
+ DeclareOpInterfaceMethods<
+ RegionBranchOpInterface, ["getSuccessorInputs"]>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "data construct";
@@ -2323,10 +2327,12 @@ def OpenACC_TerminatorOp
// 2.6.6 Enter Data Directive
//===----------------------------------------------------------------------===//
-def OpenACC_EnterDataOp : OpenACC_Op<"enter_data",
- [AttrSizedOperandSegments,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
- MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
+def OpenACC_EnterDataOp
+ : OpenACC_Op<"enter_data",
+ [AttrSizedOperandSegments,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
+ MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "enter data operation";
let description = [{
@@ -2395,10 +2401,12 @@ def OpenACC_EnterDataOp : OpenACC_Op<"enter_data",
// 2.6.6 Exit Data Directive
//===----------------------------------------------------------------------===//
-def OpenACC_ExitDataOp : OpenACC_Op<"exit_data",
- [AttrSizedOperandSegments,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
- MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
+def OpenACC_ExitDataOp
+ : OpenACC_Op<"exit_data",
+ [AttrSizedOperandSegments,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
+ MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "exit data operation";
let description = [{
@@ -2472,9 +2480,10 @@ def OpenACC_ExitDataOp : OpenACC_Op<"exit_data",
def OpenACC_HostDataOp
: OpenACC_Op<"host_data",
[AttrSizedOperandSegments,
- DeclareOpInterfaceMethods<RegionBranchOpInterface,
- ["getSuccessorInputs"]>,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
+ DeclareOpInterfaceMethods<
+ RegionBranchOpInterface, ["getSuccessorInputs"]>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>,
MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
let summary = "host_data construct";
@@ -2519,9 +2528,10 @@ def OpenACC_LoopOp
RecursiveMemoryEffects,
DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
DeclareOpInterfaceMethods<LoopLikeOpInterface>,
- DeclareOpInterfaceMethods<RegionBranchOpInterface,
- ["getSuccessorInputs"]>,
- MemoryEffects<[MemWrite<OpenACC_ConstructResource>]>]> {
+ DeclareOpInterfaceMethods<
+ RegionBranchOpInterface, ["getSuccessorInputs"]>,
+ MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ MemWrite<OpenACC_ConstructResource>]>]> {
let summary = "loop construct";
let description = [{
@@ -3034,9 +3044,11 @@ def AtomicCaptureOp : OpenACC_Op<"atomic.capture",
// 2.13 Declare Directive
//===----------------------------------------------------------------------===//
-def OpenACC_DeclareEnterOp : OpenACC_Op<"declare_enter",
- [MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
- MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
+def OpenACC_DeclareEnterOp
+ : OpenACC_Op<"declare_enter",
+ [MemoryEffects<[MemRead<OpenACC_ConstructResource>,
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/178291
More information about the Mlir-commits
mailing list