This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new 897be720a6 [Relax] Fix FuseOpsByPattern dropping bound constants on 
duplicate-structure functions (#19801)
897be720a6 is described below

commit 897be720a60a9029824bc61ed8a5634bef8fb71f
Author: Shushi Hong <[email protected]>
AuthorDate: Tue Jun 16 20:13:43 2026 -0400

    [Relax] Fix FuseOpsByPattern dropping bound constants on 
duplicate-structure functions (#19801)
    
    BlockBuilder::AddFunction deduplicates context functions through a map
    whose hash (StructuralHashIgnoreNDarray) intentionally ignores tensor
    content for speed. Its equality, however, was the default
    ffi::StructuralEqual, whose operator() also skips tensor content. As a
    result two grouped functions that differ only in their bound constants
    -- e.g. two conv layers with different weights produced by
    FuseOpsByPattern(bind_constants=True) -- compared equal and were merged,
    silently dropping all but the first constant and miscompiling the
    result.
    
    A hash may be approximate, but the dedup equality must be exact. This pr
    adds a value-aware equality functor (skip_tensor_content=false) and use
    it as the map's KeyEqual, keeping the fast content-ignoring hash.
    Functions with identical constants still dedup; functions with differing
    constants no longer do.
---
 src/relax/ir/block_builder.cc | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/relax/ir/block_builder.cc b/src/relax/ir/block_builder.cc
index f9360c6c42..fe6887a97e 100644
--- a/src/relax/ir/block_builder.cc
+++ b/src/relax/ir/block_builder.cc
@@ -429,6 +429,20 @@ class BlockBuilderImpl : public BlockBuilderNode {
     }
   };
 
+  /*!
+   * \brief Structural equality that DOES compare tensor (constant) data 
content. The hash above
+   * intentionally ignores tensor content for speed, but the equality must 
stay exact: otherwise two
+   * grouped functions that differ only in their bound constants (e.g. two 
conv layers with
+   * different weights) would be incorrectly treated as duplicates and merged.
+   */
+  class StructuralEqualConsiderNDarray {
+   public:
+    bool operator()(const ffi::ObjectRef& lhs, const ffi::ObjectRef& rhs) 
const {
+      return ffi::StructuralEqual::Equal(lhs, rhs, /*map_free_vars=*/false,
+                                         /*skip_tensor_content=*/false);
+    }
+  };
+
   /*!
    * \brief A hashmap to store the mapping of Relax functions and TIR PrimFuncs
    * in context_mod to their GlobalVar to avoid generating duplicated 
functions.
@@ -436,7 +450,7 @@ class BlockBuilderImpl : public BlockBuilderNode {
    */
   std::unique_ptr<std::unordered_map<
       BaseFunc, std::unordered_set<GlobalVar, ffi::ObjectPtrHash, 
ffi::ObjectPtrEqual>,
-      StructuralHashIgnoreNDarray, ffi::StructuralEqual>>
+      StructuralHashIgnoreNDarray, StructuralEqualConsiderNDarray>>
       ctx_func_dedup_map_ = nullptr;
 
   /*!
@@ -446,7 +460,7 @@ class BlockBuilderImpl : public BlockBuilderNode {
     if (ctx_func_dedup_map_ != nullptr) return;
     ctx_func_dedup_map_ = std::make_unique<std::unordered_map<
         BaseFunc, std::unordered_set<GlobalVar, ffi::ObjectPtrHash, 
ffi::ObjectPtrEqual>,
-        StructuralHashIgnoreNDarray, ffi::StructuralEqual>>();
+        StructuralHashIgnoreNDarray, StructuralEqualConsiderNDarray>>();
     for (const auto& kv : context_mod_->functions) {
       const GlobalVar gv = kv.first;
       const BaseFunc func = kv.second;

Reply via email to