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

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


The following commit(s) were added to refs/heads/unity by this push:
     new d9f3aa32ef [Unity][Analysis] Get symbolic TIR vars from struct info 
(#14509)
d9f3aa32ef is described below

commit d9f3aa32ef974d3078f70f75f987e30258b59882
Author: Ruihang Lai <[email protected]>
AuthorDate: Wed Apr 5 13:41:12 2023 -0400

    [Unity][Analysis] Get symbolic TIR vars from struct info (#14509)
    
    This PR adds an analysis function which helps to fetch all the TIR
    variables that appear in a given struct info object. This is helpful
    for passes that need to be aware of symbolic shape dynamism.
---
 include/tvm/relax/analysis.h                       |  8 ++++
 python/tvm/relax/analysis/analysis.py              | 17 +++++++++
 src/relax/analysis/struct_info_analysis.cc         | 43 ++++++++++++++++++++++
 src/relax/transform/lift_transform_params.cc       | 42 +--------------------
 .../relax/test_analysis_struct_info_analysis.py    | 17 +++++++++
 5 files changed, 86 insertions(+), 41 deletions(-)

diff --git a/include/tvm/relax/analysis.h b/include/tvm/relax/analysis.h
index 21dc5ef420..f38a202d49 100644
--- a/include/tvm/relax/analysis.h
+++ b/include/tvm/relax/analysis.h
@@ -260,6 +260,14 @@ TVM_DLL bool IsBaseOf(const StructInfo& base, const 
StructInfo& derived,
 TVM_DLL StructInfo StructInfoLCA(const StructInfo& lhs, const StructInfo& rhs,
                                  arith::Analyzer* ana = nullptr);
 
+/*!
+ * \brief Get the TIR variables that appear in the input struct info.
+ * The returned list is deduplicated - each TIR variable will appear at most 
once.
+ * \param sinfo The struct info object to be analyzed.
+ * \return The list of TIR variables that appear in the input struct info.
+ */
+TVM_DLL Array<tir::Var> TIRVarsInStructInfo(const StructInfo& sinfo);
+
 //-----------------------------------
 // General IR analysis
 //-----------------------------------
diff --git a/python/tvm/relax/analysis/analysis.py 
b/python/tvm/relax/analysis/analysis.py
index 2a2c3d87b8..82d1f7a828 100644
--- a/python/tvm/relax/analysis/analysis.py
+++ b/python/tvm/relax/analysis/analysis.py
@@ -167,6 +167,23 @@ def struct_info_lca(lhs: StructInfo, rhs: StructInfo) -> 
StructInfo:
     return _ffi_api.StructInfoLCA(lhs, rhs)  # type: ignore
 
 
+def tir_vars_in_struct_info(sinfo: StructInfo) -> List[tir.Var]:
+    """Get the TIR variables that appear in the input struct info.
+    The returned list is deduplicated - each TIR variable will appear at most 
once.
+
+    Parameters
+    ----------
+    sinfo : StructInfo
+        The struct info object to be analyzed.
+
+    Returns
+    -------
+    ret : List[tir.Var]
+        The list of TIR variables that appear in the input struct info.
+    """
+    return _ffi_api.TIRVarsInStructInfo(sinfo)  # type: ignore
+
+
 def bound_vars(expr: Expr) -> List[Var]:
     """
     Return all bound variables from expression expr.
diff --git a/src/relax/analysis/struct_info_analysis.cc 
b/src/relax/analysis/struct_info_analysis.cc
index 7dfcd60c95..55f58d8511 100644
--- a/src/relax/analysis/struct_info_analysis.cc
+++ b/src/relax/analysis/struct_info_analysis.cc
@@ -26,6 +26,7 @@
 #include <tvm/relax/analysis.h>
 #include <tvm/relax/expr_functor.h>
 #include <tvm/relax/struct_info_functor.h>
+#include <tvm/tir/analysis.h>
 #include <tvm/tir/expr_functor.h>
 
 namespace tvm {
@@ -861,5 +862,47 @@ TVM_REGISTER_GLOBAL("relax.analysis.StructInfoLCA")
       return StructInfoLCA(lhs, rhs);
     });
 
+//--------------------------
+// TIRVarsInStructInfo
+//--------------------------
+
+Array<tir::Var> TIRVarsInStructInfo(const StructInfo& sinfo) {
+  struct TIRVarsDetector : public StructInfoVisitor {
+    void VisitShape(Array<PrimExpr> shape) {
+      for (const PrimExpr& value : shape) {
+        Array<tir::Var> vars = tir::UndefinedVars(value);
+        for (const tir::Var& var : vars) {
+          auto insert_res = tir_vars_dedup_set.insert(var.get());
+          if (insert_res.second) {
+            tir_vars.push_back(var);
+          }
+        }
+      }
+    }
+
+    void VisitStructInfo_(const ShapeStructInfoNode* shape_sinfo) final {
+      if (shape_sinfo->values.defined()) {
+        VisitShape(shape_sinfo->values.value());
+      }
+    }
+
+    void VisitStructInfo_(const TensorStructInfoNode* tensor_sinfo) final {
+      if (tensor_sinfo->shape.defined()) {
+        VisitStructInfo(GetStructInfo(tensor_sinfo->shape.value()));
+      }
+    }
+
+    Array<tir::Var> tir_vars;
+    std::unordered_set<const tir::VarNode*> tir_vars_dedup_set;
+  };
+
+  TIRVarsDetector detector;
+  detector(sinfo);
+  return detector.tir_vars;
+}
+
+TVM_REGISTER_GLOBAL("relax.analysis.TIRVarsInStructInfo")
+    .set_body_typed([](const StructInfo& sinfo) { return 
TIRVarsInStructInfo(sinfo); });
+
 }  // namespace relax
 }  // namespace tvm
diff --git a/src/relax/transform/lift_transform_params.cc 
b/src/relax/transform/lift_transform_params.cc
index e0296e6ae5..cbeedb6694 100644
--- a/src/relax/transform/lift_transform_params.cc
+++ b/src/relax/transform/lift_transform_params.cc
@@ -132,46 +132,6 @@ class TransformParamsFuncBuilder : public ExprMutator {
   std::unordered_set<Var, ObjectPtrHash, ObjectPtrEqual> outputs_;
 };
 
-bool SInfoContainsSymVar(StructInfo sinfo) {
-  struct SymVarDetector : public StructInfoVisitor {
-    void VisitStructInfo(const StructInfo& sinfo) final {
-      if (contains_sym_var) {
-        return;
-      }
-      StructInfoVisitor::VisitStructInfo(sinfo);
-    }
-
-    bool CheckShape(Array<PrimExpr> shape) {
-      for (const PrimExpr& value : shape) {
-        const auto* int_imm = value.as<IntImmNode>();
-        if (int_imm == nullptr) {
-          contains_sym_var = true;
-          return false;
-        }
-      }
-      return true;
-    }
-
-    void VisitStructInfo_(const ShapeStructInfoNode* shape_sinfo) final {
-      if (shape_sinfo->values.defined()) {
-        CheckShape(shape_sinfo->values.value());
-      }
-    }
-
-    void VisitStructInfo_(const TensorStructInfoNode* tensor_sinfo) final {
-      if (tensor_sinfo->shape.defined()) {
-        VisitStructInfo(GetStructInfo(tensor_sinfo->shape.value()));
-      }
-    }
-
-    bool contains_sym_var = false;
-  };
-
-  SymVarDetector detector;
-  detector(sinfo);
-  return detector.contains_sym_var;
-}
-
 /*!
  * \brief Visitor that creates the plan of lifting transform params.
  *
@@ -230,7 +190,7 @@ class LiftTransformParamsPlanner : public ExprVisitor {
     });
 
     // Cond 4. Do not lift when its struct info contains symbolic variables.
-    if (SInfoContainsSymVar(GetStructInfo(binding->var))) {
+    if (!TIRVarsInStructInfo(GetStructInfo(binding->var)).empty()) {
       can_lift = false;
     }
 
diff --git a/tests/python/relax/test_analysis_struct_info_analysis.py 
b/tests/python/relax/test_analysis_struct_info_analysis.py
index 03b98f8a56..62f44d15dd 100644
--- a/tests/python/relax/test_analysis_struct_info_analysis.py
+++ b/tests/python/relax/test_analysis_struct_info_analysis.py
@@ -557,5 +557,22 @@ def test_struct_info_lca():
     _check_lca(fopaque2(), fn_info_shape(1), fopaque2())
 
 
+def test_tir_vars_in_struct_info():
+    n, m = tir.Var("n", "int64"), tir.Var("m", "int64")
+    shape0 = rx.ShapeStructInfo([1, n, 3])
+    shape1 = rx.ShapeStructInfo([1, 2 * n, n, m])
+    tensor0 = rx.TensorStructInfo([1, n, 3], "int32")
+    tensor1 = rx.TensorStructInfo([1, 2 * n, n, m], "int32")
+    func = rx.FuncStructInfo(
+        [rx.TensorStructInfo([1, 2 * n, n, m], "int32")], 
rx.TensorStructInfo([1, n, 3], "int32")
+    )
+
+    
tvm.ir.assert_structural_equal(rx.analysis.tir_vars_in_struct_info(shape0), [n])
+    
tvm.ir.assert_structural_equal(rx.analysis.tir_vars_in_struct_info(shape1), [n, 
m])
+    
tvm.ir.assert_structural_equal(rx.analysis.tir_vars_in_struct_info(tensor0), 
[n])
+    
tvm.ir.assert_structural_equal(rx.analysis.tir_vars_in_struct_info(tensor1), 
[n, m])
+    tvm.ir.assert_structural_equal(rx.analysis.tir_vars_in_struct_info(func), 
[n, m])
+
+
 if __name__ == "__main__":
     tvm.testing.main()

Reply via email to