[Mlir-commits] [mlir] [mlir] Adding AnyResource to MLIR Side Effects. (PR #187423)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Mar 18 19:15:20 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Slava Zakharin (vzakhari)

<details>
<summary>Changes</summary>

The new resource overlaps with any other resource whether
it is addressable or not.

The only use case for this so far is to implement "conditional"
MemoryEffectsOpInterface such that some instances of an operation
return some known memory effects, and some instances return
"unknown" memory effects by affecting AnyResource
(i.e. the operation may conflict with any other operation
that addresses any memory).

RFC: https://discourse.llvm.org/t/rfc-mlir-memory-region-hierarchy-for-mlir-side-effects/89811/32

---
Full diff: https://github.com/llvm/llvm-project/pull/187423.diff


6 Files Affected:

- (modified) mlir/include/mlir/Interfaces/SideEffectInterfaces.h (+16-3) 
- (modified) mlir/test/Analysis/test-alias-analysis-modref.mlir (+22) 
- (modified) mlir/test/IR/test-side-effects.mlir (+9) 
- (modified) mlir/test/lib/Dialect/Test/TestOpDefs.cpp (+16) 
- (modified) mlir/test/lib/Dialect/Test/TestOps.td (+7) 
- (modified) mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp (+3-2) 


``````````diff
diff --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
index 97f860565b183..b7b525732e3e0 100644
--- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
+++ b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
@@ -127,8 +127,8 @@ class Resource {
   /// Return a string name of the resource.
   virtual StringRef getName() const = 0;
 
-  /// Return the parent resource in the hierarchy, or nullptr for a root.
-  virtual Resource *getParent() const { return nullptr; }
+  /// Return the parent resource in the hierarchy.
+  virtual Resource *getParent() const;
 
   /// Returns true if this resource is addressable (effects on it can alias
   /// pointer-based memory). Default is true.
@@ -175,7 +175,20 @@ class Resource {
   TypeID id;
 };
 
-/// A conservative default resource kind.
+/// Special kind of resource that includes all other resources
+/// regardless of whether they are addressable or not.
+/// It might be used to specify an effect on all resources.
+struct AnyResource : public Resource::Base<AnyResource> {
+  StringRef getName() const final { return "<AnyResource>"; }
+  Resource *getParent() const override { return nullptr; }
+};
+
+/// All resources that do not override getParent() have AnyResource
+/// as their parent so that none of the resources is disjoint
+/// from AnyResource.
+inline Resource *Resource::getParent() const { return AnyResource::get(); }
+
+/// A conservative default addressable resource kind.
 struct DefaultResource : public Resource::Base<DefaultResource> {
   DefaultResource() = default;
   StringRef getName() const override { return "<Default>"; }
diff --git a/mlir/test/Analysis/test-alias-analysis-modref.mlir b/mlir/test/Analysis/test-alias-analysis-modref.mlir
index b82f789f4d77d..5ff83bedd2856 100644
--- a/mlir/test/Analysis/test-alias-analysis-modref.mlir
+++ b/mlir/test/Analysis/test-alias-analysis-modref.mlir
@@ -89,3 +89,25 @@ func.func @addressable_write(%arg: memref<2xf32>) attributes {test.ptr = "func"}
   "test.side_effect_op"() {effects = [{effect="write"}], test.ptr = "side_effect_op"} : () -> i32
   return {test.ptr = "return"}
 }
+
+// -----
+
+// An op with no side effects (safe) does not mod-ref any memory.
+// CHECK-LABEL: Testing : "conditional_no_effects"
+// CHECK-DAG: conditional_side_effect_op -> func.region0#0: NoModRef
+// CHECK-DAG: return -> func.region0#0: NoModRef
+func.func @conditional_no_effects(%arg: memref<2xf32>) attributes {test.ptr = "func"} {
+  "test.conditional_side_effect_op"() {has_effects = false, test.ptr = "conditional_side_effect_op"} : () -> i32
+  return {test.ptr = "return"}
+}
+
+// -----
+
+// An op with read/write/free/alloc effects on AnyResource may mod-ref any memory.
+// CHECK-LABEL: Testing : "conditional_all_effects"
+// CHECK-DAG: conditional_side_effect_op -> func.region0#0: ModRef
+// CHECK-DAG: return -> func.region0#0: NoModRef
+func.func @conditional_all_effects(%arg: memref<2xf32>) attributes {test.ptr = "func"} {
+  "test.conditional_side_effect_op"() {has_effects = true, test.ptr = "conditional_side_effect_op"} : () -> i32
+  return {test.ptr = "return"}
+}
diff --git a/mlir/test/IR/test-side-effects.mlir b/mlir/test/IR/test-side-effects.mlir
index b652ecb7dad1d..de13581d5628b 100644
--- a/mlir/test/IR/test-side-effects.mlir
+++ b/mlir/test/IR/test-side-effects.mlir
@@ -56,5 +56,14 @@ func.func @side_effect(%arg : index) {
     test.region_yield %arg0 : index 
   } {effects = [ {effect="allocate", on_argument, test_resource} ]} : index -> index
 
+  // expected-remark at +1 {{operation has no memory effects}}
+  %9 = "test.conditional_side_effect_op"() {has_effects = false} : () -> i32
+
+  // expected-remark at +4 {{found an instance of 'read' on resource '<AnyResource>'}}
+  // expected-remark at +3 {{found an instance of 'write' on resource '<AnyResource>'}}
+  // expected-remark at +2 {{found an instance of 'free' on resource '<AnyResource>'}}
+  // expected-remark at +1 {{found an instance of 'allocate' on resource '<AnyResource>'}}
+  %10 = "test.conditional_side_effect_op"() {has_effects = true} : () -> i32
+
   func.return 
 }
diff --git a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
index ed5dc5bead78a..072abdd67ab1f 100644
--- a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
+++ b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
@@ -501,6 +501,22 @@ void SideEffectOp::getEffects(
   testSideEffectOpGetEffect(getOperation(), effects);
 }
 
+//===----------------------------------------------------------------------===//
+// ConditionalSideEffectOp
+//===----------------------------------------------------------------------===//
+
+void ConditionalSideEffectOp::getEffects(
+    SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+  if (!getHasEffects())
+    return;
+
+  SideEffects::Resource *resource = SideEffects::AnyResource::get();
+  effects.emplace_back(MemoryEffects::Read::get(), resource);
+  effects.emplace_back(MemoryEffects::Write::get(), resource);
+  effects.emplace_back(MemoryEffects::Free::get(), resource);
+  effects.emplace_back(MemoryEffects::Allocate::get(), resource);
+}
+
 void SideEffectWithRegionOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   // Check for an effects attribute on the op instance.
diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index 4c9e6b3fe9e45..f9ffddd1300b6 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -2472,6 +2472,13 @@ def SideEffectOp : TEST_Op<"side_effect_op",
   let results = (outs AnyType:$result);
 }
 
+def ConditionalSideEffectOp
+    : TEST_Op<"conditional_side_effect_op", [DeclareOpInterfaceMethods<
+                                                MemoryEffectsOpInterface>]> {
+  let arguments = (ins BoolAttr:$has_effects);
+  let results = (outs AnyType:$result);
+}
+
 def SideEffectWithRegionOp : TEST_Op<"side_effect_with_region_op",
     [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
      DeclareOpInterfaceMethods<TestEffectOpInterface>]> {
diff --git a/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp b/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp
index 2f7f7a889ccab..e1b02d689b995 100644
--- a/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp
+++ b/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp
@@ -91,7 +91,8 @@ TEST(SideEffectResourceTest, CustomHierarchyIsaCast) {
   EXPECT_EQ(TestGrandchildResource::get()->getParent(),
             TestChildResource::get());
   EXPECT_EQ(TestChildResource::get()->getParent(), TestRootResource::get());
-  EXPECT_EQ(TestRootResource::get()->getParent(), nullptr);
+  EXPECT_EQ(TestRootResource::get()->getParent(), AnyResource::get());
+  EXPECT_EQ(AnyResource::get()->getParent(), nullptr);
 
   // isSubresourceOf
   EXPECT_TRUE(
@@ -112,7 +113,7 @@ TEST(SideEffectResourceTest, CustomHierarchyIsaCast) {
 }
 
 TEST(SideEffectResourceTest, DisjointnessAndGetParent) {
-  EXPECT_EQ(DefaultResource::get()->getParent(), nullptr);
+  EXPECT_EQ(DefaultResource::get()->getParent(), AnyResource::get());
   EXPECT_EQ(AutomaticAllocationScopeResource::get()->getParent(),
             DefaultResource::get());
   EXPECT_TRUE(DefaultResource::get()->isDisjointFrom(TestRootResource::get()));

``````````

</details>


https://github.com/llvm/llvm-project/pull/187423


More information about the Mlir-commits mailing list