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

Slava Zakharin llvmlistbot at llvm.org
Thu Mar 19 16:55:42 PDT 2026


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

>From 50006b96cc9202d74082427620217101bc3d2a5b Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Wed, 18 Mar 2026 17:34:27 -0700
Subject: [PATCH 1/2] [mlir] Adding AnyResource to MLIR Side Effects.

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).
---
 .../mlir/Interfaces/SideEffectInterfaces.h    | 19 +++++++++++++---
 .../Analysis/test-alias-analysis-modref.mlir  | 22 +++++++++++++++++++
 mlir/test/IR/test-side-effects.mlir           |  9 ++++++++
 mlir/test/lib/Dialect/Test/TestOpDefs.cpp     | 16 ++++++++++++++
 mlir/test/lib/Dialect/Test/TestOps.td         |  7 ++++++
 .../Interfaces/SideEffectInterfacesTest.cpp   |  5 +++--
 6 files changed, 73 insertions(+), 5 deletions(-)

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()));

>From 6df9077e94b308390d98043b2ac3ce5f4046b407 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Thu, 19 Mar 2026 15:50:31 -0700
Subject: [PATCH 2/2] Replaced AnyResource with DefaultResource.

---
 .../mlir/Interfaces/SideEffectInterfaces.h    | 22 +++++---------
 mlir/lib/Transforms/CSE.cpp                   | 26 ++++++++++------
 .../Analysis/test-alias-analysis-modref.mlir  |  5 ++--
 mlir/test/IR/test-side-effects.mlir           |  8 ++---
 mlir/test/Transforms/cse.mlir                 | 30 ++++++++++++++-----
 mlir/test/lib/Dialect/Test/TestOpDefs.cpp     |  2 +-
 .../Interfaces/SideEffectInterfacesTest.cpp   | 24 ++++++++-------
 7 files changed, 70 insertions(+), 47 deletions(-)

diff --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
index b7b525732e3e0..dfffbcaf1bbab 100644
--- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
+++ b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
@@ -175,23 +175,13 @@ class Resource {
   TypeID id;
 };
 
-/// 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.
+/// The default resource kind. It serves as the root of the resource hierarchy:
+/// all resources that do not override getParent() have DefaultResource as their
+/// parent.
 struct DefaultResource : public Resource::Base<DefaultResource> {
   DefaultResource() = default;
   StringRef getName() const override { return "<Default>"; }
+  Resource *getParent() const override { return nullptr; }
 
 protected:
   /// For use when this type is the parent of another resource; allows the
@@ -199,6 +189,10 @@ struct DefaultResource : public Resource::Base<DefaultResource> {
   DefaultResource(TypeID id) : Base(id) {}
 };
 
+/// All resources that do not override getParent() have DefaultResource
+/// as their parent.
+inline Resource *Resource::getParent() const { return DefaultResource::get(); }
+
 /// An automatic allocation-scope resource that is valid in the context of a
 /// parent AutomaticAllocationScope trait.
 struct AutomaticAllocationScopeResource
diff --git a/mlir/lib/Transforms/CSE.cpp b/mlir/lib/Transforms/CSE.cpp
index 7870f1f401890..9c6427c555cc8 100644
--- a/mlir/lib/Transforms/CSE.cpp
+++ b/mlir/lib/Transforms/CSE.cpp
@@ -182,15 +182,15 @@ bool CSEDriver::hasOtherSideEffectingOpInBetween(Operation *fromOp,
   assert(hasEffect<MemoryEffects::Read>(toOp) &&
          "expected read effect on toOp");
 
-  // Collect the resources of fromOp's read effects. A write can only block
-  // CSE if its resource is not disjoint from one of these.
-  SmallPtrSet<SideEffects::Resource *, 1> readResources;
+  // Collect the read effects of fromOp. A write can only block CSE if it
+  // can conflict with one of these reads.
+  SmallVector<MemoryEffects::EffectInstance> readEffects;
   if (auto memOp = dyn_cast<MemoryEffectOpInterface>(fromOp)) {
     SmallVector<MemoryEffects::EffectInstance> fromEffects;
     memOp.getEffects(fromEffects);
-    for (const auto &e : fromEffects)
+    for (MemoryEffects::EffectInstance &e : fromEffects)
       if (isa<MemoryEffects::Read>(e.getEffect()))
-        readResources.insert(e.getResource());
+        readEffects.push_back(e);
   }
 
   Operation *nextOp = fromOp->getNextNode();
@@ -224,10 +224,18 @@ bool CSEDriver::hasOtherSideEffectingOpInBetween(Operation *fromOp,
       if (isa<MemoryEffects::Write>(effect.getEffect())) {
         // A write on a resource disjoint from all read resources cannot
         // conflict with the reads being CSE'd.
-        auto *writeResource = effect.getResource();
-        bool canConflict = llvm::any_of(readResources, [&](auto *readResource) {
-          return !writeResource->isDisjointFrom(readResource);
-        });
+        SideEffects::Resource *writeResource = effect.getResource();
+        bool canConflict =
+            llvm::any_of(readEffects, [&](const auto &readEffect) {
+              SideEffects::Resource *readResource = readEffect.getResource();
+              if (writeResource->isDisjointFrom(readResource))
+                return false;
+              // A pointer-based access to an addressable resource cannot
+              // conflict with a non-addressable resource.
+              if (readEffect.getValue() && !writeResource->isAddressable())
+                return false;
+              return true;
+            });
         if (canConflict) {
           result.first->second = {nextOp, MemoryEffects::Write::get()};
           return true;
diff --git a/mlir/test/Analysis/test-alias-analysis-modref.mlir b/mlir/test/Analysis/test-alias-analysis-modref.mlir
index 5ff83bedd2856..2a9c612317d53 100644
--- a/mlir/test/Analysis/test-alias-analysis-modref.mlir
+++ b/mlir/test/Analysis/test-alias-analysis-modref.mlir
@@ -92,7 +92,7 @@ func.func @addressable_write(%arg: memref<2xf32>) attributes {test.ptr = "func"}
 
 // -----
 
-// An op with no side effects (safe) does not mod-ref any memory.
+// An op with no side effects 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
@@ -103,7 +103,8 @@ func.func @conditional_no_effects(%arg: memref<2xf32>) attributes {test.ptr = "f
 
 // -----
 
-// An op with read/write/free/alloc effects on AnyResource may mod-ref any memory.
+// An op with read/write/free/alloc effects on DefaultResource
+// 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
diff --git a/mlir/test/IR/test-side-effects.mlir b/mlir/test/IR/test-side-effects.mlir
index de13581d5628b..f66937a9ec943 100644
--- a/mlir/test/IR/test-side-effects.mlir
+++ b/mlir/test/IR/test-side-effects.mlir
@@ -59,10 +59,10 @@ func.func @side_effect(%arg : 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>'}}
+  // expected-remark at +4 {{found an instance of 'read' on resource '<Default>'}}
+  // expected-remark at +3 {{found an instance of 'write' on resource '<Default>'}}
+  // expected-remark at +2 {{found an instance of 'free' on resource '<Default>'}}
+  // expected-remark at +1 {{found an instance of 'allocate' on resource '<Default>'}}
   %10 = "test.conditional_side_effect_op"() {has_effects = true} : () -> i32
 
   func.return 
diff --git a/mlir/test/Transforms/cse.mlir b/mlir/test/Transforms/cse.mlir
index 14cdcdeffd1ec..dc967d5f5c6c4 100644
--- a/mlir/test/Transforms/cse.mlir
+++ b/mlir/test/Transforms/cse.mlir
@@ -576,14 +576,30 @@ func.func @cse_recursive_effects_failure() -> (i32, i32, i32) {
 
 // -----
 
-/// Check that a write on a resource disjoint from DefaultResource does not
-/// block CSE of reads on DefaultResource, because the resources are disjoint.
-// CHECK-LABEL: @cse_non_addressable_write_does_not_block
-func.func @cse_non_addressable_write_does_not_block() -> i32 {
-  // CHECK-NEXT: %[[V:.*]] = "test.op_with_memread"() : () -> i32
+/// A non-addressable write on a subresource of DefaultResource, so it is NOT
+/// disjoint. Without a pointer-based read, the write conservatively conflicts.
+// CHECK-LABEL: @cse_non_addressable_write_blocks_non_pointer_read
+func.func @cse_non_addressable_write_blocks_non_pointer_read() -> i32 {
+  // CHECK-NEXT: %[[V0:.*]] = "test.op_with_memread"() : () -> i32
   %0 = "test.op_with_memread"() : () -> (i32)
   "test.side_effect_op"() {effects = [{effect="write", test_nonaddressable_resource}]} : () -> i32
+  // CHECK: %[[V1:.*]] = "test.op_with_memread"() : () -> i32
   %1 = "test.op_with_memread"() : () -> (i32)
+  // CHECK: %{{.*}} = arith.addi %[[V0]], %[[V1]] : i32
+  %2 = arith.addi %0, %1 : i32
+  return %2 : i32
+}
+
+// -----
+
+/// A pointer-based read on an addressable resource (DefaultResource) cannot
+/// conflict with a write on a non-addressable resource, so CSE proceeds.
+// CHECK-LABEL: @cse_non_addressable_write_does_not_block_pointer_read
+func.func @cse_non_addressable_write_does_not_block_pointer_read() -> i32 {
+  // CHECK-NEXT: %[[V:.*]] = "test.side_effect_op"()
+  %0 = "test.side_effect_op"() {effects = [{effect="read", on_result}]} : () -> i32
+  "test.side_effect_op"() {effects = [{effect="write", test_nonaddressable_resource}]} : () -> i32
+  %1 = "test.side_effect_op"() {effects = [{effect="read", on_result}]} : () -> i32
   // CHECK-NEXT: %{{.*}} = "test.side_effect_op"()
   // CHECK-NEXT: %{{.*}} = arith.addi %[[V]], %[[V]] : i32
   %2 = arith.addi %0, %1 : i32
@@ -592,7 +608,7 @@ func.func @cse_non_addressable_write_does_not_block() -> i32 {
 
 // -----
 
-/// Check that consecutive reads on the same resource (disjoint from DefaultResource) are CSE'd
+/// Check that consecutive reads on the same non-addressable resource are CSE'd
 /// when there is no intervening write.
 // CHECK-LABEL: @cse_reads_on_same_nonaddressable_resource
 func.func @cse_reads_on_same_nonaddressable_resource() -> i32 {
@@ -623,7 +639,7 @@ func.func @cse_write_same_nonaddressable_resource_blocks() -> i32 {
 // -----
 
 /// Check that a write to a resource disjoint from the read resource does NOT
-/// block CSE (sibling resources under different roots are disjoint).
+/// block CSE (sibling non-addressable subresources are disjoint).
 // CHECK-LABEL: @cse_write_disjoint_nonaddressable_subresource_allows
 func.func @cse_write_disjoint_nonaddressable_subresource_allows() -> i32 {
   // CHECK-NEXT: %[[V:.*]] = "test.side_effect_op"()
diff --git a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
index 072abdd67ab1f..5d2121ce26671 100644
--- a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
+++ b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
@@ -510,7 +510,7 @@ void ConditionalSideEffectOp::getEffects(
   if (!getHasEffects())
     return;
 
-  SideEffects::Resource *resource = SideEffects::AnyResource::get();
+  SideEffects::Resource *resource = SideEffects::DefaultResource::get();
   effects.emplace_back(MemoryEffects::Read::get(), resource);
   effects.emplace_back(MemoryEffects::Write::get(), resource);
   effects.emplace_back(MemoryEffects::Free::get(), resource);
diff --git a/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp b/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp
index e1b02d689b995..d7dbdd08f0416 100644
--- a/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp
+++ b/mlir/unittests/Interfaces/SideEffectInterfacesTest.cpp
@@ -91,8 +91,8 @@ TEST(SideEffectResourceTest, CustomHierarchyIsaCast) {
   EXPECT_EQ(TestGrandchildResource::get()->getParent(),
             TestChildResource::get());
   EXPECT_EQ(TestChildResource::get()->getParent(), TestRootResource::get());
-  EXPECT_EQ(TestRootResource::get()->getParent(), AnyResource::get());
-  EXPECT_EQ(AnyResource::get()->getParent(), nullptr);
+  EXPECT_EQ(TestRootResource::get()->getParent(), DefaultResource::get());
+  EXPECT_EQ(DefaultResource::get()->getParent(), nullptr);
 
   // isSubresourceOf
   EXPECT_TRUE(
@@ -102,21 +102,25 @@ TEST(SideEffectResourceTest, CustomHierarchyIsaCast) {
   EXPECT_FALSE(
       TestRootResource::get()->isSubresourceOf(TestGrandchildResource::get()));
 
-  // Custom hierarchy disjoint from DefaultResource
-  EXPECT_TRUE(TestRootResource::get()->isDisjointFrom(DefaultResource::get()));
-  EXPECT_FALSE(isa<DefaultResource>(TestRootResource::get()));
-  EXPECT_FALSE(isa<DefaultResource>(TestChildResource::get()));
-  EXPECT_FALSE(isa<DefaultResource>(TestGrandchildResource::get()));
+  // Custom hierarchy is a subresource of DefaultResource (the root).
+  EXPECT_FALSE(TestRootResource::get()->isDisjointFrom(DefaultResource::get()));
+  EXPECT_TRUE(TestRootResource::get()->isSubresourceOf(DefaultResource::get()));
+  EXPECT_TRUE(
+      TestGrandchildResource::get()->isSubresourceOf(DefaultResource::get()));
+  EXPECT_FALSE(
+      DefaultResource::get()->isSubresourceOf(TestRootResource::get()));
   EXPECT_FALSE(isa<TestRootResource>(DefaultResource::get()));
-  EXPECT_EQ(dyn_cast<DefaultResource>(TestGrandchildResource::get()), nullptr);
   EXPECT_EQ(dyn_cast<TestRootResource>(DefaultResource::get()), nullptr);
 }
 
 TEST(SideEffectResourceTest, DisjointnessAndGetParent) {
-  EXPECT_EQ(DefaultResource::get()->getParent(), AnyResource::get());
+  EXPECT_EQ(DefaultResource::get()->getParent(), nullptr);
   EXPECT_EQ(AutomaticAllocationScopeResource::get()->getParent(),
             DefaultResource::get());
-  EXPECT_TRUE(DefaultResource::get()->isDisjointFrom(TestRootResource::get()));
+  // TestRootResource is a subresource of DefaultResource (the root),
+  // so they are not disjoint.
+  EXPECT_FALSE(DefaultResource::get()->isDisjointFrom(TestRootResource::get()));
+  EXPECT_TRUE(TestRootResource::get()->isSubresourceOf(DefaultResource::get()));
   EXPECT_TRUE(
       TestChildResource::get()->isSubresourceOf(TestRootResource::get()));
   EXPECT_FALSE(



More information about the Mlir-commits mailing list