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 deb11d384e [TIR] Use IRModuleNode::Remove to remove None in 
PrimFuncPass (#14494)
deb11d384e is described below

commit deb11d384e753907c8ce1ea93957888609622ad5
Author: Eric Lunderberg <[email protected]>
AuthorDate: Wed Apr 5 09:09:28 2023 -0500

    [TIR] Use IRModuleNode::Remove to remove None in PrimFuncPass (#14494)
    
    Prior to this commit, `PrimFuncPass` directly removed empty `PrimFunc`
    objects from the module's `Map<GlobalVar, BaseFunc> functions`.
    Because it didn't update the `global_var_map_` as well, these two maps
    could become out of sync.  Since the `global_var_map_` is checked as
    part of `StructuralEqual()`, but isn't displayed when printing to
    TVMScript, this can result in identical printouts being flagged as
    non-identical.
    
    This commit updates `PrimFuncPass` to call the `IRModuleNode::Remove`
    method, which updates both the `functions` and `global_var_map_`
    variables.
---
 src/tir/ir/transform.cc                            | 11 +++++---
 .../python/unittest/test_tir_transform_helpers.py  | 30 +++++++++++++++++++++-
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/tir/ir/transform.cc b/src/tir/ir/transform.cc
index 4c59a17673..38ec16ea37 100644
--- a/src/tir/ir/transform.cc
+++ b/src/tir/ir/transform.cc
@@ -88,7 +88,8 @@ PrimFuncPass::PrimFuncPass(
 // Perform Module -> Module optimizations at the PrimFunc level.
 IRModule PrimFuncPassNode::operator()(IRModule mod, const PassContext& 
pass_ctx) const {
   ICHECK(mod.defined());
-  std::vector<ObjectRef> deleted_list;
+  std::vector<GlobalVar> deleted_list;
+
   IRModuleNode* mod_ptr = mod.CopyOnWrite();
   auto* func_dict = mod_ptr->functions.CopyOnWrite();
   // directly loop over the underlying dict
@@ -101,14 +102,16 @@ IRModule PrimFuncPassNode::operator()(IRModule mod, const 
PassContext& pass_ctx)
       kv.second = std::move(func);
 
       if (!kv.second.defined()) {
-        deleted_list.push_back(kv.first);
+        deleted_list.push_back(Downcast<GlobalVar>(kv.first));
       }
     }
   }
 
-  // automatic removal of None
+  // Automatic removal of None.  This uses IRModuleNode::Remove
+  // instead of manipulating func_dict directly, to ensure that both
+  // the function map and the global_var_map_ are correctly updated.
   for (const auto& gv : deleted_list) {
-    func_dict->erase(gv);
+    mod_ptr->Remove(gv);
   }
   return mod;
 }
diff --git a/tests/python/unittest/test_tir_transform_helpers.py 
b/tests/python/unittest/test_tir_transform_helpers.py
index f8dc0f682d..657bda591a 100644
--- a/tests/python/unittest/test_tir_transform_helpers.py
+++ b/tests/python/unittest/test_tir_transform_helpers.py
@@ -17,7 +17,7 @@
 import pytest
 
 import tvm
-from tvm.script import tir as T
+from tvm.script import tir as T, ir as I
 import tvm.testing
 
 
@@ -119,5 +119,33 @@ def test_filter_primfunc():
     assert len(after.functions) == 0
 
 
+class TestFilterRemovesGlobalVarMap(tvm.testing.CompareBeforeAfter):
+    """Filtering out a function should be identical to never adding it
+
+    This test is to guard against hidden state in the IRModule that
+    remains after filtering.  Previously, this was observed in the
+    `IRModuleNode::global_var_map_`, which retained entries of
+    filtered-out functions.
+    """
+
+    transform = tvm.tir.transform.Filter(lambda prim_func: False)
+
+    def before(self):
+        @I.ir_module
+        class module:
+            @T.prim_func
+            def func():
+                T.evaluate(0)
+
+        return module
+
+    def expected(self):
+        @I.ir_module
+        class module:
+            pass
+
+        return module
+
+
 if __name__ == "__main__":
     tvm.testing.main()

Reply via email to