Skip to content

[mlir]: Added properties/attributes ignore flags to OperationEquivalence #142623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2025

Conversation

AviadCo
Copy link
Contributor

@AviadCo AviadCo commented Jun 3, 2025

Those flags are useful for cases and operation which we may consider equivalent even when their attributes/properties are not the same.

@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir labels Jun 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 3, 2025

@llvm/pr-subscribers-mlir-core

Author: Aviad Cohen (AviadCo)

Changes

Those flags are useful for cases and operation which we may consider equivalent even when their attributes/properties are not the same.


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

3 Files Affected:

  • (modified) mlir/include/mlir/IR/OperationSupport.h (+8-1)
  • (modified) mlir/lib/IR/OperationSupport.cpp (+16-7)
  • (modified) mlir/unittests/IR/OperationSupportTest.cpp (+25)
diff --git a/mlir/include/mlir/IR/OperationSupport.h b/mlir/include/mlir/IR/OperationSupport.h
index 0046d977c68f4..65e6d4f64e36c 100644
--- a/mlir/include/mlir/IR/OperationSupport.h
+++ b/mlir/include/mlir/IR/OperationSupport.h
@@ -1322,7 +1322,14 @@ struct OperationEquivalence {
     // When provided, the location attached to the operation are ignored.
     IgnoreLocations = 1,
 
-    LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
+    // When provided, the discardable attributes attached to the operation are
+    // ignored.
+    IgnoreDiscardableAttrs = 2,
+
+    // When provided, the properties attached to the operation are ignored.
+    IgnoreProperties = 4,
+
+    LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreProperties)
   };
 
   /// Compute a hash for the given operation.
diff --git a/mlir/lib/IR/OperationSupport.cpp b/mlir/lib/IR/OperationSupport.cpp
index 7c9e6c89d4d8e..038a2075fb4c8 100644
--- a/mlir/lib/IR/OperationSupport.cpp
+++ b/mlir/lib/IR/OperationSupport.cpp
@@ -680,9 +680,13 @@ llvm::hash_code OperationEquivalence::computeHash(
   //   - Operation Name
   //   - Attributes
   //   - Result Types
-  llvm::hash_code hash =
-      llvm::hash_combine(op->getName(), op->getRawDictionaryAttrs(),
-                         op->getResultTypes(), op->hashProperties());
+  DictionaryAttr dictAttrs;
+  if (!(flags & Flags::IgnoreDiscardableAttrs))
+    dictAttrs = op->getRawDictionaryAttrs();
+  llvm::hash_code hash = llvm::hash_combine(
+      op->getName(), dictAttrs, op->getResultTypes());
+  if (!(flags & Flags::IgnoreProperties))
+    hash = llvm::hash_combine(hash, op->hashProperties());
 
   //   - Location if required
   if (!(flags & Flags::IgnoreLocations))
@@ -836,14 +840,19 @@ OperationEquivalence::isRegionEquivalentTo(Region *lhs, Region *rhs,
     return true;
 
   // 1. Compare the operation properties.
+  if (!(flags & IgnoreDiscardableAttrs) &&
+      lhs->getRawDictionaryAttrs() != rhs->getRawDictionaryAttrs())
+    return false;
+
   if (lhs->getName() != rhs->getName() ||
-      lhs->getRawDictionaryAttrs() != rhs->getRawDictionaryAttrs() ||
       lhs->getNumRegions() != rhs->getNumRegions() ||
       lhs->getNumSuccessors() != rhs->getNumSuccessors() ||
       lhs->getNumOperands() != rhs->getNumOperands() ||
-      lhs->getNumResults() != rhs->getNumResults() ||
-      !lhs->getName().compareOpProperties(lhs->getPropertiesStorage(),
-                                          rhs->getPropertiesStorage()))
+      lhs->getNumResults() != rhs->getNumResults())
+    return false;
+  if (!(flags & IgnoreProperties) &&
+      !(lhs->getName().compareOpProperties(lhs->getPropertiesStorage(),
+                                           rhs->getPropertiesStorage())))
     return false;
   if (!(flags & IgnoreLocations) && lhs->getLoc() != rhs->getLoc())
     return false;
diff --git a/mlir/unittests/IR/OperationSupportTest.cpp b/mlir/unittests/IR/OperationSupportTest.cpp
index bac2b72b68deb..18ee9d71cb9fc 100644
--- a/mlir/unittests/IR/OperationSupportTest.cpp
+++ b/mlir/unittests/IR/OperationSupportTest.cpp
@@ -315,6 +315,7 @@ TEST(OperandStorageTest, PopulateDefaultAttrs) {
 TEST(OperationEquivalenceTest, HashWorksWithFlags) {
   MLIRContext context;
   context.getOrLoadDialect<test::TestDialect>();
+  OpBuilder b(&context);
 
   auto *op1 = createOp(&context);
   // `op1` has an unknown loc.
@@ -325,12 +326,36 @@ TEST(OperationEquivalenceTest, HashWorksWithFlags) {
         op, OperationEquivalence::ignoreHashValue,
         OperationEquivalence::ignoreHashValue, flags);
   };
+  // Check ignore location.
   EXPECT_EQ(getHash(op1, OperationEquivalence::IgnoreLocations),
             getHash(op2, OperationEquivalence::IgnoreLocations));
   EXPECT_NE(getHash(op1, OperationEquivalence::None),
             getHash(op2, OperationEquivalence::None));
+  op1->setLoc(NameLoc::get(StringAttr::get(&context, "foo")));
+  // Check ignore discardable dictionary attributes.
+  SmallVector<NamedAttribute> newAttrs = {
+      b.getNamedAttr("foo", b.getStringAttr("f"))};
+  op1->setAttrs(newAttrs);
+  EXPECT_EQ(getHash(op1, OperationEquivalence::IgnoreDiscardableAttrs),
+            getHash(op2, OperationEquivalence::IgnoreDiscardableAttrs));
+  EXPECT_NE(getHash(op1, OperationEquivalence::None),
+            getHash(op2, OperationEquivalence::None));
   op1->destroy();
   op2->destroy();
+
+  // Check ignore properties.
+  auto req1 = b.getI32IntegerAttr(10);
+  Operation *opWithProperty1 = b.create<test::OpAttrMatch1>(
+      b.getUnknownLoc(), req1, nullptr, nullptr, req1);
+  auto req2 = b.getI32IntegerAttr(60);
+  Operation *opWithProperty2 = b.create<test::OpAttrMatch1>(
+      b.getUnknownLoc(), req2, nullptr, nullptr, req2);
+  EXPECT_EQ(getHash(opWithProperty1, OperationEquivalence::IgnoreProperties),
+            getHash(opWithProperty2, OperationEquivalence::IgnoreProperties));
+  EXPECT_NE(getHash(opWithProperty1, OperationEquivalence::None),
+            getHash(opWithProperty2, OperationEquivalence::None));
+  opWithProperty1->destroy();
+  opWithProperty2->destroy();
 }
 
 } // namespace

@llvmbot
Copy link
Member

llvmbot commented Jun 3, 2025

@llvm/pr-subscribers-mlir

Author: Aviad Cohen (AviadCo)

Changes

Those flags are useful for cases and operation which we may consider equivalent even when their attributes/properties are not the same.


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

3 Files Affected:

  • (modified) mlir/include/mlir/IR/OperationSupport.h (+8-1)
  • (modified) mlir/lib/IR/OperationSupport.cpp (+16-7)
  • (modified) mlir/unittests/IR/OperationSupportTest.cpp (+25)
diff --git a/mlir/include/mlir/IR/OperationSupport.h b/mlir/include/mlir/IR/OperationSupport.h
index 0046d977c68f4..65e6d4f64e36c 100644
--- a/mlir/include/mlir/IR/OperationSupport.h
+++ b/mlir/include/mlir/IR/OperationSupport.h
@@ -1322,7 +1322,14 @@ struct OperationEquivalence {
     // When provided, the location attached to the operation are ignored.
     IgnoreLocations = 1,
 
-    LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
+    // When provided, the discardable attributes attached to the operation are
+    // ignored.
+    IgnoreDiscardableAttrs = 2,
+
+    // When provided, the properties attached to the operation are ignored.
+    IgnoreProperties = 4,
+
+    LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreProperties)
   };
 
   /// Compute a hash for the given operation.
diff --git a/mlir/lib/IR/OperationSupport.cpp b/mlir/lib/IR/OperationSupport.cpp
index 7c9e6c89d4d8e..038a2075fb4c8 100644
--- a/mlir/lib/IR/OperationSupport.cpp
+++ b/mlir/lib/IR/OperationSupport.cpp
@@ -680,9 +680,13 @@ llvm::hash_code OperationEquivalence::computeHash(
   //   - Operation Name
   //   - Attributes
   //   - Result Types
-  llvm::hash_code hash =
-      llvm::hash_combine(op->getName(), op->getRawDictionaryAttrs(),
-                         op->getResultTypes(), op->hashProperties());
+  DictionaryAttr dictAttrs;
+  if (!(flags & Flags::IgnoreDiscardableAttrs))
+    dictAttrs = op->getRawDictionaryAttrs();
+  llvm::hash_code hash = llvm::hash_combine(
+      op->getName(), dictAttrs, op->getResultTypes());
+  if (!(flags & Flags::IgnoreProperties))
+    hash = llvm::hash_combine(hash, op->hashProperties());
 
   //   - Location if required
   if (!(flags & Flags::IgnoreLocations))
@@ -836,14 +840,19 @@ OperationEquivalence::isRegionEquivalentTo(Region *lhs, Region *rhs,
     return true;
 
   // 1. Compare the operation properties.
+  if (!(flags & IgnoreDiscardableAttrs) &&
+      lhs->getRawDictionaryAttrs() != rhs->getRawDictionaryAttrs())
+    return false;
+
   if (lhs->getName() != rhs->getName() ||
-      lhs->getRawDictionaryAttrs() != rhs->getRawDictionaryAttrs() ||
       lhs->getNumRegions() != rhs->getNumRegions() ||
       lhs->getNumSuccessors() != rhs->getNumSuccessors() ||
       lhs->getNumOperands() != rhs->getNumOperands() ||
-      lhs->getNumResults() != rhs->getNumResults() ||
-      !lhs->getName().compareOpProperties(lhs->getPropertiesStorage(),
-                                          rhs->getPropertiesStorage()))
+      lhs->getNumResults() != rhs->getNumResults())
+    return false;
+  if (!(flags & IgnoreProperties) &&
+      !(lhs->getName().compareOpProperties(lhs->getPropertiesStorage(),
+                                           rhs->getPropertiesStorage())))
     return false;
   if (!(flags & IgnoreLocations) && lhs->getLoc() != rhs->getLoc())
     return false;
diff --git a/mlir/unittests/IR/OperationSupportTest.cpp b/mlir/unittests/IR/OperationSupportTest.cpp
index bac2b72b68deb..18ee9d71cb9fc 100644
--- a/mlir/unittests/IR/OperationSupportTest.cpp
+++ b/mlir/unittests/IR/OperationSupportTest.cpp
@@ -315,6 +315,7 @@ TEST(OperandStorageTest, PopulateDefaultAttrs) {
 TEST(OperationEquivalenceTest, HashWorksWithFlags) {
   MLIRContext context;
   context.getOrLoadDialect<test::TestDialect>();
+  OpBuilder b(&context);
 
   auto *op1 = createOp(&context);
   // `op1` has an unknown loc.
@@ -325,12 +326,36 @@ TEST(OperationEquivalenceTest, HashWorksWithFlags) {
         op, OperationEquivalence::ignoreHashValue,
         OperationEquivalence::ignoreHashValue, flags);
   };
+  // Check ignore location.
   EXPECT_EQ(getHash(op1, OperationEquivalence::IgnoreLocations),
             getHash(op2, OperationEquivalence::IgnoreLocations));
   EXPECT_NE(getHash(op1, OperationEquivalence::None),
             getHash(op2, OperationEquivalence::None));
+  op1->setLoc(NameLoc::get(StringAttr::get(&context, "foo")));
+  // Check ignore discardable dictionary attributes.
+  SmallVector<NamedAttribute> newAttrs = {
+      b.getNamedAttr("foo", b.getStringAttr("f"))};
+  op1->setAttrs(newAttrs);
+  EXPECT_EQ(getHash(op1, OperationEquivalence::IgnoreDiscardableAttrs),
+            getHash(op2, OperationEquivalence::IgnoreDiscardableAttrs));
+  EXPECT_NE(getHash(op1, OperationEquivalence::None),
+            getHash(op2, OperationEquivalence::None));
   op1->destroy();
   op2->destroy();
+
+  // Check ignore properties.
+  auto req1 = b.getI32IntegerAttr(10);
+  Operation *opWithProperty1 = b.create<test::OpAttrMatch1>(
+      b.getUnknownLoc(), req1, nullptr, nullptr, req1);
+  auto req2 = b.getI32IntegerAttr(60);
+  Operation *opWithProperty2 = b.create<test::OpAttrMatch1>(
+      b.getUnknownLoc(), req2, nullptr, nullptr, req2);
+  EXPECT_EQ(getHash(opWithProperty1, OperationEquivalence::IgnoreProperties),
+            getHash(opWithProperty2, OperationEquivalence::IgnoreProperties));
+  EXPECT_NE(getHash(opWithProperty1, OperationEquivalence::None),
+            getHash(opWithProperty2, OperationEquivalence::None));
+  opWithProperty1->destroy();
+  opWithProperty2->destroy();
 }
 
 } // namespace

@AviadCo
Copy link
Contributor Author

AviadCo commented Jun 3, 2025

@vitalybuka I think I found the issue caused to the regression in #141664
Is it possible to use a bot to run on my PR before merging it? I am unable to reproduce the issue locally

Those flags are useful for cases and operation which we may consider equivalent even when their attributes/properties are not the same.
@AviadCo AviadCo force-pushed the hash/ignore-prop-attrs branch from 637faae to 17d38dd Compare June 3, 2025 15:01
@AviadCo AviadCo requested a review from vitalybuka June 3, 2025 19:01
@vitalybuka
Copy link
Collaborator

@vitalybuka I think I found the issue caused to the regression in #141664 Is it possible to use a bot to run on my PR before merging it? I am unable to reproduce the issue locally

We can, but It's some hassle.
Let's just submit, if it's not enough we revert, and I will help you either reproduce or debug?

@AviadCo
Copy link
Contributor Author

AviadCo commented Jun 4, 2025

@vitalybuka I think I found the issue caused to the regression in #141664 Is it possible to use a bot to run on my PR before merging it? I am unable to reproduce the issue locally

We can, but It's some hassle. Let's just submit, if it's not enough we revert, and I will help you either reproduce or debug?

sounds good to me, I will merge it

@AviadCo AviadCo merged commit 4c64490 into llvm:main Jun 4, 2025
11 checks passed
rorth pushed a commit to rorth/llvm-project that referenced this pull request Jun 11, 2025
…nce (llvm#142623)

Those flags are useful for cases and operation which we may consider equivalent even when their attributes/properties are not the same.
DhruvSrivastavaX pushed a commit to DhruvSrivastavaX/lldb-for-aix that referenced this pull request Jun 12, 2025
…nce (llvm#142623)

Those flags are useful for cases and operation which we may consider equivalent even when their attributes/properties are not the same.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:core MLIR Core Infrastructure mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants