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-tirx.git


The following commit(s) were added to refs/heads/main by this push:
     new 3b95be67 [REFACTOR] Expose expression patterns and organize analysis 
APIs (#1)
3b95be67 is described below

commit 3b95be6782ff60ef547b3cd5bf052d9a313d5053
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Oct 20 15:25:29 2026 -0400

    [REFACTOR] Expose expression patterns and organize analysis APIs (#1)
    
    Make the existing pattern matcher and inline constant folding reusable
    through public IR headers while preserving their matching and evaluation
    behavior.
    
    - Separate shared captures and pattern composition from primitive
    expression patterns.
    - Move linear-equation and clip-bound detection into TIRx analysis, and
    consolidate bound deduction with integer sets.
    - Expose symbolic infinity accessors backed by private singleton
    storage, and update C++ and Python consumers to their owning APIs.
---
 .github/workflows/main.yml                         |  10 -
 CMakeLists.txt                                     |   2 +-
 docs/reference/python/sym.rst                      |   2 -
 docs/reference/python/tirx.analysis.rst            |   2 +
 include/tvm/ir/pattern_match.h                     | 312 +++++++++++++++++++++
 {src => include/tvm}/ir/prim/const_fold.h          | 104 ++-----
 include/tvm/ir/prim/op.h                           |  28 ++
 {src/sym => include/tvm/ir/prim}/pattern_match.h   | 306 ++------------------
 include/tvm/runtime/base.h                         |   2 +-
 include/tvm/sym/bound.h                            |  53 ----
 include/tvm/sym/int_set.h                          |  18 ++
 include/tvm/sym/pattern.h                          |  55 ----
 include/tvm/tirx/analysis.h                        |  22 ++
 pyproject.toml                                     |   2 +-
 python/tvm_tirx/libinfo.py                         |   2 +-
 python/tvm_tirx/sym/__init__.py                    |   3 +-
 python/tvm_tirx/sym/bound.py                       |  40 ---
 python/tvm_tirx/sym/int_set.py                     |  21 ++
 python/tvm_tirx/sym/pattern.py                     |  61 ----
 python/tvm_tirx/tirx/analysis/analysis.py          |  42 +++
 src/backend/cuda/tile/exec_analysis.cc             |   4 +-
 src/backend/webgpu/codegen/codegen_webgpu.cc       |  10 +-
 src/codegen/c/codegen_c.cc                         |  10 +-
 src/codegen/llvm/codegen_llvm.cc                   |   8 +-
 src/ir/prim/int_operator.h                         |   4 +-
 src/ir/prim/math.cc                                |   2 +-
 src/ir/prim/op.cc                                  |  60 ++--
 src/ir/prim/op_utils.h                             |   4 +-
 src/ir/prim/symbolic_limits.cc                     |  19 +-
 src/sym/analyzer.cc                                |   3 +-
 src/sym/bound_deducer.cc                           |   4 +-
 src/sym/canonical_simplify.cc                      |   2 +-
 src/sym/const_fold.h                               |  16 +-
 src/sym/const_int_bound.cc                         |   2 +-
 src/sym/constraint_extract.cc                      |   3 +-
 src/sym/int_operator.h                             |   8 +-
 src/sym/int_set.cc                                 |  76 ++---
 src/sym/interval_set.h                             |  12 +-
 src/sym/iter_affine_map.cc                         |   4 +-
 src/sym/known_comparison_analyzer.cc               |   2 +-
 src/sym/modular_set.cc                             |   3 +-
 src/sym/rewrite_simplify.cc                        | 147 +++++-----
 src/sym/rewrite_simplify.h                         |   2 +-
 .../analysis/linear_analysis.cc}                   |  16 +-
 src/tirx/ir/tensor.cc                              |   5 +-
 src/tirx/op/math.cc                                |   2 +-
 src/tirx/tile/lower.cc                             |   1 -
 src/tirx/transform/lower_intrin.cc                 |   6 +-
 src/tirx/transform/remove_no_op.cc                 |   3 +-
 src/tirx/transform/renormalize_split_pattern.cc    |   3 +-
 tests/cpp/{sym => ir}/pattern_match_test.cc        |  20 +-
 tests/cpp/sym/domain_map_test.cc                   |   1 -
 .../analysis}/test_detect_clip_bound.py            |  18 +-
 .../analysis}/test_detect_linear_equation.py       |  28 +-
 54 files changed, 757 insertions(+), 838 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index d7bdcdc0..603cfcbe 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -66,7 +66,6 @@ jobs:
         shell: bash -l {0}
         run: |
           set -euxo pipefail
-          export TVM_FFI_VERSION="$(python -c 'from importlib.metadata import 
version; print(version("apache-tvm-ffi"))')"
           pip install psutil cloudpickle ml_dtypes numpy packaging scipy 
typing_extensions
           # --no-deps: this package requires apache-tvm-ffi>=0.1.14.post1, and 
the source-built core
           # versions as 0.1.dev1+g<sha> from the shallow checkout, which is < 
0.1.0 under PEP 440.
@@ -74,15 +73,6 @@ jobs:
           pip install --no-deps "apache-tvm-ffi-orcjit>=0.1.2"
           # Keep the source-matched tvm-ffi installed by the setup steps.
           pip install --no-deps dist/*.whl
-          python - <<'PY'
-          import os
-          from importlib.metadata import requires, version
-
-          assert version("apache-tvm-ffi") == os.environ["TVM_FFI_VERSION"]
-          assert version("apache-tvm-tirx") == "0.1.0a1"
-          assert "apache-tvm-ffi>=0.1.15.post0" in requires("apache-tvm-tirx")
-          assert "apache-tvm-ffi-orcjit>=0.1.2" in requires("apache-tvm-tirx")
-          PY
 
       - name: Test
         shell: bash -l {0}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43746a9b..6e81ddcd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,7 @@ endfunction()
 
 # ######### Common options ##########
 
-set(TVM_TIRX_VERSION "0.1.0a1")
+set(TVM_TIRX_VERSION "0.1.0a2")
 if(PROJECT_IS_TOP_LEVEL)
   tvm_tirx_option(TVM_TIRX_BUILD_TESTS BOOL OFF "Build C++ tests")
   tvm_tirx_option(TVM_TIRX_BUILD_PYTHON_MODULE BOOL OFF "Build the Python 
package with scikit-build-core")
diff --git a/docs/reference/python/sym.rst b/docs/reference/python/sym.rst
index 0f35e9df..703371cd 100644
--- a/docs/reference/python/sym.rst
+++ b/docs/reference/python/sym.rst
@@ -52,8 +52,6 @@ Functions
    estimate_region_upper_bound
    allow_uint_as_index
    deduce_bound
-   detect_linear_equation
-   detect_clip_bound
    detect_iter_map
    iter_map_simplify
    normalize_iter_map_to_expr
diff --git a/docs/reference/python/tirx.analysis.rst 
b/docs/reference/python/tirx.analysis.rst
index fd428c8d..2ea762cb 100644
--- a/docs/reference/python/tirx.analysis.rst
+++ b/docs/reference/python/tirx.analysis.rst
@@ -32,3 +32,5 @@ Functions
    verify_memory
    undefined_vars
    check_well_formed
+   detect_linear_equation
+   detect_clip_bound
diff --git a/include/tvm/ir/pattern_match.h b/include/tvm/ir/pattern_match.h
new file mode 100644
index 00000000..b903dc4d
--- /dev/null
+++ b/include/tvm/ir/pattern_match.h
@@ -0,0 +1,312 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file tvm/ir/pattern_match.h
+ * \brief Shared expression-template pattern and capture protocol.
+ *
+ * \code
+ * #include <tvm/ir/prim/pattern_match.h>
+ *
+ * void MatchMultiplyAdd(const tvm::PrimExpr& expr) {
+ *   tvm::PVar<tvm::PrimExpr> a, b, c;
+ *   if ((a * b + c).Match(expr)) {
+ *     tvm::PrimExpr lhs = a.Eval();
+ *     tvm::PrimExpr rhs = b.Eval();
+ *     tvm::PrimExpr addend = c.Eval();
+ *   }
+ * }
+ * \endcode
+ */
+#ifndef TVM_IR_PATTERN_MATCH_H_
+#define TVM_IR_PATTERN_MATCH_H_
+
+#include <tvm/ffi/cast.h>
+
+#include <optional>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace tvm {
+/*!
+ * \brief Base class of all the patterns.
+ *
+ * There are two major member functions supported by each pattern.
+ * - Match: checks if value matches the pattern.
+ * - Eval: construct a new value based on matched values in PVar.
+ *
+ * We use curiously recurring template pattern to construct
+ * expression templates.
+ *
+ * \tparam Derived The type of the derived class.
+ */
+template <typename Derived>
+class Pattern {
+ public:
+  /*!
+   * \brief Nested storage type in the expression.
+   *
+   *  Depending on the Derived class,
+   *  Nested can be Derived (nest by value) or
+   *  const Derived& (nest by reference).
+   *
+   *  The trick of Nested typedef originates from Eigen.
+   *
+   * \note We use nest by value for intermediate expressions,
+   *       and nest by reference for PVars.
+   */
+  using Nested = Derived;
+
+  /*!
+   * \brief Check if value matches the current pattern.
+   *
+   * This call also populates the PVars with matched value.
+   * The values in PVars are valid until the next call to Match.
+   *
+   * \param value The value to be matched against
+   *
+   * \return whether value matches the pattern.
+   */
+  template <typename NodeType>
+  inline bool Match(const NodeType& value) const {
+    return Match(value, []() { return true; });
+  }
+
+  /*!
+   * \brief Check if value matches the current pattern.
+   *
+   * This call also populates the PVars with matched value.
+   * The values in PVars are valid until the next call to Match.
+   *
+   * \param value The value to be matched against
+   *
+   * \param cond A callable that performs additional validation,
+   * returning true if the match passes.  This will typically be a
+   * lambda function written in terms of the filled PVars.
+   *
+   * \return whether value matches the pattern.
+   */
+  template <typename NodeType, typename Condition>
+  bool Match(const NodeType& value, Condition cond) const {
+    derived().InitMatch_();
+    return derived().Match_(value) && cond();
+  }
+  /*! \return Derived instance of current class. */
+  const Derived& derived() const { return *static_cast<const Derived*>(this); }
+};
+
+/*!
+ * \brief Default deep equality checker
+ * \tparam T the comparison point.
+ */
+template <typename T>
+class PEqualChecker {
+ public:
+  bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }
+};
+
+/*!
+ * \brief Pattern variable container.
+ *
+ * PVar is used as a "hole" in the pattern that can be matched.
+ *
+ * \tparam T the type of the hole.
+ *
+ * \note PVar is not thread safe.
+ *       Do not use the same PVar in multiple threads.
+ */
+template <typename T>
+class PVar : public Pattern<PVar<T>> {
+ public:
+  // Store PVars by reference in the expression.
+  using Nested = const PVar<T>&;
+
+  void InitMatch_() const { value_.reset(); }
+
+  bool Match_(const T& value) const {
+    if (!value_) {
+      value_ = value;
+      return true;
+    } else {
+      return PEqualChecker<T>()(*value_, value);
+    }
+  }
+
+  template <typename NodeRefType, typename = typename std::enable_if<
+                                      !std::is_same<NodeRefType, T>::value &&
+                                      std::is_base_of<ffi::ObjectRef, 
NodeRefType>::value &&
+                                      std::is_base_of<ffi::ObjectRef, 
T>::value>::type>
+  bool Match_(const NodeRefType& value) const {
+    if (auto typed_value = value.template as<T>()) {
+      return Match_(*typed_value);
+    } else {
+      return false;
+    }
+  }
+
+  T Eval() const {
+    TVM_FFI_ICHECK(value_.has_value());
+    return *value_;
+  }
+
+  T EvalOr(const T& default_value) const { return 
value_.value_or(default_value); }
+
+ protected:
+  /*! \brief The matched value */
+  mutable std::optional<T> value_;
+};
+
+/*!
+ * \brief Wrapper for pattern variable container with extra match logic.
+ *
+ * \tparam Derived the type of derived class.
+ * \tparam T the type of the hole.
+ */
+template <typename Derived, typename T>
+class PVarWithCheck : public Pattern<PVarWithCheck<Derived, T>> {
+ public:
+  // Store by reference in the expression.
+  using Nested = const PVarWithCheck<Derived, T>&;
+
+  void InitMatch_() const { pvar_.InitMatch_(); }
+
+  bool Match_(const T& value) const {
+    if (!static_cast<const Derived*>(this)->Match_(value)) return false;
+    return pvar_.Match_(value);
+  }
+
+  template <typename NodeRefType,
+            typename = typename std::enable_if<std::is_base_of<NodeRefType, 
T>::value>::type>
+  bool Match_(const NodeRefType& value) const {
+    if (auto typed_value = value.template as<T>()) {
+      return Match_(*typed_value);
+    } else {
+      return false;
+    }
+  }
+
+  T Eval() const { return pvar_.Eval(); }
+
+ protected:
+  PVar<T> pvar_;
+};
+
+/*!
+ * \brief Constant Pattern variable container.
+ *
+ * \tparam T the type of the hole.
+ */
+template <typename T>
+class PConst : public Pattern<PConst<T>> {
+ public:
+  PConst(T value)  // NOLINT(*)
+      : value_(value) {}
+
+  void InitMatch_() const {}
+
+  bool Match_(const T& value) const { return PEqualChecker<T>()(value_, 
value); }
+
+  T Eval() const { return value_; }
+
+ private:
+  const T value_;
+};
+
+template <typename... TPattern>
+class PMatchesOneOf {
+ public:
+  explicit PMatchesOneOf(const TPattern&... patterns) : patterns_{patterns...} 
{}
+
+  /*! \brief Check if value matches one of the patterns.
+   *
+   * This call also populates the PVars with matched value based on
+   * the first successful match.  The values in PVars are valid until
+   * the next call to Match.
+   *
+   * \param value The value to be matched against.
+   *
+   * \return Whether value matches the pattern.
+   */
+  template <typename NodeType>
+  inline bool Match(const NodeType& value) const {
+    return Match(value, []() { return true; });
+  }
+
+  /*! \brief Check if value matches one of the patterns.
+   *
+   * This call also populates the PVars with matched value based on
+   * the first successful match.  The values in PVars are valid until
+   * the next call to Match.
+   *
+   * \param value The value to be matched against.
+   *
+   * \param cond A callable that performs additional validation,
+   * returning true if the match passes.  This will typically be a
+   * lambda function written in terms of the filled PVars.  This will
+   * be called once for each successful pattern match.  If `cond()`
+   * returns false, the next match will be attempted.
+   *
+   * \return Whether value matches the pattern.
+   */
+  template <typename NodeType, typename Condition>
+  inline bool Match(const NodeType& value, Condition cond) const {
+    return MatchImpl(value, cond, 
std::make_index_sequence<sizeof...(TPattern)>());
+  }
+
+ private:
+  template <typename NodeType, typename Condition>
+  inline bool MatchImpl(const NodeType& value, Condition cond, 
std::index_sequence<>) const {
+    return false;
+  }
+
+  template <typename NodeType, typename Condition, size_t FirstIndex, 
size_t... RemainingIndices>
+  inline bool MatchImpl(const NodeType& value, Condition cond,
+                        std::index_sequence<FirstIndex, RemainingIndices...>) 
const {
+    return std::get<FirstIndex>(patterns_).Match(value, cond) ||
+           MatchImpl(value, cond, std::index_sequence<RemainingIndices...>());
+  }
+
+  // Hold the patterns by const&.  This follows the same usage as both
+  // the `PVar`, which occurs as `const PVar<T>&` when it appears
+  // inside other patterns.  Because the `PVar<T>::value_` field is
+  // mutable, it can still be updated through these const references.
+  // So long as the call to `Match()` occurs within the same
+  // expression as created the patterns, this avoids accidental copies
+  // without creating dangling references.  This may be improved in
+  // the future by use of `constexpr` constructors/operators, allowing
+  // more typical value semantics.
+  std::tuple<const TPattern&...> patterns_;
+};
+
+/* \brief Return a proxy object that returns true after the first match
+ *
+ * In the RewriteSimplifier, there are often several expressions that
+ * simplify to the same resulting expression.  This utility allows
+ * them to be specified as a single rule, reducing duplication of the
+ * result/condition of a rewrite.
+ */
+template <typename... TPattern>
+inline std::enable_if_t<(std::is_base_of_v<Pattern<TPattern>, TPattern> && ... 
&& true),
+                        PMatchesOneOf<TPattern...>>
+MatchesOneOf(const TPattern&... patterns) {
+  return PMatchesOneOf<TPattern...>(patterns...);
+}
+}  // namespace tvm
+#endif  // TVM_IR_PATTERN_MATCH_H_
diff --git a/src/ir/prim/const_fold.h b/include/tvm/ir/prim/const_fold.h
similarity index 81%
rename from src/ir/prim/const_fold.h
rename to include/tvm/ir/prim/const_fold.h
index 0a0f611e..8fcb7c17 100644
--- a/src/ir/prim/const_fold.h
+++ b/include/tvm/ir/prim/const_fold.h
@@ -18,7 +18,7 @@
  */
 
 /*!
- * \file const_fold.h
+ * \file tvm/ir/prim/const_fold.h
  * \brief Centralized location for constant folding.
  */
 #ifndef TVM_IR_PRIM_CONST_FOLD_H_
@@ -32,11 +32,8 @@
 #include <cmath>
 #include <limits>
 
-#include "int_operator.h"
-
 namespace tvm {
 namespace prim {
-namespace detail {
 
 /*!
  * \brief Try to run binary compute with constant folding.
@@ -63,6 +60,8 @@ inline ffi::Optional<PrimExpr> TryConstFold(PrimExpr a, 
PrimExpr b);
 template <typename Op>
 inline ffi::Optional<PrimExpr> TryConstFold(PrimExpr a);
 
+namespace details {
+
 /*!
  * \brief Check whether type is used to represent index.
  *
@@ -128,6 +127,8 @@ inline double GetFoldResultDoubleRepr(float x) {
   return res;
 }
 
+}  // namespace details
+
 #define TVM_PRIM_CONST_PROPAGATION(BODY)         \
   using tvm::FloatImmNode;                       \
   const IntImmNode* pa = a.as<IntImmNode>();     \
@@ -136,11 +137,11 @@ inline double GetFoldResultDoubleRepr(float x) {
   const FloatImmNode* fb = b.as<FloatImmNode>(); \
   BODY;
 
-#define TVM_PRIM_INDEX_CONST_PROPAGATION(BODY)                                 
               \
-  const IntImmNode* pa = a.as<IntImmNode>();                                   
               \
-  const IntImmNode* pb = b.as<IntImmNode>();                                   
               \
-  if (::tvm::prim::detail::IsIndexTypedExpr(a) && 
::tvm::prim::detail::IsIndexTypedExpr(b)) { \
-    BODY;                                                                      
               \
+#define TVM_PRIM_INDEX_CONST_PROPAGATION(BODY)                                 
                 \
+  const IntImmNode* pa = a.as<IntImmNode>();                                   
                 \
+  const IntImmNode* pb = b.as<IntImmNode>();                                   
                 \
+  if (::tvm::prim::details::IsIndexTypedExpr(a) && 
::tvm::prim::details::IsIndexTypedExpr(b)) { \
+    BODY;                                                                      
                 \
   }
 
 // specialization of constant folders.
@@ -150,14 +151,14 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Add>(PrimExpr a, PrimExpr b) {
     PrimType result_ty = a.ty();
     if (pa && pb) {
       ffi::BigInt res = pa->value + pb->value;
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pa && pa->value == 0) return b;
     if (pb && pb->value == 0) return a;
     if (fa && fb) {
       if (result_ty.bits() == 32) {
-        return FloatImm(result_ty, 
GetFoldResultDoubleRepr(static_cast<float>(fa->value) +
-                                                           
static_cast<float>(fb->value)));
+        return FloatImm(result_ty, 
details::GetFoldResultDoubleRepr(static_cast<float>(fa->value) +
+                                                                    
static_cast<float>(fb->value)));
       } else if (result_ty.bits() == 64) {
         return FloatImm(result_ty, fa->value + fb->value);
       }
@@ -180,13 +181,13 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Sub>(PrimExpr a, PrimExpr b) {
     PrimType result_ty = a.ty();
     if (pa && pb) {
       ffi::BigInt res = pa->value - pb->value;
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pb && pb->value == 0) return a;
     if (fa && fb) {
       if (result_ty.bits() == 32) {
-        return FloatImm(result_ty, 
GetFoldResultDoubleRepr(static_cast<float>(fa->value) -
-                                                           
static_cast<float>(fb->value)));
+        return FloatImm(result_ty, 
details::GetFoldResultDoubleRepr(static_cast<float>(fa->value) -
+                                                                    
static_cast<float>(fb->value)));
       } else if (result_ty.bits() == 64) {
         return FloatImm(result_ty, fa->value - fb->value);
       }
@@ -202,7 +203,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Mul>(PrimExpr a, PrimExpr b) {
     PrimType result_ty = a.ty();
     if (pa && pb) {
       ffi::BigInt res = pa->value * pb->value;
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pa) {
       if (pa->value == 1) return b;
@@ -214,8 +215,8 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Mul>(PrimExpr a, PrimExpr b) {
     }
     if (fa && fb) {
       if (result_ty.bits() == 32) {
-        return FloatImm(result_ty, 
GetFoldResultDoubleRepr(static_cast<float>(fa->value) *
-                                                           
static_cast<float>(fb->value)));
+        return FloatImm(result_ty, 
details::GetFoldResultDoubleRepr(static_cast<float>(fa->value) *
+                                                                    
static_cast<float>(fb->value)));
       } else if (result_ty.bits() == 64) {
         return FloatImm(result_ty, fa->value * fb->value);
       }
@@ -241,7 +242,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Div>(PrimExpr a, PrimExpr b) {
       // NOTE: this will assumes truc div.
       TVM_FFI_ICHECK_NE(pb->value, 0) << "Divide by zero";
       ffi::BigInt res = pa->value / pb->value;
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pa) {
       if (pa->value == 0) return a;
@@ -253,8 +254,8 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Div>(PrimExpr a, PrimExpr b) {
     if (fa && fb) {
       TVM_FFI_ICHECK_NE(fb->value, 0) << "Divide by zero";
       if (result_ty.bits() == 32) {
-        return FloatImm(result_ty, 
GetFoldResultDoubleRepr(static_cast<float>(fa->value) /
-                                                           
static_cast<float>(fb->value)));
+        return FloatImm(result_ty, 
details::GetFoldResultDoubleRepr(static_cast<float>(fa->value) /
+                                                                    
static_cast<float>(fb->value)));
       } else if (result_ty.bits() == 64) {
         return FloatImm(result_ty, fa->value / fb->value);
       }
@@ -275,7 +276,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Mod>(PrimExpr a, PrimExpr b) {
     if (pa && pb) {
       TVM_FFI_ICHECK_NE(pb->value, 0) << "Divide by zero";
       ffi::BigInt res = pa->value % pb->value;
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pa) {
       if (pa->value == 0) return a;
@@ -288,7 +289,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Mod>(PrimExpr a, PrimExpr b) {
   // Fold wide literals without enabling symbolic index rewrites for their 
type.
   if (pa && pb && a.ty().bits() >= 64) {
     TVM_FFI_ICHECK_NE(pb->value, 0) << "Divide by zero";
-    return IntImm(a.ty(), GetFoldResult(pa->value % pb->value, a.ty()));
+    return IntImm(a.ty(), details::GetFoldResult(pa->value % pb->value, 
a.ty()));
   }
   return std::nullopt;
 }
@@ -300,7 +301,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::FloorDiv>(PrimExpr a, PrimExpr
     if (pa && pb) {
       TVM_FFI_ICHECK_NE(pb->value, 0) << "Divide by zero";
       ffi::BigInt res = ffi::floordiv(pa->value, pb->value);
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pa) {
       if (pa->value == 0) return a;
@@ -311,9 +312,9 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::FloorDiv>(PrimExpr a, PrimExpr
     }
     if (fa && fb && fb->value != 0) {
       if (result_ty.bits() == 32) {
-        return FloatImm(result_ty,
-                        
GetFoldResultDoubleRepr(std::floor(static_cast<float>(fa->value) /
-                                                           
static_cast<float>(fb->value))));
+        return FloatImm(
+            result_ty, 
details::GetFoldResultDoubleRepr(std::floor(static_cast<float>(fa->value) /
+                                                                   
static_cast<float>(fb->value))));
       } else if (result_ty.bits() == 64) {
         return FloatImm(result_ty, std::floor(fa->value / fb->value));
       } else {
@@ -336,7 +337,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::FloorMod>(PrimExpr a, PrimExpr
     if (pa && pb) {
       TVM_FFI_ICHECK_NE(pb->value, 0) << "Divide by zero";
       ffi::BigInt res = ffi::floormod(pa->value, pb->value);
-      return IntImm(result_ty, GetFoldResult(res, result_ty));
+      return IntImm(result_ty, details::GetFoldResult(res, result_ty));
     }
     if (pa) {
       if (pa->value == 0) return a;
@@ -349,7 +350,7 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::FloorMod>(PrimExpr a, PrimExpr
   // Fold wide literals without enabling symbolic index rewrites for their 
type.
   if (pa && pb && (a.ty().bits() >= 64 || 
a.ty().MatchesCode(DLDataTypeCode::kDLUInt))) {
     TVM_FFI_ICHECK_NE(pb->value, 0) << "Divide by zero";
-    return IntImm(a.ty(), GetFoldResult(ffi::floormod(pa->value, pb->value), 
a.ty()));
+    return IntImm(a.ty(), details::GetFoldResult(ffi::floormod(pa->value, 
pb->value), a.ty()));
   }
   return std::nullopt;
 }
@@ -461,51 +462,6 @@ inline ffi::Optional<PrimExpr> 
TryConstFold<prim::Not>(PrimExpr a) {
   return std::nullopt;
 }
 
-/*! \brief Shared symbolic value limits used by primitive folding and integer 
analysis. */
-struct SymbolicLimits {
-  /*! \brief positive infinity */
-  static PrimExpr pos_inf_;
-  /*! \brief negative infinity */
-  static PrimExpr neg_inf_;
-};
-
-/*!
- * \brief Opaque expression representing positive infinity.
- *
- *  It can only be used as parameter of by min/max
- *  for integer analysis and cannot be used in normal expressions.
- *
- * \return positive infinity.
- */
-inline PrimExpr pos_inf() { return SymbolicLimits::pos_inf_; }
-
-/*!
- * \brief Check if value is positive infinity.
- * \param value The value to be checked.
- *
- * \return The check result.
- */
-inline bool is_pos_inf(const PrimExpr& value) { return 
value.same_as(SymbolicLimits::pos_inf_); }
-
-/*!
- * \brief Opaque expression representing negative infinity.
- *
- *  It can only be used as parameter of by min/max
- *  for integer analysis and cannot be used in normal expressions.
- *
- * \return negative infinity.
- */
-inline PrimExpr neg_inf() { return SymbolicLimits::neg_inf_; }
-
-/*!
- * \brief Check if value is negative infinity.
- * \param value The value to be checked.
- *
- * \return The check result.
- */
-inline bool is_neg_inf(const PrimExpr& value) { return 
value.same_as(SymbolicLimits::neg_inf_); }
-
-}  // namespace detail
 }  // namespace prim
 }  // namespace tvm
 #endif  // TVM_IR_PRIM_CONST_FOLD_H_
diff --git a/include/tvm/ir/prim/op.h b/include/tvm/ir/prim/op.h
index f1eca89c..ff8563f7 100644
--- a/include/tvm/ir/prim/op.h
+++ b/include/tvm/ir/prim/op.h
@@ -265,6 +265,34 @@ inline PrimExpr operator*=(PrimExpr& a, PrimExpr b) {
 
 namespace prim {
 
+/*!
+ * \brief Symbolic positive infinity for unbounded integer intervals.
+ * \note This sentinel is not IEEE infinity and cannot be used in normal 
expressions.
+ * \return The positive infinity sentinel with stable identity and lifetime.
+ */
+TVM_TIRX_DLL const PrimExpr& pos_inf();
+
+/*!
+ * \brief Symbolic negative infinity for unbounded integer intervals.
+ * \note This sentinel is not IEEE infinity and cannot be used in normal 
expressions.
+ * \return The negative infinity sentinel with stable identity and lifetime.
+ */
+TVM_TIRX_DLL const PrimExpr& neg_inf();
+
+/*!
+ * \brief Check whether a value is the symbolic positive infinity sentinel.
+ * \param value The value to check.
+ * \return Whether the value has the sentinel's identity.
+ */
+TVM_TIRX_DLL bool is_pos_inf(const PrimExpr& value);
+
+/*!
+ * \brief Check whether a value is the symbolic negative infinity sentinel.
+ * \param value The value to check.
+ * \return Whether the value has the sentinel's identity.
+ */
+TVM_TIRX_DLL bool is_neg_inf(const PrimExpr& value);
+
 /*!
  * \brief Get the target's vscale value. It will be lowered to llvm.vscale 
intrinsic
  * (https://llvm.org/docs/LangRef.html#llvm-vscale-intrinsic)
diff --git a/src/sym/pattern_match.h b/include/tvm/ir/prim/pattern_match.h
similarity index 69%
rename from src/sym/pattern_match.h
rename to include/tvm/ir/prim/pattern_match.h
index 4457461f..62506abb 100644
--- a/src/sym/pattern_match.h
+++ b/include/tvm/ir/prim/pattern_match.h
@@ -18,9 +18,9 @@
  */
 
 /*!
- * \file tvm/arithmetic/pattern_match.h
+ * \file tvm/ir/prim/pattern_match.h
  *
- * \brief Internal tool for expression-template based pattern matching.
+ * \brief Public tool for expression-template based pattern matching.
  *
  * It helps to simplify pattern matching and rewrites.
  * All the patterns are generated via expression template during compile time,
@@ -31,7 +31,7 @@
  * \code
  *
  *  // max(x + z, y + z) => max(x, y) + z
- *  sym::PVar<Expr> x, y, z;
+ *  tvm::PVar<PrimExpr> x, y, z;
  *
  *  // The following code tries to match the declared pattern.
  *  // Match will fill the result of match into PVar if successful.
@@ -44,9 +44,9 @@
  *    return (max(x, y) + z).Eval();
  *  }
  *
- *  tvm::Var tx, ty;
- *  sym::PVar<IntImm> c;
- *  sym::PVar<Var> v;
+ *  tvm::PrimVar tx("tx"), ty("ty");
+ *  tvm::PVar<IntImm> c;
+ *  tvm::PVar<Var> v;
  *  // We can match integer and Var, both of which are
  *  // special case container of Expr
  *  TVM_FFI_ICHECK((v * c).Match(tx * 3));
@@ -62,97 +62,18 @@
  *       Please be aware that the filled value in a PVar
  *       can be overriden in the next call to Match.
  */
-#ifndef TVM_SYM_PATTERN_MATCH_H_
-#define TVM_SYM_PATTERN_MATCH_H_
+#ifndef TVM_IR_PRIM_PATTERN_MATCH_H_
+#define TVM_IR_PRIM_PATTERN_MATCH_H_
 
-#include <tvm/ffi/cast.h>
+#include <tvm/ir/pattern_match.h>
+#include <tvm/ir/prim/const_fold.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
 
 #include <cmath>
 #include <tuple>
 
-#include "const_fold.h"
-
 namespace tvm {
-namespace sym {
-/*!
- * \brief Base class of all the patterns.
- *
- * There are two major member functions supported by each pattern.
- * - Match: checks if value matches the pattern.
- * - Eval: construct a new value based on matched values in PVar.
- *
- * We use curiously recurring template pattern to construct
- * expression templates.
- *
- * \tparam Derived The type of the derived class.
- */
-template <typename Derived>
-class Pattern {
- public:
-  /*!
-   * \brief Nested storage type in the expression.
-   *
-   *  Depending on the Derived class,
-   *  Nested can be Derived (nest by value) or
-   *  const Derived& (nest by reference).
-   *
-   *  The trick of Nested typedef originates from Eigen.
-   *
-   * \note We use nest by value for intermediate expressions,
-   *       and nest by reference for PVars.
-   */
-  using Nested = Derived;
-
-  /*!
-   * \brief Check if value matches the current pattern.
-   *
-   * This call also populates the PVars with matched value.
-   * The values in PVars are valid until the next call to Match.
-   *
-   * \param value The value to be matched against
-   *
-   * \return whether value matches the pattern.
-   */
-  template <typename NodeType>
-  inline bool Match(const NodeType& value) const {
-    return Match(value, []() { return true; });
-  }
-
-  /*!
-   * \brief Check if value matches the current pattern.
-   *
-   * This call also populates the PVars with matched value.
-   * The values in PVars are valid until the next call to Match.
-   *
-   * \param value The value to be matched against
-   *
-   * \param cond A callable that performs additional validation,
-   * returning true if the match passes.  This will typically be a
-   * lambda function written in terms of the filled PVars.
-   *
-   * \return whether value matches the pattern.
-   */
-  template <typename NodeType, typename Condition>
-  bool Match(const NodeType& value, Condition cond) const {
-    derived().InitMatch_();
-    return derived().Match_(value) && cond();
-  }
-  /*! \return Derived instance of current class. */
-  const Derived& derived() const { return *static_cast<const Derived*>(this); }
-};
-
-/*!
- * \brief Default deep equality checker
- * \tparam T the comparison point.
- */
-template <typename T>
-class PEqualChecker {
- public:
-  bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }
-};
-
 template <>
 class PEqualChecker<PrimExpr> {
  public:
@@ -182,92 +103,6 @@ class PEqualChecker<Var> {
   bool operator()(const Var& lhs, const Var& rhs) const { return 
lhs.same_as(rhs); }
 };
 
-/*!
- * \brief Pattern variable container.
- *
- * PVar is used as a "hole" in the pattern that can be matched.
- *
- * \tparam T the type of the hole.
- *
- * \note PVar is not thread safe.
- *       Do not use the same PVar in multiple threads.
- */
-template <typename T>
-class PVar : public Pattern<PVar<T>> {
- public:
-  // Store PVars by reference in the expression.
-  using Nested = const PVar<T>&;
-
-  void InitMatch_() const { value_.reset(); }
-
-  bool Match_(const T& value) const {
-    if (!value_) {
-      value_ = value;
-      return true;
-    } else {
-      return PEqualChecker<T>()(*value_, value);
-    }
-  }
-
-  template <typename NodeRefType, typename = typename std::enable_if<
-                                      !std::is_same<NodeRefType, T>::value &&
-                                      std::is_base_of<ffi::ObjectRef, 
NodeRefType>::value &&
-                                      std::is_base_of<ffi::ObjectRef, 
T>::value>::type>
-  bool Match_(const NodeRefType& value) const {
-    if (auto typed_value = value.template as<T>()) {
-      return Match_(*typed_value);
-    } else {
-      return false;
-    }
-  }
-
-  T Eval() const {
-    TVM_FFI_ICHECK(value_.has_value());
-    return *value_;
-  }
-
-  T EvalOr(const T& default_value) const { return 
value_.value_or(default_value); }
-
- protected:
-  /*! \brief The matched value */
-  mutable std::optional<T> value_;
-};
-
-/*!
- * \brief Wrapper for pattern variable container with extra match logic.
- *
- * \tparam Derived the type of derived class.
- * \tparam T the type of the hole.
- */
-template <typename Derived, typename T>
-class PVarWithCheck : public sym::Pattern<PVarWithCheck<Derived, T>> {
- public:
-  // Store by reference in the expression.
-  using Nested = const PVarWithCheck<Derived, T>&;
-
-  void InitMatch_() const { pvar_.InitMatch_(); }
-
-  bool Match_(const T& value) const {
-    if (!static_cast<const Derived*>(this)->Match_(value)) return false;
-    return pvar_.Match_(value);
-  }
-
-  template <typename NodeRefType,
-            typename = typename std::enable_if<std::is_base_of<NodeRefType, 
T>::value>::type>
-  bool Match_(const NodeRefType& value) const {
-    if (auto typed_value = value.template as<T>()) {
-      return Match_(*typed_value);
-    } else {
-      return false;
-    }
-  }
-
-  T Eval() const { return pvar_.Eval(); }
-
- protected:
-  sym::PVar<T> pvar_;
-};
-
 /*!
  * \brief Pattern variable container with expr type check.
  *
@@ -300,27 +135,6 @@ class PVecDataType : public PVarWithCheck<PVecDataType, 
DLDataType> {
   DLDataType elem_dtype_;
 };
 
-/*!
- * \brief Constant Pattern variable container.
- *
- * \tparam T the type of the hole.
- */
-template <typename T>
-class PConst : public Pattern<PConst<T>> {
- public:
-  PConst(T value)  // NOLINT(*)
-      : value_(value) {}
-
-  void InitMatch_() const {}
-
-  bool Match_(const T& value) const { return PEqualChecker<T>()(value_, 
value); }
-
-  T Eval() const { return value_; }
-
- private:
-  const T value_;
-};
-
 /*!
  * \brief Pattern binary expression.
  * \tparam OpType The AST noderef type.
@@ -353,7 +167,7 @@ class PBinaryExpr : public Pattern<PBinaryExpr<OpType, TA, 
TB, kFoldConstants>>
     PrimExpr lhs = a_.Eval();
     PrimExpr rhs = b_.Eval();
     if constexpr (kFoldConstants) {
-      if (auto ret = TryConstFold<OpType>(lhs, rhs)) return ret.value();
+      if (auto ret = prim::TryConstFold<OpType>(lhs, rhs)) return ret.value();
     }
     return OpType(lhs, rhs);
   }
@@ -734,7 +548,7 @@ inline PBroadcastExpr<TA, TLanes> broadcast(const 
Pattern<TA>& value,
 }
 
 // internal namespace
-namespace detail {
+namespace details {
 // implementation details for  CallExpr
 template <bool stop, std::size_t I, typename F>
 struct tuple_for_each_dispatcher {
@@ -783,7 +597,7 @@ struct PCallExprEvalArgsFunctor {
     args_.push_back(pattern.Eval());
   }
 };
-}  // namespace detail
+}  // namespace details
 
 /*!
  * \brief Pattern CallExpr expression.
@@ -798,16 +612,16 @@ class PCallExpr : public Pattern<PCallExpr<Op, TArgs...>> 
{
   explicit PCallExpr(const TArgs&... args) : args_(args...) {}
 
   void InitMatch_() const {
-    detail::PCallExprInitMatchFunctor finit;
-    detail::tuple_for_each(finit, args_);
+    details::PCallExprInitMatchFunctor finit;
+    details::tuple_for_each(finit, args_);
   }
 
   bool Match_(const ffi::ObjectRef& node) const {
     if (const CallNode* ptr = node.as<CallNode>()) {
       if (ptr->args.size() != sizeof...(TArgs)) return false;
       if (!ptr->op.same_as(Op::GetOp())) return false;
-      detail::PCallExprMatchFunctor fmatch(ptr);
-      detail::tuple_for_each(fmatch, args_);
+      details::PCallExprMatchFunctor fmatch(ptr);
+      details::tuple_for_each(fmatch, args_);
       return fmatch.matched_;
     } else {
       return false;
@@ -815,8 +629,8 @@ class PCallExpr : public Pattern<PCallExpr<Op, TArgs...>> {
   }
 
   PrimExpr Eval() const {
-    detail::PCallExprEvalArgsFunctor feval_args;
-    detail::tuple_for_each(feval_args, args_);
+    details::PCallExprEvalArgsFunctor feval_args;
+    details::tuple_for_each(feval_args, args_);
     return Op::Eval(feval_args.args_);
   }
 
@@ -853,85 +667,5 @@ inline PCallExpr<PIfThenElseOp, TCond, TA, TB> 
if_then_else(const Pattern<TCond>
                                                  false_value.derived());
 }
 
-template <typename... TPattern>
-class PMatchesOneOf {
- public:
-  explicit PMatchesOneOf(const TPattern&... patterns) : patterns_{patterns...} 
{}
-
-  /*! \brief Check if value matches one of the patterns.
-   *
-   * This call also populates the PVars with matched value based on
-   * the first successful match.  The values in PVars are valid until
-   * the next call to Match.
-   *
-   * \param value The value to be matched against.
-   *
-   * \return Whether value matches the pattern.
-   */
-  template <typename NodeType>
-  inline bool Match(const NodeType& value) const {
-    return Match(value, []() { return true; });
-  }
-
-  /*! \brief Check if value matches one of the patterns.
-   *
-   * This call also populates the PVars with matched value based on
-   * the first successful match.  The values in PVars are valid until
-   * the next call to Match.
-   *
-   * \param value The value to be matched against.
-   *
-   * \param cond A callable that performs additional validation,
-   * returning true if the match passes.  This will typically be a
-   * lambda function written in terms of the filled PVars.  This will
-   * be called once for each successful pattern match.  If `cond()`
-   * returns false, the next match will be attempted.
-   *
-   * \return Whether value matches the pattern.
-   */
-  template <typename NodeType, typename Condition>
-  inline bool Match(const NodeType& value, Condition cond) const {
-    return MatchImpl(value, cond, 
std::make_index_sequence<sizeof...(TPattern)>());
-  }
-
- private:
-  template <typename NodeType, typename Condition>
-  inline bool MatchImpl(const NodeType& value, Condition cond, 
std::index_sequence<>) const {
-    return false;
-  }
-
-  template <typename NodeType, typename Condition, size_t FirstIndex, 
size_t... RemainingIndices>
-  inline bool MatchImpl(const NodeType& value, Condition cond,
-                        std::index_sequence<FirstIndex, RemainingIndices...>) 
const {
-    return std::get<FirstIndex>(patterns_).Match(value, cond) ||
-           MatchImpl(value, cond, std::index_sequence<RemainingIndices...>());
-  }
-
-  // Hold the patterns by const&.  This follows the same usage as both
-  // the `PVar`, which occurs as `const PVar<T>&` when it appears
-  // inside other patterns.  Because the `PVar<T>::value_` field is
-  // mutable, it can still be updated through these const references.
-  // So long as the call to `Match()` occurs within the same
-  // expression as created the patterns, this avoids accidental copies
-  // without creating dangling references.  This may be improved in
-  // the future by use of `constexpr` constructors/operators, allowing
-  // more typical value semantics.
-  std::tuple<const TPattern&...> patterns_;
-};
-
-/* \brief Return a proxy object that returns true after the first match
- *
- * In the RewriteSimplifier, there are often several expressions that
- * simplify to the same resulting expression.  This utility allows
- * them to be specified as a single rule, reducing duplication of the
- * result/condition of a rewrite.
- */
-template <typename... TPattern>
-inline std::enable_if_t<(std::is_base_of_v<Pattern<TPattern>, TPattern> && ... 
&& true),
-                        PMatchesOneOf<TPattern...>>
-matches_one_of(const TPattern&... patterns) {
-  return PMatchesOneOf<TPattern...>(patterns...);
-}
-}  // namespace sym
 }  // namespace tvm
-#endif  // TVM_SYM_PATTERN_MATCH_H_
+#endif  // TVM_IR_PRIM_PATTERN_MATCH_H_
diff --git a/include/tvm/runtime/base.h b/include/tvm/runtime/base.h
index 95d75e28..4e79fff6 100644
--- a/include/tvm/runtime/base.h
+++ b/include/tvm/runtime/base.h
@@ -32,7 +32,7 @@
 // passes the setuptools_scm-resolved version through CMake). The literal 
below is the
 // fallback for a bare build with no override.
 #ifndef TVM_TIRX_VERSION
-#define TVM_TIRX_VERSION "0.1.0a1"
+#define TVM_TIRX_VERSION "0.1.0a2"
 #endif
 
 // Core runtime visibility is independent of TIRx compiler visibility.
diff --git a/include/tvm/sym/bound.h b/include/tvm/sym/bound.h
deleted file mode 100644
index 5bee6ddd..00000000
--- a/include/tvm/sym/bound.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/*!
- * \file tvm/sym/bound.h
- * \brief Bound deducers.
- */
-#ifndef TVM_SYM_BOUND_H_
-#define TVM_SYM_BOUND_H_
-
-#include <tvm/ir/expr.h>
-#include <tvm/ir/prim/expr.h>
-#include <tvm/sym/int_set.h>
-
-namespace tvm {
-namespace sym {
-
-/*!
- * \brief Deduce the bound of the target variable in an expression,
- *  given the domain of each variable. Return IntSet::Nothing() to
- *  represent failure.
- *
- * \note The returned set may be smaller than set that
- *       contains all possible values of v that satisfies the bound.
- *
- * \param v The target variable to be deduced.
- * \param cond The conditional expression.
- * \param hint_map The domain of variable, used to help deduce.
- * \param relax_map The domain of each variable, used to relax the domain,
- *        The deduce bound must imply e for all value in relax_map
- * \return An integer set that always satisfies the condition.
- */
-TVM_TIRX_DLL IntSet DeduceBound(PrimExpr v, PrimExpr cond, const ffi::Map<Var, 
IntSet>& hint_map,
-                                const ffi::Map<Var, IntSet>& relax_map);
-
-}  // namespace sym
-}  // namespace tvm
-#endif  // TVM_SYM_BOUND_H_
diff --git a/include/tvm/sym/int_set.h b/include/tvm/sym/int_set.h
index c71307c4..c0fd55bf 100644
--- a/include/tvm/sym/int_set.h
+++ b/include/tvm/sym/int_set.h
@@ -303,6 +303,24 @@ TVM_TIRX_DLL ffi::Array<IntSet> 
EstimateRegionUpperBound(const ffi::Array<Range>
                                                          const PrimExpr& 
predicate,
                                                          const sym::Analyzer& 
analyzer);
 
+/*!
+ * \brief Deduce the bound of the target variable in an expression,
+ *  given the domain of each variable. Return IntSet::Nothing() to
+ *  represent failure.
+ *
+ * \note The returned set may be smaller than set that
+ *       contains all possible values of v that satisfies the bound.
+ *
+ * \param v The target variable to be deduced.
+ * \param cond The conditional expression.
+ * \param hint_map The domain of variable, used to help deduce.
+ * \param relax_map The domain of each variable, used to relax the domain,
+ *        The deduce bound must imply e for all value in relax_map
+ * \return An integer set that always satisfies the condition.
+ */
+TVM_TIRX_DLL IntSet DeduceBound(PrimExpr v, PrimExpr cond, const ffi::Map<Var, 
IntSet>& hint_map,
+                                const ffi::Map<Var, IntSet>& relax_map);
+
 }  // namespace sym
 }  // namespace tvm
 #endif  // TVM_SYM_INT_SET_H_
diff --git a/include/tvm/sym/pattern.h b/include/tvm/sym/pattern.h
deleted file mode 100644
index 42fc25c8..00000000
--- a/include/tvm/sym/pattern.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file tvm/sym/pattern.h
- * \brief Expression pattern detectors.
- */
-#ifndef TVM_SYM_PATTERN_H_
-#define TVM_SYM_PATTERN_H_
-
-#include <tvm/ir/expr.h>
-
-namespace tvm {
-namespace sym {
-/*!
- * \brief Detect if e can be rewritten as e = sum_{i=0}^{n-1} var[i] * 
coeff[i] + coeff[n]
- *  Where coeff[i] and base are invariant of var[j] for all i and j.
- *
- * \param e The expression to be detected.
- * \param vars List of variables to be used in detection.
- * \return [coeff[i]] if it is possible, empty array if it is not.
- */
-TVM_TIRX_DLL ffi::Array<PrimExpr> DetectLinearEquation(const PrimExpr& e,
-                                                       const 
ffi::Array<PrimVar>& vars);
-
-/*!
- * \brief Detect if expression corresponds to clip bound of the vars
- *
- * \param e The expression to be detected.
- * \param vars List of variables to be used in detection.
- * \return concat([min_value[i], max_value[i]]), None is returned if there is 
no min or max value
- *          return empty if the e does not match the pattern.
- */
-ffi::Array<ffi::Optional<PrimExpr>> DetectClipBound(const PrimExpr& e,
-                                                    const ffi::Array<PrimVar>& 
vars);
-
-}  // namespace sym
-}  // namespace tvm
-#endif  // TVM_SYM_PATTERN_H_
diff --git a/include/tvm/tirx/analysis.h b/include/tvm/tirx/analysis.h
index fa19ccdc..2d19c902 100644
--- a/include/tvm/tirx/analysis.h
+++ b/include/tvm/tirx/analysis.h
@@ -38,6 +38,28 @@ namespace tvm {
 
 namespace tirx {
 
+/*!
+ * \brief Detect if e can be rewritten as e = sum_{i=0}^{n-1} var[i] * 
coeff[i] + coeff[n]
+ *  Where coeff[i] and base are invariant of var[j] for all i and j.
+ *
+ * \param e The expression to be detected.
+ * \param vars List of variables to be used in detection.
+ * \return [coeff[i]] if it is possible, empty array if it is not.
+ */
+TVM_TIRX_DLL ffi::Array<PrimExpr> DetectLinearEquation(const PrimExpr& e,
+                                                       const 
ffi::Array<PrimVar>& vars);
+
+/*!
+ * \brief Detect if expression corresponds to clip bound of the vars
+ *
+ * \param e The expression to be detected.
+ * \param vars List of variables to be used in detection.
+ * \return concat([min_value[i], max_value[i]]), None is returned if there is 
no min or max value
+ *          return empty if the e does not match the pattern.
+ */
+TVM_TIRX_DLL ffi::Array<ffi::Optional<PrimExpr>> DetectClipBound(const 
PrimExpr& e,
+                                                                 const 
ffi::Array<PrimVar>& vars);
+
 /*!
  * \brief Verify if memory accesses are legal for a specific target device 
type.
  *
diff --git a/pyproject.toml b/pyproject.toml
index efc79d88..22254d49 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,7 +17,7 @@
 
 [project]
 name = "apache-tvm-tirx"
-version = "0.1.0a1"
+version = "0.1.0a2"
 description = "TVM TIRx"
 license = "Apache-2.0"
 license-files = ["LICENSE"]
diff --git a/python/tvm_tirx/libinfo.py b/python/tvm_tirx/libinfo.py
index 8dad587a..cf72e4b4 100644
--- a/python/tvm_tirx/libinfo.py
+++ b/python/tvm_tirx/libinfo.py
@@ -94,7 +94,7 @@ def find_include_path() -> str:
     raise RuntimeError("Cannot find TVM include path.")
 
 
-__version__ = "0.1.0a1"
+__version__ = "0.1.0a2"
 
 
 _LIBRARY_NAMES = ("tvm_tirx_compiler", "tvm_runtime")
diff --git a/python/tvm_tirx/sym/__init__.py b/python/tvm_tirx/sym/__init__.py
index 59274c09..cf1ec6bb 100644
--- a/python/tvm_tirx/sym/__init__.py
+++ b/python/tvm_tirx/sym/__init__.py
@@ -20,6 +20,7 @@
 from .int_set import (
     IntSet,
     IntervalSet,
+    deduce_bound,
     estimate_region_lower_bound,
     estimate_region_strict_bound,
     estimate_region_upper_bound,
@@ -32,8 +33,6 @@ from .analyzer import (
     CompareResult,
     allow_uint_as_index,
 )
-from .bound import deduce_bound
-from .pattern import detect_linear_equation, detect_clip_bound
 from .iter_affine_map import IterMapExpr, IterMark, IterSplitExpr, IterSumExpr
 from .iter_affine_map import (
     detect_iter_map,
diff --git a/python/tvm_tirx/sym/bound.py b/python/tvm_tirx/sym/bound.py
deleted file mode 100644
index f000fa74..00000000
--- a/python/tvm_tirx/sym/bound.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-"""Bound deduction."""
-
-from . import _ffi_api
-
-
-def deduce_bound(var, cond, hint_map, relax_map):
-    """Deduce the bound of the target variable in the cond.
-
-    Parameters
-    ----------
-    var : tvm_tirx.ir.Var
-        The target variable to be deduced.
-
-    cond : Expr
-        The condition
-
-    hint_map : Map[tvm_tirx.ir.Var, IntSet]
-        Domain of variables used to help deduction.
-
-    relax_map : Map[tvm_tirx.ir.Var, IntSet]
-        The domain of the variables to be relaxed
-        using the provided domain.
-    """
-    return _ffi_api.DeduceBound(var, cond, hint_map, relax_map)
diff --git a/python/tvm_tirx/sym/int_set.py b/python/tvm_tirx/sym/int_set.py
index 57b35449..fa96e852 100644
--- a/python/tvm_tirx/sym/int_set.py
+++ b/python/tvm_tirx/sym/int_set.py
@@ -201,3 +201,24 @@ def union_lower_bound(sets):
         An N-dimensional integer set, the lower bound of the union
     """
     return _ffi_api.UnionLowerBound(sets)
+
+
+def deduce_bound(var, cond, hint_map, relax_map):
+    """Deduce the bound of the target variable in the cond.
+
+    Parameters
+    ----------
+    var : tvm_tirx.ir.Var
+        The target variable to be deduced.
+
+    cond : Expr
+        The condition
+
+    hint_map : Map[tvm_tirx.ir.Var, IntSet]
+        Domain of variables used to help deduction.
+
+    relax_map : Map[tvm_tirx.ir.Var, IntSet]
+        The domain of the variables to be relaxed
+        using the provided domain.
+    """
+    return _ffi_api.DeduceBound(var, cond, hint_map, relax_map)
diff --git a/python/tvm_tirx/sym/pattern.py b/python/tvm_tirx/sym/pattern.py
deleted file mode 100644
index 5bec413c..00000000
--- a/python/tvm_tirx/sym/pattern.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-"""Detect bounds, affine forms, and other patterns in symbolic expressions."""
-
-from . import _ffi_api
-
-
-def detect_linear_equation(expr, var_list):
-    """Match `expr = sum_{i=0}^{n-1} var[i] * coeff[i] + coeff[n]`
-
-    Where coeff[i] and base are invariant of var[j] for all i and j.
-
-    Parameters
-    ----------
-    expr : Expr
-        The expression to be matched.
-
-    var_list : List[tvm_tirx.ir.Var]
-        A list of variables.
-
-    Returns
-    -------
-    coeff : List[Expr]
-        A list of co-efficients if the match is successful.
-        An empty list if the match failed.
-    """
-    return _ffi_api.DetectLinearEquation(expr, var_list)
-
-
-def detect_clip_bound(expr, var_list):
-    """Detect if expression corresponds to clip bound of the vars
-
-    Parameters
-    ----------
-    expr : Expr
-        The expression to be matched.
-
-    var_list : List[tvm_tirx.ir.Var]
-        A list of variables.
-
-    Returns
-    -------
-    coeff : List[Expr]
-        `concat([min_value[i], max_value[i]] for i, v in enumerate(var_list))`
-        An empty list if the match failed.
-    """
-    return _ffi_api.DetectClipBound(expr, var_list)
diff --git a/python/tvm_tirx/tirx/analysis/analysis.py 
b/python/tvm_tirx/tirx/analysis/analysis.py
index d0c6d990..18f35f61 100644
--- a/python/tvm_tirx/tirx/analysis/analysis.py
+++ b/python/tvm_tirx/tirx/analysis/analysis.py
@@ -83,3 +83,45 @@ def check_well_formed(obj: Function | IRModule, assert_mode: 
bool = True) -> boo
         If the IR is invalid and assert_mode is True.
     """
     return _ffi_api.CheckWellFormed(obj, assert_mode)  # type: ignore # 
pylint: disable=no-member
+
+
+def detect_linear_equation(expr, var_list):
+    """Match `expr = sum_{i=0}^{n-1} var[i] * coeff[i] + coeff[n]`
+
+    Where coeff[i] and base are invariant of var[j] for all i and j.
+
+    Parameters
+    ----------
+    expr : Expr
+        The expression to be matched.
+
+    var_list : List[tvm_tirx.ir.Var]
+        A list of variables.
+
+    Returns
+    -------
+    coeff : List[Expr]
+        A list of co-efficients if the match is successful.
+        An empty list if the match failed.
+    """
+    return _ffi_api.DetectLinearEquation(expr, var_list)
+
+
+def detect_clip_bound(expr, var_list):
+    """Detect if expression corresponds to clip bound of the vars
+
+    Parameters
+    ----------
+    expr : Expr
+        The expression to be matched.
+
+    var_list : List[tvm_tirx.ir.Var]
+        A list of variables.
+
+    Returns
+    -------
+    coeff : List[Expr]
+        `concat([min_value[i], max_value[i]] for i, v in enumerate(var_list))`
+        An empty list if the match failed.
+    """
+    return _ffi_api.DetectClipBound(expr, var_list)
diff --git a/src/backend/cuda/tile/exec_analysis.cc 
b/src/backend/cuda/tile/exec_analysis.cc
index 66a3b100..d38e17af 100644
--- a/src/backend/cuda/tile/exec_analysis.cc
+++ b/src/backend/cuda/tile/exec_analysis.cc
@@ -25,8 +25,8 @@
 #include <tvm/ir/prim/op.h>
 #include <tvm/runtime/logging.h>
 #include <tvm/sym/analyzer.h>
-#include <tvm/sym/pattern.h>
 #include <tvm/target/target.h>
+#include <tvm/tirx/analysis.h>
 #include <tvm/tirx/function.h>
 #include <tvm/tirx/op/annotation.h>
 #include <tvm/tirx/op/attr.h>
@@ -547,7 +547,7 @@ struct ExecAnalysis::Impl {
                                  int64_t* base) {
     PrimExpr simplified = analyzer_->Simplify(diff);
     for (const auto& [var, candidate] : ScopeIdTargets()) {
-      ffi::Array<PrimExpr> linear = sym::DetectLinearEquation(simplified, 
{var});
+      ffi::Array<PrimExpr> linear = tirx::DetectLinearEquation(simplified, 
{var});
       if (linear.size() != 2) continue;
       int64_t c = 0;
       int64_t b = 0;
diff --git a/src/backend/webgpu/codegen/codegen_webgpu.cc 
b/src/backend/webgpu/codegen/codegen_webgpu.cc
index c4d6f360..e52b305a 100644
--- a/src/backend/webgpu/codegen/codegen_webgpu.cc
+++ b/src/backend/webgpu/codegen/codegen_webgpu.cc
@@ -27,6 +27,7 @@
 #include <tvm/ffi/reflection/registry.h>
 #include <tvm/ir/function.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/runtime/memory_scope.h>
 #include <tvm/support/bytes_io.h>
 #include <tvm/support/gpu_thread_tag.h>
@@ -49,7 +50,6 @@
 
 #include "../../../codegen/build_common.h"
 #include "../../../runtime/metadata.h"
-#include "../../../sym/pattern_match.h"
 #include "webgpu_fallback_module.h"
 
 namespace tvm {
@@ -657,8 +657,8 @@ void CodeGenWebGPU::Dispatch_(const TensorLoadNode* op, 
std::ostream& os) {  //
     TVM_FFI_ICHECK_EQ(element_ty.lanes(), 1) << "Can only vector load scalar 
array";
     TVM_FFI_ICHECK(value_ty.WithLanes(1) == element_ty)
         << "WebGPU vector loading requires base type to match";
-    sym::PVar<PrimExpr> base;
-    if (sym::ramp(base, 1, value_ty.lanes()).Match(index)) {
+    tvm::PVar<PrimExpr> base;
+    if (tvm::ramp(base, 1, value_ty.lanes()).Match(index)) {
       // vec3<f32>(buf[base + 0], buf[base + 1], buf[base + 2]);
       std::string base_vid = SSAGetID(PrintExpr(base.Eval()), 
base.Eval().ty());
       PrintType(element_ty.WithLanes(value_ty.lanes()), os);
@@ -743,8 +743,8 @@ void CodeGenWebGPU::Dispatch_(const TensorStoreNode* op) {
     TVM_FFI_ICHECK(value_ty.WithLanes(1) == element_ty)
         << "WebGPU vector stire requires base type to match";
     std::string value_vid = PrintExpr(op->value);
-    sym::PVar<PrimExpr> base;
-    if (sym::ramp(base, 1, value_ty.lanes()).Match(index)) {
+    tvm::PVar<PrimExpr> base;
+    if (tvm::ramp(base, 1, value_ty.lanes()).Match(index)) {
       // buf[base + 0] = value[0]
       // buf[base + 1] = value[1]
       std::string base_vid = SSAGetID(PrintExpr(base.Eval()), 
base.Eval().ty());
diff --git a/src/codegen/c/codegen_c.cc b/src/codegen/c/codegen_c.cc
index 27843901..dbb603a4 100644
--- a/src/codegen/c/codegen_c.cc
+++ b/src/codegen/c/codegen_c.cc
@@ -26,6 +26,7 @@
 #include <tvm/ffi/extra/structural_equal.h>
 #include <tvm/ir/function.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/ir/unique_name_supply.h>
 #include <tvm/runtime/memory_scope.h>
 #include <tvm/sym/analyzer.h>
@@ -41,7 +42,6 @@
 #include <iomanip>
 #include <limits>
 
-#include "../../sym/pattern_match.h"
 #include "codegen_params.h"
 
 namespace tvm {
@@ -1016,8 +1016,8 @@ void CodeGenC::Dispatch_(const TensorLoadNode* op, 
std::ostream& os) {  // NOLIN
     }
   } else {
     bool can_vector_load = false;
-    sym::PVar<PrimExpr> base;
-    if (sym::ramp(base, 1, value_ty.lanes()).Match(index)) {
+    tvm::PVar<PrimExpr> base;
+    if (tvm::ramp(base, 1, value_ty.lanes()).Match(index)) {
       const prim::RampNode* ramp = index.as<prim::RampNode>();
       TVM_FFI_ICHECK(ramp);
       sym::ModularSet me = sym::Analyzer()->modular_set(ramp->base);
@@ -1082,9 +1082,9 @@ void CodeGenC::Dispatch_(const TensorStoreNode* op) {
     this->PrintIndent();
     stream << ref << " = " << value << ";\n";
   } else {
-    sym::PVar<PrimExpr> base;
+    tvm::PVar<PrimExpr> base;
 
-    if (sym::ramp(base, 1, value_ty.lanes()).Match(index_expr) &&
+    if (tvm::ramp(base, 1, value_ty.lanes()).Match(index_expr) &&
         value_ty.code() != DLDataTypeCode::kDLFloat4_e2m1fn) {
       std::string value = this->PrintExpr(op->value);
       this->PrintVecStore(op->dest.as_or_throw<TensorVar>().get(), value_ty, 
base.Eval(), value);
diff --git a/src/codegen/llvm/codegen_llvm.cc b/src/codegen/llvm/codegen_llvm.cc
index 855026f3..0a54fe46 100644
--- a/src/codegen/llvm/codegen_llvm.cc
+++ b/src/codegen/llvm/codegen_llvm.cc
@@ -87,6 +87,7 @@
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Transforms/IPO.h>
 #include <llvm/Transforms/Utils/ModuleUtils.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/runtime/base.h>
 #include <tvm/runtime/device_api.h>
 #include <tvm/runtime/logging.h>
@@ -100,7 +101,6 @@
 #include <utility>
 #include <vector>
 
-#include "../../sym/pattern_match.h"
 #include "../build_common.h"
 #include "codegen_params.h"
 #include "llvm_instance.h"
@@ -664,12 +664,12 @@ void CodeGenLLVM::AddAliasInfo(llvm::Instruction* inst, 
const VarNode* buffer_va
   }
 
   int64_t base = 0, width = 0;
-  sym::PVar<IntImm> pbase, pstride;
-  sym::PVar<IntImm> planes;
+  tvm::PVar<IntImm> pbase, pstride;
+  tvm::PVar<IntImm> planes;
   // create meta-data for alias analysis
   // Use a group of binary tree ranges of memory banks.
   int64_t xwith = 0;
-  if (sym::ramp(pbase, pstride, planes).Match(index)) {
+  if (tvm::ramp(pbase, pstride, planes).Match(index)) {
     if (auto b = pbase.Eval()->value.as<int64_t>(),
         w = (planes.Eval()->value * pstride.Eval()->value).as<int64_t>();
         b.has_value() && w.has_value()) {
diff --git a/src/ir/prim/int_operator.h b/src/ir/prim/int_operator.h
index ece6ac2e..b4f90011 100644
--- a/src/ir/prim/int_operator.h
+++ b/src/ir/prim/int_operator.h
@@ -28,7 +28,7 @@
 
 namespace tvm {
 namespace prim {
-namespace detail {
+namespace details {
 
 /*!
  * \brief Perform trunc division of two integers.
@@ -71,7 +71,7 @@ inline int64_t floormod(int64_t x, int64_t y) {
   return is_floor_div ? rmod : rmod + y;
 }
 
-}  // namespace detail
+}  // namespace details
 }  // namespace prim
 }  // namespace tvm
 #endif  // TVM_IR_PRIM_INT_OPERATOR_H_
diff --git a/src/ir/prim/math.cc b/src/ir/prim/math.cc
index 76e2cdda..a2194d61 100644
--- a/src/ir/prim/math.cc
+++ b/src/ir/prim/math.cc
@@ -31,7 +31,7 @@
 namespace tvm {
 namespace prim {
 
-using namespace prim::detail;
+using namespace prim::details;
 
 template <size_t N>
 static Type InferTypeReturnArgType(const CallNode* call) {
diff --git a/src/ir/prim/op.cc b/src/ir/prim/op.cc
index a160e457..8cd61e1b 100644
--- a/src/ir/prim/op.cc
+++ b/src/ir/prim/op.cc
@@ -17,17 +17,17 @@
  * under the License.
  */
 #include <tvm/ffi/reflection/registry.h>
+#include <tvm/ir/prim/const_fold.h>
 #include <tvm/ir/prim/op.h>
 
 #include <cmath>
 
-#include "const_fold.h"
 #include "op_utils.h"
 
 namespace tvm {
 using prim::IsConstInt;
 using prim::MakeConst;
-using namespace prim::detail;
+using namespace prim::details;
 namespace {
 TVM_FFI_INLINE const PrimTypeNode* GetPrimTypeNode(const PrimExpr& expr) {
   // Avoid PrimExpr::ty() ObjectRef materialization on binary operator hot 
paths.
@@ -71,7 +71,7 @@ bool IsVScaleCall(const PrimExpr& expr) {
 }
 
 }  // namespace
-namespace prim::detail {
+namespace prim::details {
 void BroadcastToMatchLanes(PrimExpr& op_a, PrimExpr& op_b) {  // NOLINT(*)
   PrimType ty_a = op_a.ty();
   PrimType ty_b = op_b.ty();
@@ -183,7 +183,7 @@ void BinaryOpMatchTypes(PrimExpr& lhs, PrimExpr& rhs, 
Location loc) {  // NOLINT
   }
 }
 
-}  // namespace prim::detail
+}  // namespace prim::details
 namespace prim {
 // maximum and min limits
 PrimExpr max_value(PrimType value_ty, Location loc) {
@@ -388,7 +388,7 @@ PrimExpr operator+(PrimExpr a, PrimExpr b) { return add(a, 
b); }
 
 PrimExpr add(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Add>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Add>(a, b)) return ret.value();
   return prim::Add(a, b, loc);
 }
 
@@ -401,7 +401,7 @@ PrimExpr neg(PrimExpr a, Location loc) {
   if (pa) {
     ffi::BigInt value = -pa->value;
     if (a.ty().MatchesCode(DLDataTypeCode::kDLInt) && a.ty().bits() >= 64) {
-      value = prim::detail::GetFoldResult(std::move(value), a.ty());
+      value = prim::details::GetFoldResult(std::move(value), a.ty());
     }
     return IntImm(a.ty(), std::move(value), loc);
   }
@@ -413,20 +413,20 @@ PrimExpr operator-(PrimExpr a, PrimExpr b) { return 
sub(a, b); }
 
 PrimExpr sub(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Sub>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Sub>(a, b)) return ret.value();
   return prim::Sub(a, b, loc);
 }
 
 PrimExpr operator*(PrimExpr a, PrimExpr b) { return mul(a, b); }
 PrimExpr mul(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Mul>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Mul>(a, b)) return ret.value();
   return prim::Mul(a, b, loc);
 }
 
 PrimExpr div(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Div>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Div>(a, b)) return ret.value();
   return prim::Div(a, b, loc);
 }
 
@@ -438,7 +438,7 @@ PrimExpr truncdiv(PrimExpr a, PrimExpr b, Location loc) {
 
 PrimExpr truncmod(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Mod>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Mod>(a, b)) return ret.value();
   return prim::Mod(a, b, loc);
 }
 
@@ -457,7 +457,7 @@ PrimExpr floordiv(PrimExpr a, PrimExpr b, Location loc) {
   TVM_FFI_ICHECK(a.ty().MatchesCode(DLDataTypeCode::kDLInt, 
DLDataTypeCode::kDLUInt)) << a;
   TVM_FFI_ICHECK(b.ty().MatchesCode(DLDataTypeCode::kDLInt, 
DLDataTypeCode::kDLUInt)) << b;
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::FloorDiv>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::FloorDiv>(a, b)) return ret.value();
   return prim::FloorDiv(a, b, loc);
 }
 
@@ -465,7 +465,7 @@ PrimExpr ceildiv(PrimExpr a, PrimExpr b, Location loc) {
   TVM_FFI_ICHECK(a.ty().MatchesCode(DLDataTypeCode::kDLInt, 
DLDataTypeCode::kDLUInt)) << a;
   TVM_FFI_ICHECK(b.ty().MatchesCode(DLDataTypeCode::kDLInt, 
DLDataTypeCode::kDLUInt)) << b;
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::FloorDiv>(a + b - 1, b)) 
return ret.value();
+  if (auto ret = prim::TryConstFold<prim::FloorDiv>(a + b - 1, b)) return 
ret.value();
   return prim::FloorDiv(a + b - 1, b, loc);
 }
 
@@ -473,33 +473,33 @@ PrimExpr floormod(PrimExpr a, PrimExpr b, Location loc) {
   TVM_FFI_ICHECK(a.ty().MatchesCode(DLDataTypeCode::kDLInt, 
DLDataTypeCode::kDLUInt)) << a;
   TVM_FFI_ICHECK(b.ty().MatchesCode(DLDataTypeCode::kDLInt, 
DLDataTypeCode::kDLUInt)) << b;
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::FloorMod>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::FloorMod>(a, b)) return ret.value();
   return prim::FloorMod(a, b, loc);
 }
 
 PrimExpr min(PrimExpr a, PrimExpr b, Location loc) {
   // inf-aware simplificaiton
-  using prim::detail::is_neg_inf;
-  using prim::detail::is_pos_inf;
+  using prim::is_neg_inf;
+  using prim::is_pos_inf;
   if (is_pos_inf(a)) return b;
   if (is_neg_inf(a)) return a;
   if (is_pos_inf(b)) return a;
   if (is_neg_inf(b)) return b;
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Min>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Min>(a, b)) return ret.value();
   return prim::Min(a, b, loc);
 }
 
 PrimExpr max(PrimExpr a, PrimExpr b, Location loc) {
   // inf-aware simplificaiton
-  using prim::detail::is_neg_inf;
-  using prim::detail::is_pos_inf;
+  using prim::is_neg_inf;
+  using prim::is_pos_inf;
   if (is_pos_inf(a)) return a;
   if (is_neg_inf(a)) return b;
   if (is_pos_inf(b)) return b;
   if (is_neg_inf(b)) return a;
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::Max>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Max>(a, b)) return ret.value();
   return prim::Max(a, b, loc);
 }
 
@@ -531,35 +531,35 @@ PrimExpr likely(PrimExpr cond, Location loc) {
 PrimExpr operator>(PrimExpr a, PrimExpr b) { return greater(a, b); }
 PrimExpr greater(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::GT>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::GT>(a, b)) return ret.value();
   return prim::GT(a, b, loc);
 }
 
 PrimExpr operator>=(PrimExpr a, PrimExpr b) { return greater_equal(a, b); }
 PrimExpr greater_equal(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::GE>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::GE>(a, b)) return ret.value();
   return prim::GE(a, b, loc);
 }
 
 PrimExpr operator<(PrimExpr a, PrimExpr b) { return less(a, b); }
 PrimExpr less(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::LT>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::LT>(a, b)) return ret.value();
   return prim::LT(a, b, loc);
 }
 
 PrimExpr operator<=(PrimExpr a, PrimExpr b) { return less_equal(a, b); }
 PrimExpr less_equal(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::LE>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::LE>(a, b)) return ret.value();
   return prim::LE(a, b, loc);
 }
 
 PrimExpr operator==(PrimExpr a, PrimExpr b) { return equal(a, b); }
 PrimExpr equal(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::EQ>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::EQ>(a, b)) return ret.value();
   if (IsVScaleCall(a) && IsVScaleCall(b)) return true;
   return prim::EQ(a, b, loc);
 }
@@ -567,7 +567,7 @@ PrimExpr equal(PrimExpr a, PrimExpr b, Location loc) {
 PrimExpr operator!=(PrimExpr a, PrimExpr b) { return not_equal(a, b); }
 PrimExpr not_equal(PrimExpr a, PrimExpr b, Location loc) {
   BinaryOpMatchTypes(a, b, loc);
-  if (auto ret = prim::detail::TryConstFold<prim::NE>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::NE>(a, b)) return ret.value();
   return prim::NE(a, b, loc);
 }
 
@@ -579,7 +579,7 @@ PrimExpr logical_and(PrimExpr a, PrimExpr b, Location loc) {
   TVM_FFI_ICHECK(b.ty().MatchesCode(DLDataTypeCode::kDLBool))
       << "Expected boolean argument as RHS of && operator (logical AND), but 
received " << b
       << " of type " << b.ty();
-  if (auto ret = prim::detail::TryConstFold<prim::And>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::And>(a, b)) return ret.value();
   return prim::And(a, b, loc);
 }
 
@@ -591,7 +591,7 @@ PrimExpr logical_or(PrimExpr a, PrimExpr b, Location loc) {
   TVM_FFI_ICHECK(b.ty().MatchesCode(DLDataTypeCode::kDLBool))
       << "Expected boolean argument as RHS of || operator (logical OR), but 
received " << b
       << " of type " << b.ty();
-  if (auto ret = prim::detail::TryConstFold<prim::Or>(a, b)) return 
ret.value();
+  if (auto ret = prim::TryConstFold<prim::Or>(a, b)) return ret.value();
   return prim::Or(a, b, loc);
 }
 
@@ -600,7 +600,7 @@ PrimExpr logical_not(PrimExpr a, Location loc) {
   TVM_FFI_ICHECK(a.ty().MatchesCode(DLDataTypeCode::kDLBool))
       << "Expected boolean argument for ! operator (logical NOT), but received 
" << a << " of type "
       << a.ty();
-  if (auto ret = prim::detail::TryConstFold<prim::Not>(a)) return ret.value();
+  if (auto ret = prim::TryConstFold<prim::Not>(a)) return ret.value();
   return prim::Not(a, loc);
 }
 
@@ -651,7 +651,7 @@ PrimExpr left_shift(PrimExpr a, PrimExpr b, Location loc) {
           << result_ty;
     if (pa && pb) {
       ffi::BigInt value = pa->value << pb->value;
-      if (result_ty.bits() >= 64) value = 
prim::detail::GetFoldResult(std::move(value), result_ty);
+      if (result_ty.bits() >= 64) value = 
prim::details::GetFoldResult(std::move(value), result_ty);
       return IntImm(result_ty, std::move(value), loc);
     }
     if (pb) {
@@ -733,7 +733,7 @@ PrimExpr prim::IntegerAbs(PrimExpr x, Location loc) {
   if (x.ty().MatchesCode(DLDataTypeCode::kDLInt)) {
     if (const IntImmNode* px = x.as<IntImmNode>()) {
       ffi::BigInt value = px->value < 0 ? -px->value : px->value;
-      if (x.ty().bits() >= 64) value = 
prim::detail::GetFoldResult(std::move(value), x.ty());
+      if (x.ty().bits() >= 64) value = 
prim::details::GetFoldResult(std::move(value), x.ty());
       return IntImm(x.ty(), std::move(value), px->loc);
     }
     return Select(x >= MakeConst(x.ty(), 0), x, -x, loc);
diff --git a/src/ir/prim/op_utils.h b/src/ir/prim/op_utils.h
index 2913bb4b..9ca7b992 100644
--- a/src/ir/prim/op_utils.h
+++ b/src/ir/prim/op_utils.h
@@ -20,8 +20,8 @@
 #ifndef TVM_IR_PRIM_OP_UTILS_H_
 #define TVM_IR_PRIM_OP_UTILS_H_
 #include <tvm/ir/prim/op.h>
-namespace tvm::prim::detail {
+namespace tvm::prim::details {
 TVM_TIRX_DLL void BinaryOpMatchTypes(PrimExpr& lhs, PrimExpr& rhs, Location 
loc);
 
-}  // namespace tvm::prim::detail
+}  // namespace tvm::prim::details
 #endif  // TVM_IR_PRIM_OP_UTILS_H_
diff --git a/src/ir/prim/symbolic_limits.cc b/src/ir/prim/symbolic_limits.cc
index 49ad9d11..2d991f27 100644
--- a/src/ir/prim/symbolic_limits.cc
+++ b/src/ir/prim/symbolic_limits.cc
@@ -21,15 +21,24 @@
  * \file symbolic_limits.cc
  * \brief Shared symbolic infinity atoms for primitive operations and integer 
analysis.
  */
-#include "const_fold.h"
+#include <tvm/ir/prim/op.h>
 
 namespace tvm {
 namespace prim {
-namespace detail {
 
-PrimExpr SymbolicLimits::pos_inf_ = PrimVar("pos_inf", PrimType::Int(64));
-PrimExpr SymbolicLimits::neg_inf_ = PrimVar("neg_inf", PrimType::Int(64));
+const PrimExpr& pos_inf() {
+  static const PrimExpr value = PrimVar("pos_inf", PrimType::Int(64));
+  return value;
+}
+
+const PrimExpr& neg_inf() {
+  static const PrimExpr value = PrimVar("neg_inf", PrimType::Int(64));
+  return value;
+}
+
+bool is_pos_inf(const PrimExpr& value) { return value.same_as(pos_inf()); }
+
+bool is_neg_inf(const PrimExpr& value) { return value.same_as(neg_inf()); }
 
-}  // namespace detail
 }  // namespace prim
 }  // namespace tvm
diff --git a/src/sym/analyzer.cc b/src/sym/analyzer.cc
index 3ca4bcdc..6183fb72 100644
--- a/src/sym/analyzer.cc
+++ b/src/sym/analyzer.cc
@@ -183,7 +183,8 @@ bool AnalyzerObj::CanProveEqual(const PrimExpr& lhs, const 
PrimExpr& rhs) {
   const auto* clhs = lhs.as<IntImmNode>();
   const auto* crhs = rhs.as<IntImmNode>();
   if (clhs && crhs) return clhs->value == crhs->value;
-  if (is_pos_inf(lhs) || is_neg_inf(lhs) || is_pos_inf(rhs) || 
is_neg_inf(rhs)) {
+  if (prim::is_pos_inf(lhs) || prim::is_neg_inf(lhs) || prim::is_pos_inf(rhs) 
||
+      prim::is_neg_inf(rhs)) {
     return lhs.same_as(rhs);
   }
   return CanProve(lhs - rhs == 0);
diff --git a/src/sym/bound_deducer.cc b/src/sym/bound_deducer.cc
index 29b35df3..457cb31a 100644
--- a/src/sym/bound_deducer.cc
+++ b/src/sym/bound_deducer.cc
@@ -27,7 +27,7 @@
 #include <tvm/ir/expr_functor.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/sym/analyzer.h>
-#include <tvm/sym/bound.h>
+#include <tvm/sym/int_set.h>
 
 #include <unordered_set>
 #include <vector>
@@ -375,7 +375,7 @@ IntSet DeduceBound(PrimExpr v, PrimExpr e, const 
ffi::Map<Var, IntSet>& hint_map
   BoundDeducer d(v, e, hint_map, relax_map);
   d.Deduce();
   if (!d.success_) return IntSet::Nothing();
-  PrimExpr min = neg_inf(), max = pos_inf();
+  PrimExpr min = prim::neg_inf(), max = prim::pos_inf();
   if (d.comp_op == kEqual) {
     min = d.result_;
     max = d.result_;
diff --git a/src/sym/canonical_simplify.cc b/src/sym/canonical_simplify.cc
index 2a41c2b2..20e9d45b 100644
--- a/src/sym/canonical_simplify.cc
+++ b/src/sym/canonical_simplify.cc
@@ -27,10 +27,10 @@
 #include <tvm/ir/cow.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
 #include "const_fold.h"
-#include "pattern_match.h"
 #include "product_normal_form.h"
 #include "rewrite_simplify.h"
 
diff --git a/src/sym/const_fold.h b/src/sym/const_fold.h
index e1b86f9d..6038ea3e 100644
--- a/src/sym/const_fold.h
+++ b/src/sym/const_fold.h
@@ -24,21 +24,17 @@
 #ifndef TVM_SYM_CONST_FOLD_H_
 #define TVM_SYM_CONST_FOLD_H_
 
-#include "../ir/prim/const_fold.h"
+#include <tvm/ir/prim/const_fold.h>
+
 #include "int_operator.h"
 
 namespace tvm {
 namespace sym {
 
-using prim::detail::GetFoldResultDoubleRepr;
-using prim::detail::is_neg_inf;
-using prim::detail::is_pos_inf;
-using prim::detail::IsIndexType;
-using prim::detail::IsIndexTypedExpr;
-using prim::detail::neg_inf;
-using prim::detail::pos_inf;
-using prim::detail::SymbolicLimits;
-using prim::detail::TryConstFold;
+using prim::TryConstFold;
+using prim::details::GetFoldResultDoubleRepr;
+using prim::details::IsIndexType;
+using prim::details::IsIndexTypedExpr;
 
 }  // namespace sym
 }  // namespace tvm
diff --git a/src/sym/const_int_bound.cc b/src/sym/const_int_bound.cc
index ca876a12..ff335127 100644
--- a/src/sym/const_int_bound.cc
+++ b/src/sym/const_int_bound.cc
@@ -27,6 +27,7 @@
 #include <tvm/ir/op.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
 #include <algorithm>
@@ -35,7 +36,6 @@
 
 #include "constraint_extract.h"
 #include "int_operator.h"
-#include "pattern_match.h"
 
 namespace tvm {
 namespace sym {
diff --git a/src/sym/constraint_extract.cc b/src/sym/constraint_extract.cc
index 51d02518..c58dcffb 100644
--- a/src/sym/constraint_extract.cc
+++ b/src/sym/constraint_extract.cc
@@ -24,10 +24,9 @@
 #include "constraint_extract.h"
 
 #include <tvm/ir/prim/expr.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
-#include "pattern_match.h"
-
 namespace tvm {
 namespace sym {
 
diff --git a/src/sym/int_operator.h b/src/sym/int_operator.h
index 92d4597a..24e6f641 100644
--- a/src/sym/int_operator.h
+++ b/src/sym/int_operator.h
@@ -87,10 +87,10 @@ inline bool WillOverflow<prim::ModNode>(int64_t x, int64_t 
y, int64_t min_value,
   return y == 0;
 }
 
-using prim::detail::floordiv;
-using prim::detail::floormod;
-using prim::detail::truncdiv;
-using prim::detail::truncmod;
+using prim::details::floordiv;
+using prim::details::floormod;
+using prim::details::truncdiv;
+using prim::details::truncmod;
 
 /*!
  * \brief Take GCD of a and b.
diff --git a/src/sym/int_set.cc b/src/sym/int_set.cc
index 50c90fd8..9f061343 100644
--- a/src/sym/int_set.cc
+++ b/src/sym/int_set.cc
@@ -28,6 +28,7 @@
 #include <tvm/ir/expr_functor.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/runtime/logging.h>
 #include <tvm/sym/int_set.h>
 #include <tvm/sym/iter_affine_map.h>
@@ -40,7 +41,6 @@
 #include "constraint_extract.h"
 #include "int_operator.h"
 #include "interval_set.h"
-#include "pattern_match.h"
 
 namespace tvm {
 namespace sym {
@@ -149,9 +149,9 @@ inline IntervalSet Combine<prim::Add>(AnalyzerObj* analyer, 
IntervalSet a, Inter
   if (a->IsEmpty()) return a;
   if (b->IsEmpty()) return b;
   PrimExpr min_value =
-      a->HasLowerBound() && b->HasLowerBound() ? a->min_value + b->min_value : 
neg_inf();
+      a->HasLowerBound() && b->HasLowerBound() ? a->min_value + b->min_value : 
prim::neg_inf();
   PrimExpr max_value =
-      a->HasUpperBound() && b->HasUpperBound() ? a->max_value + b->max_value : 
pos_inf();
+      a->HasUpperBound() && b->HasUpperBound() ? a->max_value + b->max_value : 
prim::pos_inf();
   return IntervalSet(min_value, max_value);
 }
 
@@ -164,9 +164,9 @@ inline IntervalSet Combine<prim::Sub>(AnalyzerObj* analyer, 
IntervalSet a, Inter
   if (a->IsEmpty()) return a;
   if (b->IsEmpty()) return b;
   PrimExpr min_value =
-      a->HasLowerBound() && b->HasUpperBound() ? a->min_value - b->max_value : 
neg_inf();
+      a->HasLowerBound() && b->HasUpperBound() ? a->min_value - b->max_value : 
prim::neg_inf();
   PrimExpr max_value =
-      a->HasUpperBound() && b->HasLowerBound() ? a->max_value - b->min_value : 
pos_inf();
+      a->HasUpperBound() && b->HasLowerBound() ? a->max_value - b->min_value : 
prim::pos_inf();
   return IntervalSet(min_value, max_value);
 }
 
@@ -185,12 +185,12 @@ inline IntervalSet Combine<prim::Mul>(AnalyzerObj* 
analyzer, IntervalSet a, Inte
     if (IsZero(b->min_value)) return b;
     if (IsOne(b->min_value)) return a;
     if (analyzer->CanProveGreaterEqual(b->min_value, 0)) {
-      PrimExpr min_value = a->HasLowerBound() ? a->min_value * b->min_value : 
neg_inf();
-      PrimExpr max_value = a->HasUpperBound() ? a->max_value * b->min_value : 
pos_inf();
+      PrimExpr min_value = a->HasLowerBound() ? a->min_value * b->min_value : 
prim::neg_inf();
+      PrimExpr max_value = a->HasUpperBound() ? a->max_value * b->min_value : 
prim::pos_inf();
       return IntervalSet(min_value, max_value);
     } else if (analyzer->CanProveGreaterEqual(-b->min_value, 1)) {
-      PrimExpr min_value = a->HasUpperBound() ? a->max_value * b->min_value : 
neg_inf();
-      PrimExpr max_value = a->HasLowerBound() ? a->min_value * b->min_value : 
pos_inf();
+      PrimExpr min_value = a->HasUpperBound() ? a->max_value * b->min_value : 
prim::neg_inf();
+      PrimExpr max_value = a->HasLowerBound() ? a->min_value * b->min_value : 
prim::pos_inf();
       return IntervalSet(min_value, max_value);
     } else if (a->HasUpperBound() && a->HasLowerBound()) {
       PrimExpr sign = b->min_value >= IntImm(b->min_value.ty().WithLanes(1), 
0);
@@ -218,12 +218,12 @@ inline IntervalSet Combine<prim::Div>(AnalyzerObj* 
analyzer, IntervalSet a, Inte
     if (IsOne(b->min_value)) return a;
     // no relaxation is needed in here due to set is inclusive
     if (analyzer->CanProveGreaterEqual(b->min_value, 0)) {
-      PrimExpr min_value = a->HasLowerBound() ? a->min_value / b->min_value : 
neg_inf();
-      PrimExpr max_value = a->HasUpperBound() ? a->max_value / b->min_value : 
pos_inf();
+      PrimExpr min_value = a->HasLowerBound() ? a->min_value / b->min_value : 
prim::neg_inf();
+      PrimExpr max_value = a->HasUpperBound() ? a->max_value / b->min_value : 
prim::pos_inf();
       return IntervalSet(min_value, max_value);
     } else if (analyzer->CanProveGreaterEqual(-b->min_value, 1)) {
-      PrimExpr min_value = a->HasUpperBound() ? a->max_value / b->min_value : 
neg_inf();
-      PrimExpr max_value = a->HasLowerBound() ? a->min_value / b->min_value : 
pos_inf();
+      PrimExpr min_value = a->HasUpperBound() ? a->max_value / b->min_value : 
prim::neg_inf();
+      PrimExpr max_value = a->HasLowerBound() ? a->min_value / b->min_value : 
prim::pos_inf();
       return IntervalSet(min_value, max_value);
     } else if (a->HasUpperBound() && a->HasLowerBound()) {
       PrimExpr sign = b->min_value >= IntImm(b->min_value.ty().WithLanes(1), 
0);
@@ -280,12 +280,16 @@ inline IntervalSet Combine<prim::FloorDiv>(AnalyzerObj* 
analyzer, IntervalSet a,
     if (IsOne(b->min_value)) return a;
     // no relaxation is needed in here due to set is inclusive
     if (analyzer->CanProveGreaterEqual(b->min_value, 0)) {
-      PrimExpr min_value = a->HasLowerBound() ? floordiv(a->min_value, 
b->min_value) : neg_inf();
-      PrimExpr max_value = a->HasUpperBound() ? floordiv(a->max_value, 
b->min_value) : pos_inf();
+      PrimExpr min_value =
+          a->HasLowerBound() ? floordiv(a->min_value, b->min_value) : 
prim::neg_inf();
+      PrimExpr max_value =
+          a->HasUpperBound() ? floordiv(a->max_value, b->min_value) : 
prim::pos_inf();
       return IntervalSet(min_value, max_value);
     } else if (analyzer->CanProveGreaterEqual(-b->min_value, 1)) {
-      PrimExpr min_value = a->HasUpperBound() ? floordiv(a->max_value, 
b->min_value) : neg_inf();
-      PrimExpr max_value = a->HasLowerBound() ? floordiv(a->min_value, 
b->min_value) : pos_inf();
+      PrimExpr min_value =
+          a->HasUpperBound() ? floordiv(a->max_value, b->min_value) : 
prim::neg_inf();
+      PrimExpr max_value =
+          a->HasLowerBound() ? floordiv(a->min_value, b->min_value) : 
prim::pos_inf();
       return IntervalSet(min_value, max_value);
     } else if (a->HasUpperBound() && a->HasLowerBound()) {
       PrimExpr sign = b->min_value >= IntImm(b->min_value.ty().WithLanes(1), 
0);
@@ -315,12 +319,12 @@ inline IntervalSet Combine<prim::FloorMod>(AnalyzerObj* 
analyzer, IntervalSet a,
     if (analyzer->CanProveGreaterEqual(divisor, 0)) {
       if (divisor.as<IntImmNode>()) {
         // a mod b = a - (a / b) * b if a_max / b == a_min / b
-        auto qmax = a->HasUpperBound() ? floordiv(a->max_value, divisor) : 
pos_inf();
-        auto qmin = a->HasLowerBound() ? floordiv(a->min_value, divisor) : 
neg_inf();
+        auto qmax = a->HasUpperBound() ? floordiv(a->max_value, divisor) : 
prim::pos_inf();
+        auto qmin = a->HasLowerBound() ? floordiv(a->min_value, divisor) : 
prim::neg_inf();
         // We can compare +/- inf against each other, but cannot use
         // operator== between the symbolic limits and an integer.
-        bool qmin_is_symbolic_limit = is_pos_inf(qmin) || is_neg_inf(qmin);
-        bool qmax_is_symbolic_limit = is_pos_inf(qmax) || is_neg_inf(qmax);
+        bool qmin_is_symbolic_limit = prim::is_pos_inf(qmin) || 
prim::is_neg_inf(qmin);
+        bool qmax_is_symbolic_limit = prim::is_pos_inf(qmax) || 
prim::is_neg_inf(qmax);
         bool compatible_dtypes = qmin_is_symbolic_limit == 
qmax_is_symbolic_limit;
         if (compatible_dtypes && analyzer->CanProve(qmax == qmin)) {
           auto tmax = a->max_value - divisor * qmin;
@@ -572,10 +576,10 @@ class IntervalSetEvaluator : public 
tvm::ExprFunctor<IntervalSet(const Expr&)> {
     }
     PrimExpr min_value = value_set->HasLowerBound()
                              ? prim::cast(value_set->min_value, 
op->ty.as_or_throw<PrimType>())
-                             : neg_inf();
+                             : prim::neg_inf();
     PrimExpr max_value = value_set->HasUpperBound()
                              ? prim::cast(value_set->max_value, 
op->ty.as_or_throw<PrimType>())
-                             : pos_inf();
+                             : prim::pos_inf();
     return IntervalSet(min_value, max_value);
   }
 
@@ -735,25 +739,25 @@ std::vector<std::pair<Var, IntSet>> 
IntSetAnalyzer::Impl::DetectBoundInfo(
   std::vector<std::pair<Var, IntSet>> bounds;
   for (const PrimExpr& subconstraint : ExtractConstraints(constraint)) {
     if ((x <= limit).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(SymbolicLimits::neg_inf_, 
limit.Eval())});
+      bounds.push_back({x.Eval(), IntSet::Interval(prim::neg_inf(), 
limit.Eval())});
     } else if ((x < limit).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(SymbolicLimits::neg_inf_, 
limit.Eval() - 1)});
+      bounds.push_back({x.Eval(), IntSet::Interval(prim::neg_inf(), 
limit.Eval() - 1)});
     } else if ((x >= limit).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval(), 
SymbolicLimits::pos_inf_)});
+      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval(), 
prim::pos_inf())});
     } else if ((x > limit).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval() + 1, 
SymbolicLimits::pos_inf_)});
+      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval() + 1, 
prim::pos_inf())});
     } else if ((x == limit).Match(subconstraint)) {
       bounds.push_back({x.Eval(), IntSet::SinglePoint(limit.Eval())});
     }
 
     if ((limit >= x).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(SymbolicLimits::neg_inf_, 
limit.Eval())});
+      bounds.push_back({x.Eval(), IntSet::Interval(prim::neg_inf(), 
limit.Eval())});
     } else if ((limit > x).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(SymbolicLimits::neg_inf_, 
limit.Eval() - 1)});
+      bounds.push_back({x.Eval(), IntSet::Interval(prim::neg_inf(), 
limit.Eval() - 1)});
     } else if ((limit <= x).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval(), 
SymbolicLimits::pos_inf_)});
+      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval(), 
prim::pos_inf())});
     } else if ((limit < x).Match(subconstraint)) {
-      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval() + 1, 
SymbolicLimits::pos_inf_)});
+      bounds.push_back({x.Eval(), IntSet::Interval(limit.Eval() + 1, 
prim::pos_inf())});
     } else if ((limit == x).Match(subconstraint)) {
       bounds.push_back({x.Eval(), IntSet::SinglePoint(limit.Eval())});
     }
@@ -977,9 +981,11 @@ IntSet UnionLowerBound(const ffi::Array<IntSet>& sets) {
         max_inclusive = std::move(new_max_inclusive);
         continue;
       }
-      bool bound_1 = is_neg_inf(new_min_inclusive) || 
is_pos_inf(max_inclusive.value()) ||
+      bool bound_1 = prim::is_neg_inf(new_min_inclusive) ||
+                     prim::is_pos_inf(max_inclusive.value()) ||
                      analyzer->CanProve(new_min_inclusive <= 
max_inclusive.value() + 1);
-      bool bound_2 = is_neg_inf(min_inclusive.value()) || 
is_pos_inf(new_max_inclusive) ||
+      bool bound_2 = prim::is_neg_inf(min_inclusive.value()) ||
+                     prim::is_pos_inf(new_max_inclusive) ||
                      analyzer->CanProve(min_inclusive.value() <= 
new_max_inclusive + 1);
       if (bound_1 && bound_2) {
         min_inclusive = min(min_inclusive.value(), new_min_inclusive);
@@ -1267,8 +1273,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
              Analyzer analyzer = opt_analyzer.has_value() ? 
opt_analyzer.value() : Analyzer();
              return EstimateRegionUpperBound(region, var_dom, predicate, 
analyzer);
            })
-      .def("sym.PosInf", []() { return SymbolicLimits::pos_inf_; })
-      .def("sym.NegInf", []() { return SymbolicLimits::neg_inf_; })
+      .def("sym.PosInf", []() { return prim::pos_inf(); })
+      .def("sym.NegInf", []() { return prim::neg_inf(); })
       .def("sym.UnionLowerBound", UnionLowerBound);
 }
 
diff --git a/src/sym/interval_set.h b/src/sym/interval_set.h
index 1aee24ae..46e767a2 100644
--- a/src/sym/interval_set.h
+++ b/src/sym/interval_set.h
@@ -64,9 +64,9 @@ class IntervalSetObj : public IntSetObj {
   }
 
   /*! \return Whether the interval has upper bound. */
-  bool HasUpperBound() const { return !is_pos_inf(max_value) && !IsEmpty(); }
+  bool HasUpperBound() const { return !prim::is_pos_inf(max_value) && 
!IsEmpty(); }
   /*! \return Whether the interval has lower bound. */
-  bool HasLowerBound() const { return !is_neg_inf(min_value) && !IsEmpty(); }
+  bool HasLowerBound() const { return !prim::is_neg_inf(min_value) && 
!IsEmpty(); }
   /*! \return Whether the interval is a single point. */
   bool IsSinglePoint() const {
     // NOTE: we are only doing cheap check as this is a frequently called 
routine,
@@ -77,10 +77,10 @@ class IntervalSetObj : public IntSetObj {
   /*! \return whether interval represent nothing */
   bool IsEmpty() const {
     // during computations, either extreme could occur.
-    return is_pos_inf(min_value) || is_neg_inf(max_value);
+    return prim::is_pos_inf(min_value) || prim::is_neg_inf(max_value);
   }
   /*! \return whether interval represent everything */
-  bool IsEverything() const { return is_neg_inf(min_value) && 
is_pos_inf(max_value); }
+  bool IsEverything() const { return prim::is_neg_inf(min_value) && 
prim::is_pos_inf(max_value); }
   TVM_FFI_DECLARE_OBJECT_INFO_FINAL("sym.IntervalSet", IntervalSetObj, 
IntSetObj);
 };
 
@@ -109,12 +109,12 @@ class IntervalSet : public IntSet {
    * \param value The value to be represented.
    * \return The result set.
    */
-  static IntervalSet Everything() { return IntervalSet(neg_inf(), pos_inf()); }
+  static IntervalSet Everything() { return IntervalSet(prim::neg_inf(), 
prim::pos_inf()); }
   /*!
    * \brief Create an empty eet.
    * \return The result set.
    */
-  static IntervalSet Empty() { return IntervalSet(pos_inf(), neg_inf()); }
+  static IntervalSet Empty() { return IntervalSet(prim::pos_inf(), 
prim::neg_inf()); }
 
   TVM_DEFINE_OBJECT_REF_COW_METHOD(IntervalSetObj);
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IntervalSet, IntSet, 
IntervalSetObj);
diff --git a/src/sym/iter_affine_map.cc b/src/sym/iter_affine_map.cc
index 813bf66f..1189aac7 100644
--- a/src/sym/iter_affine_map.cc
+++ b/src/sym/iter_affine_map.cc
@@ -27,6 +27,7 @@
 #include <tvm/ffi/reflection/registry.h>
 #include <tvm/ir/expr_functor.h>
 #include <tvm/ir/prim/expr.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 #include <tvm/sym/iter_affine_map.h>
 
@@ -34,7 +35,6 @@
 #include <utility>
 
 #include "const_fold.h"
-#include "pattern_match.h"
 #include "product_normal_form.h"
 
 namespace tvm {
@@ -1376,7 +1376,7 @@ struct IterConstraint {
  */
 bool MatchBoundConstraints(PrimExpr pred, ffi::Map<PrimVar, Range>* 
input_iters,
                            std::vector<IterConstraint>* result) {
-  sym::PVar<PrimExpr> lhs, rhs, rest;
+  tvm::PVar<PrimExpr> lhs, rhs, rest;
   std::unordered_set<const VarNode*> input_iter_nodes;
   for (const auto& [var, _] : *input_iters) {
     input_iter_nodes.insert(var.get());
diff --git a/src/sym/known_comparison_analyzer.cc 
b/src/sym/known_comparison_analyzer.cc
index ab9850c2..3908b26d 100644
--- a/src/sym/known_comparison_analyzer.cc
+++ b/src/sym/known_comparison_analyzer.cc
@@ -21,13 +21,13 @@
  */
 
 #include <tvm/ir/prim/expr.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
 #include <optional>
 #include <vector>
 
 #include "constraint_extract.h"
-#include "pattern_match.h"
 
 namespace tvm {
 namespace sym {
diff --git a/src/sym/modular_set.cc b/src/sym/modular_set.cc
index d765747f..0ea3d3f0 100644
--- a/src/sym/modular_set.cc
+++ b/src/sym/modular_set.cc
@@ -26,6 +26,7 @@
 #include <tvm/ffi/reflection/registry.h>
 #include <tvm/ir/expr_functor.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
 #include <limits>
@@ -33,8 +34,6 @@
 #include <unordered_map>
 #include <utility>
 
-#include "pattern_match.h"
-
 namespace tvm {
 namespace sym {
 using namespace tvm::prim;
diff --git a/src/sym/rewrite_simplify.cc b/src/sym/rewrite_simplify.cc
index 716832d2..f72a48d9 100644
--- a/src/sym/rewrite_simplify.cc
+++ b/src/sym/rewrite_simplify.cc
@@ -29,6 +29,7 @@
 #include <tvm/ir/op.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
 #include <algorithm>
@@ -38,7 +39,6 @@
 
 #include "const_fold.h"
 #include "constraint_extract.h"
-#include "pattern_match.h"
 
 namespace tvm {
 namespace sym {
@@ -52,17 +52,17 @@ TVM_FFI_INLINE bool IsVectorExpr(const ExprNode* expr) {
 
 TVM_FFI_STATIC_INIT_BLOCK() { RewriteSimplifierStatsObj::RegisterReflection(); 
}
 
-// Note: When using matches_one_of or PMatchesOneOf alongside these
+// Note: When using MatchesOneOf or PMatchesOneOf alongside these
 // macros, be careful which patterns are used in the ResExpr.  While
 // the different source expressions may be in terms of different PVar,
 // the ResExpr should only contain patterns that are defined in
 // *every* SrcExpr given.
 //
 // Allowed (replacement does not use either c1 or y):
-//     TVM_TRY_REWRITE(matches_one_of(x + c1 - c1, x + y - y), x)
+//     TVM_TRY_REWRITE(MatchesOneOf(x + c1 - c1, x + y - y), x)
 //
 // Forbidden (c3 undefined if the first pattern matches):
-//     TVM_TRY_REWRITE(matches_one_of(floormod(x*c1,c2), floormod(x*c1 + c3, 
c2)),
+//     TVM_TRY_REWRITE(MatchesOneOf(floormod(x*c1,c2), floormod(x*c1 + c3, 
c2)),
 //                     floormod(x*floormod(c1,c2) + floormod(c3,c2), c2))
 
 // macro for doing simple rewrite
@@ -311,9 +311,9 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::AddNode* op,
     // mul co-efficient folding
     TVM_TRY_REWRITE(x + x, x * 2);
 
-    TVM_TRY_REWRITE(matches_one_of(x * y + x, y * x + x, x + y * x, x + x * 
y), (y + 1) * x);
+    TVM_TRY_REWRITE(MatchesOneOf(x * y + x, y * x + x, x + y * x, x + x * y), 
(y + 1) * x);
 
-    TVM_TRY_REWRITE(matches_one_of(x * y + x * z, y * x + x * z, x * y + z * 
x, y * x + z * x),
+    TVM_TRY_REWRITE(MatchesOneOf(x * y + x * z, y * x + x * z, x * y + z * x, 
y * x + z * x),
                     (y + z) * x);
 
     // DivMod rules
@@ -321,8 +321,8 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::AddNode* op,
     TVM_TRY_REWRITE(truncdiv(x, c1) * c1 + truncmod(x, c1), x);
     // floor div
     TVM_TRY_REWRITE(
-        matches_one_of(floordiv(x, y) * y + floormod(x, y), y * floordiv(x, y) 
+ floormod(x, y),
-                       floormod(x, y) + floordiv(x, y) * y, floormod(x, y) + y 
* floordiv(x, y)),
+        MatchesOneOf(floordiv(x, y) * y + floormod(x, y), y * floordiv(x, y) + 
floormod(x, y),
+                     floormod(x, y) + floordiv(x, y) * y, floormod(x, y) + y * 
floordiv(x, y)),
         x);
 
     TVM_TRY_REWRITE_IF(floordiv(floormod(x, c2) + c1, c2) + floordiv(x, c2), 
floordiv(x + c1, c2),
@@ -342,9 +342,8 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::AddNode* op,
     // canonicalization rule
     // will try rewrite again after canonicalization.
 
-    TVM_TRY_RECURSIVE_REWRITE(matches_one_of(x + (c1 - y), (c1 - y) + x), (x - 
y) + c1);
-    TVM_TRY_RECURSIVE_REWRITE(matches_one_of((x + c1) + y, x + (c1 + y), x + 
(y + c1)),
-                              (x + y) + c1);
+    TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(x + (c1 - y), (c1 - y) + x), (x - 
y) + c1);
+    TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf((x + c1) + y, x + (c1 + y), x + (y 
+ c1)), (x + y) + c1);
     TVM_TRY_RECURSIVE_REWRITE(x + max(y, z), max(y, z) + x);
     TVM_TRY_RECURSIVE_REWRITE(x + min(y, z), min(y, z) + x);
 
@@ -418,19 +417,19 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::SubNode* op,
   if (IsIndexTypedExpr(op)) {
     // Index rules
     // cancelation rules
-    TVM_TRY_REWRITE(matches_one_of((x + y) - y, (y + x) - y), x);
-    TVM_TRY_REWRITE(matches_one_of(x - (y + x), x - (x + y)), 0 - y);
+    TVM_TRY_REWRITE(MatchesOneOf((x + y) - y, (y + x) - y), x);
+    TVM_TRY_REWRITE(MatchesOneOf(x - (y + x), x - (x + y)), 0 - y);
 
-    TVM_TRY_REWRITE(matches_one_of(min(x, y) - y, x - max(y, x)), min(x - y, 
0));
-    TVM_TRY_REWRITE(matches_one_of(x - max(x, y), min(y, x) - y), min(0, x - 
y));
-    TVM_TRY_REWRITE(matches_one_of(max(x, y) - y, x - min(y, x)), max(x - y, 
0));
-    TVM_TRY_REWRITE(matches_one_of(x - min(x, y), max(y, x) - y), max(0, x - 
y));
+    TVM_TRY_REWRITE(MatchesOneOf(min(x, y) - y, x - max(y, x)), min(x - y, 0));
+    TVM_TRY_REWRITE(MatchesOneOf(x - max(x, y), min(y, x) - y), min(0, x - y));
+    TVM_TRY_REWRITE(MatchesOneOf(max(x, y) - y, x - min(y, x)), max(x - y, 0));
+    TVM_TRY_REWRITE(MatchesOneOf(x - min(x, y), max(y, x) - y), max(0, x - y));
 
     // mul co-efficient folding: pefer co-effiicent to stay at rhs
     TVM_TRY_REWRITE(x - x, ZeroWithTypeLike(x));
-    TVM_TRY_REWRITE(matches_one_of(x * y - x, y * x - x), (y - 1) * x);
-    TVM_TRY_REWRITE(matches_one_of(x - x * y, x - y * x), (1 - y) * x);
-    TVM_TRY_REWRITE(matches_one_of(x * y - x * z, y * x - x * z, x * y - z * 
x, y * x - z * x),
+    TVM_TRY_REWRITE(MatchesOneOf(x * y - x, y * x - x), (y - 1) * x);
+    TVM_TRY_REWRITE(MatchesOneOf(x - x * y, x - y * x), (1 - y) * x);
+    TVM_TRY_REWRITE(MatchesOneOf(x * y - x * z, y * x - x * z, x * y - z * x, 
y * x - z * x),
                     (y - z) * x);
 
     // constant cancelation
@@ -439,28 +438,28 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::SubNode* op,
 
     // cancelization rule involving 4 operands
     TVM_TRY_REWRITE(
-        matches_one_of((x + y) - (x + z), (x + y) - (z + x), (y + x) - (z + 
x), (y + x) - (x + z)),
+        MatchesOneOf((x + y) - (x + z), (x + y) - (z + x), (y + x) - (z + x), 
(y + x) - (x + z)),
         y - z);
 
-    TVM_TRY_REWRITE(matches_one_of(min(x + y, z) - x, min(y + x, z) - x), 
min(y, z - x));
-    TVM_TRY_REWRITE(matches_one_of(min(z, x + y) - x, min(z, y + x) - x), 
min(z - x, y));
+    TVM_TRY_REWRITE(MatchesOneOf(min(x + y, z) - x, min(y + x, z) - x), min(y, 
z - x));
+    TVM_TRY_REWRITE(MatchesOneOf(min(z, x + y) - x, min(z, y + x) - x), min(z 
- x, y));
 
-    TVM_TRY_REWRITE(matches_one_of(max(x + y, z) - x, max(y + x, z) - x), 
max(y, z - x));
-    TVM_TRY_REWRITE(matches_one_of(max(z, x + y) - x, max(z, y + x) - x), 
max(z - x, y));
+    TVM_TRY_REWRITE(MatchesOneOf(max(x + y, z) - x, max(y + x, z) - x), max(y, 
z - x));
+    TVM_TRY_REWRITE(MatchesOneOf(max(z, x + y) - x, max(z, y + x) - x), max(z 
- x, y));
 
-    TVM_TRY_REWRITE(matches_one_of(x - min(x + y, z), x - min(y + x, z)), 
max(0 - y, x - z));
-    TVM_TRY_REWRITE(matches_one_of(x - min(z, x + y), x - min(z, y + x)), 
max(x - z, 0 - y));
-    TVM_TRY_REWRITE(matches_one_of(x - max(x + y, z), x - max(y + x, z)), 
min(0 - y, x - z));
-    TVM_TRY_REWRITE(matches_one_of(x - max(z, x + y), x - max(z, y + x)), 
min(x - z, 0 - y));
+    TVM_TRY_REWRITE(MatchesOneOf(x - min(x + y, z), x - min(y + x, z)), max(0 
- y, x - z));
+    TVM_TRY_REWRITE(MatchesOneOf(x - min(z, x + y), x - min(z, y + x)), max(x 
- z, 0 - y));
+    TVM_TRY_REWRITE(MatchesOneOf(x - max(x + y, z), x - max(y + x, z)), min(0 
- y, x - z));
+    TVM_TRY_REWRITE(MatchesOneOf(x - max(z, x + y), x - max(z, y + x)), min(x 
- z, 0 - y));
 
     TVM_TRY_REWRITE(min(x, y) - min(y, x), ZeroWithTypeLike(x));
     TVM_TRY_REWRITE(max(x, y) - max(y, x), ZeroWithTypeLike(x));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(min(b1, b2) - min(s1, s2), min(b1, b2) - 
min(s2, s1)),
-                       b1 - s1, CanProveEqual(((b1 - s1) - (b2 - s2)).Eval(), 
0));
+    TVM_TRY_REWRITE_IF(MatchesOneOf(min(b1, b2) - min(s1, s2), min(b1, b2) - 
min(s2, s1)), b1 - s1,
+                       CanProveEqual(((b1 - s1) - (b2 - s2)).Eval(), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(max(b1, b2) - max(s1, s2), max(b1, b2) - 
max(s2, s1)),
-                       b1 - s1, CanProveEqual(((b1 - s1) - (b2 - s2)).Eval(), 
0));
+    TVM_TRY_REWRITE_IF(MatchesOneOf(max(b1, b2) - max(s1, s2), max(b1, b2) - 
max(s2, s1)), b1 - s1,
+                       CanProveEqual(((b1 - s1) - (b2 - s2)).Eval(), 0));
 
     // DivMod rules
     // trucdiv
@@ -602,8 +601,8 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::MulNode* op,
   // Vector rules
   if (IsVectorExpr(op)) {
     TVM_TRY_REWRITE(broadcast(x, lanes) * broadcast(y, lanes), broadcast(x * 
y, lanes));
-    TVM_TRY_REWRITE(matches_one_of(ramp(b1, s1, lanes) * broadcast(x, lanes),
-                                   broadcast(x, lanes) * ramp(b1, s1, lanes)),
+    TVM_TRY_REWRITE(MatchesOneOf(ramp(b1, s1, lanes) * broadcast(x, lanes),
+                                 broadcast(x, lanes) * ramp(b1, s1, lanes)),
                     ramp(b1 * x, s1 * x, lanes));
     TVM_TRY_REWRITE_IF(broadcast(c3, lanes) * x, broadcast(c3, lanes), 
c3.Eval()->value == 0.0f);
   }
@@ -612,7 +611,7 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::MulNode* op,
     // constant simplification rule
     TVM_TRY_REWRITE((x + c1) * c2, x * c2 + c1 * c2);
     TVM_TRY_REWRITE((x * c1) * c2, x * (c1 * c2));
-    TVM_TRY_REWRITE(matches_one_of(min(x, y) * max(x, y), max(x, y) * min(x, 
y)), x * y);
+    TVM_TRY_REWRITE(MatchesOneOf(min(x, y) * max(x, y), max(x, y) * min(x, 
y)), x * y);
 
     // Two representations of const*ceildiv(x, c1)
     TVM_TRY_REWRITE_IF(floordiv(x - floormod(x, c2), c1) * c1, x - floormod(x, 
c2),
@@ -699,7 +698,7 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::DivNode* op,
     }
 
     TVM_TRY_REWRITE(truncdiv(x, x), OneWithTypeLike(x));
-    TVM_TRY_REWRITE(matches_one_of(truncdiv(x * c1, x), truncdiv(c1 * x, x)), 
c1);
+    TVM_TRY_REWRITE(MatchesOneOf(truncdiv(x * c1, x), truncdiv(c1 * x, x)), 
c1);
 
     // Rules involving 2-operands.
     TVM_TRY_REWRITE_IF(truncdiv(x * c1 + y, c2), x * truncdiv(c1, c2) + 
truncdiv(y, c2),
@@ -758,23 +757,23 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::DivNode* op,
                            c1.Eval()->value % c2.Eval()->value == 0 &&
                            CanProveGreaterEqual(x.Eval(), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(truncdiv(x + y, x), truncdiv(y + x, x)), 
truncdiv(y, x) + 1,
+    TVM_TRY_REWRITE_IF(MatchesOneOf(truncdiv(x + y, x), truncdiv(y + x, x)), 
truncdiv(y, x) + 1,
                        CanProveGreaterEqual(x.Eval(), 0) && 
CanProveGreaterEqual(y.Eval(), 0));
 
     TVM_TRY_REWRITE_IF(
-        matches_one_of(truncdiv((x + y) + z, x), truncdiv((y + x) + z, x), 
truncdiv(y + (z + x), x),
-                       truncdiv(y + (x + z), x)),
+        MatchesOneOf(truncdiv((x + y) + z, x), truncdiv((y + x) + z, x), 
truncdiv(y + (z + x), x),
+                     truncdiv(y + (x + z), x)),
         truncdiv(y + z, x) + 1,
         CanProveGreaterEqual(x.Eval(), 0) && CanProveGreaterEqual((y + 
z).Eval(), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(truncdiv(x * y, y), truncdiv(y * x, y)), 
x,
+    TVM_TRY_REWRITE_IF(MatchesOneOf(truncdiv(x * y, y), truncdiv(y * x, y)), x,
                        CanProveGreaterEqual(x.Eval(), 0) && 
CanProveGreaterEqual(y.Eval(), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(truncdiv(x * z + y, z), truncdiv(z * x + 
y, z)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(truncdiv(x * z + y, z), truncdiv(z * x + 
y, z)),
                        x + truncdiv(y, z),
                        CanProveGreaterEqual(x.Eval(), 0) && 
CanProveGreaterEqual(y.Eval(), 0) &&
                            CanProveGreaterEqual(z.Eval(), 0));
-    TVM_TRY_REWRITE_IF(matches_one_of(truncdiv(y + x * z, z), truncdiv(y + z * 
x, z)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(truncdiv(y + x * z, z), truncdiv(y + z * 
x, z)),
                        truncdiv(y, z) + x,
                        CanProveGreaterEqual(x.Eval(), 0) && 
CanProveGreaterEqual(y.Eval(), 0) &&
                            CanProveGreaterEqual(z.Eval(), 0));
@@ -956,7 +955,7 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::FloorDivNode*
     }
 
     TVM_TRY_REWRITE(floordiv(x, x), OneWithTypeLike(x));
-    TVM_TRY_REWRITE(matches_one_of(floordiv(x * c1, x), floordiv(c1 * x, x)), 
c1);
+    TVM_TRY_REWRITE(MatchesOneOf(floordiv(x * c1, x), floordiv(c1 * x, x)), 
c1);
 
     TVM_TRY_REWRITE(floordiv(floormod(x, 2) + 1, 2), floormod(x, 2));
 
@@ -981,7 +980,7 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::FloorDivNode*
                            c2.Eval()->value % c1.Eval()->value == 0 &&
                            CanProveEqual(floordiv(y.Eval() + z.Eval(), 
c1.Eval()), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(floordiv(x * c1 - y + z, c2), floordiv(x 
* c1 + z - y, c2)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(floordiv(x * c1 - y + z, c2), floordiv(x * 
c1 + z - y, c2)),
                        x * floordiv(c1, c2) + floordiv(z - y, c2),
                        c2.Eval()->value > 0 && c1.Eval()->value % 
c2.Eval()->value == 0);
 
@@ -999,19 +998,19 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::FloorDivNode*
 
     TVM_TRY_REWRITE_IF(floordiv(x * c1, x * c2), floordiv(c1, c2), 
c2.Eval()->value > 0);
 
-    TVM_TRY_REWRITE_IF(matches_one_of(floordiv(x + y, x), floordiv(y + x, x)), 
floordiv(y, x) + 1,
+    TVM_TRY_REWRITE_IF(MatchesOneOf(floordiv(x + y, x), floordiv(y + x, x)), 
floordiv(y, x) + 1,
                        CanProveGreaterEqual(x.Eval(), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(floordiv((x + y) + z, x), floordiv((y + 
x) + z, x),
-                                      floordiv(y + (z + x), x), floordiv(y + 
(x + z), x)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(floordiv((x + y) + z, x), floordiv((y + x) 
+ z, x),
+                                    floordiv(y + (z + x), x), floordiv(y + (x 
+ z), x)),
                        floordiv(y + z, x) + 1, CanProveGreaterEqual(x.Eval(), 
0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(floordiv(x * y, y), floordiv(y * x, y)), 
x,
+    TVM_TRY_REWRITE_IF(MatchesOneOf(floordiv(x * y, y), floordiv(y * x, y)), x,
                        CanProveGreaterEqual(y.Eval(), 0));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(floordiv(x * z + y, z), floordiv(z * x + 
y, z)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(floordiv(x * z + y, z), floordiv(z * x + 
y, z)),
                        x + floordiv(y, z), CanProveGreaterEqual(z.Eval(), 0));
-    TVM_TRY_REWRITE_IF(matches_one_of(floordiv(y + x * z, z), floordiv(y + z * 
x, z)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(floordiv(y + x * z, z), floordiv(y + z * 
x, z)),
                        floordiv(y, z) + x, CanProveGreaterEqual(z.Eval(), 0));
     TVM_TRY_REWRITE_IF(floordiv(x * z * c1 + y, z * c1), x + floordiv(y, z * 
c1),
                        CanProveGreaterEqual(z.Eval() * c1.Eval(), 0));
@@ -1150,15 +1149,15 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::FloorModNode*
 
     TVM_TRY_REWRITE_IF(floormod(x * c1, x * c2), x * floormod(c1, c2), 
c2.Eval()->value != 0);
 
-    TVM_TRY_REWRITE(matches_one_of(floormod(x * y, y), floormod(y * x, y)), 
ZeroWithTypeLike(y));
+    TVM_TRY_REWRITE(MatchesOneOf(floormod(x * y, y), floormod(y * x, y)), 
ZeroWithTypeLike(y));
 
     // x = ay + b, then (ay + b + (ny - ay - b) % y) % y -> (b + (-b) % y) % y 
-> 0
     TVM_TRY_REWRITE_IF(
-        matches_one_of(floormod(x + floormod(z, y), y), floormod(floormod(z, 
y) + x, y)),
+        MatchesOneOf(floormod(x + floormod(z, y), y), floormod(floormod(z, y) 
+ x, y)),
         ZeroWithTypeLike(x), CanProveEqual(floormod(x.Eval() + z.Eval(), 
y.Eval()), 0));
     // x = ay + b, then (ay + b - (ay + b) % +-y) % y -> (b - b % +-y) % y -> 0
     TVM_TRY_REWRITE_IF(
-        matches_one_of(floormod(x - floormod(x, z), y), floormod(floormod(x, 
z) - x, y)),
+        MatchesOneOf(floormod(x - floormod(x, z), y), floormod(floormod(x, z) 
- x, y)),
         ZeroWithTypeLike(x),
         CanProveEqual(y.Eval() - z.Eval(), 0) || CanProveEqual(y.Eval() + 
z.Eval(), 0));
 
@@ -1299,19 +1298,19 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::MinNode* op,
     // DivMod rules
     // NOTE: trucdiv(x, y) >= floordiv(x, y)
     TVM_TRY_REWRITE_IF(
-        matches_one_of(min(truncdiv(x + c1, c2) * c2, x), min(x, truncdiv(x + 
c1, c2) * c2),
-                       min(floordiv(x + c1, c2) * c2, x), min(x, floordiv(x + 
c1, c2) * c2)),
+        MatchesOneOf(min(truncdiv(x + c1, c2) * c2, x), min(x, truncdiv(x + 
c1, c2) * c2),
+                     min(floordiv(x + c1, c2) * c2, x), min(x, floordiv(x + 
c1, c2) * c2)),
         x, c2.Eval()->value > 0 && c1.Eval()->value + 1 == c2.Eval()->value);
 
-    TVM_TRY_REWRITE_IF(matches_one_of(min(truncdiv(x + c1, c2) * c2, max(x, 
c2)),
-                                      min(max(x, c2), truncdiv(x + c1, c2) * 
c2),
-                                      min(floordiv(x + c1, c2) * c2, max(x, 
c2)),
-                                      min(max(x, c2), floordiv(x + c1, c2) * 
c2)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(min(truncdiv(x + c1, c2) * c2, max(x, c2)),
+                                    min(max(x, c2), truncdiv(x + c1, c2) * c2),
+                                    min(floordiv(x + c1, c2) * c2, max(x, c2)),
+                                    min(max(x, c2), floordiv(x + c1, c2) * 
c2)),
                        max(x, c2),
                        c2.Eval()->value > 0 && c1.Eval()->value + 1 == 
c2.Eval()->value &&
                            CanProveGreaterEqual(x.Eval(), 1));
 
-    TVM_TRY_REWRITE_IF(matches_one_of(min(x, floordiv(x, c2) * c2), 
min(floordiv(x, c2) * c2, x)),
+    TVM_TRY_REWRITE_IF(MatchesOneOf(min(x, floordiv(x, c2) * c2), 
min(floordiv(x, c2) * c2, x)),
                        floordiv(x, c2) * c2, c2.Eval()->value > 0);
 
     TVM_TRY_REWRITE((PMatchesOneOf{
@@ -1911,8 +1910,8 @@ PrimExpr 
RewriteSimplifier::Impl::ApplyRewriteRules(prim::LT ret, InplaceMode in
 
     // clang-format on
 
-    TVM_TRY_RECURSIVE_REWRITE(matches_one_of(c1 < x + c2, c1 - x < c2), c1 - 
c2 < x);
-    TVM_TRY_RECURSIVE_REWRITE(matches_one_of(c1 < c2 - x, x + c1 < c2), x < c2 
- c1);
+    TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(c1 < x + c2, c1 - x < c2), c1 - c2 
< x);
+    TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(c1 < c2 - x, x + c1 < c2), x < c2 - 
c1);
     TVM_TRY_RECURSIVE_REWRITE(c1 < x - c2, c1 + c2 < x);
     TVM_TRY_RECURSIVE_REWRITE(x - c2 < c1, x < c1 + c2);
 
@@ -2040,10 +2039,10 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::AndNode* op,
                      cfalse, c2.Eval()->value > c1.Eval()->value);
 
   TVM_TRY_REWRITE((x == c1) && (x == c2), (x == c1) && (c1 == c2));
-  TVM_TRY_REWRITE(matches_one_of(x == c1 && x != c2, x != c2 && x == c1), x == 
c1 && c1 != c2);
+  TVM_TRY_REWRITE(MatchesOneOf(x == c1 && x != c2, x != c2 && x == c1), x == 
c1 && c1 != c2);
 
-  TVM_TRY_RECURSIVE_REWRITE(matches_one_of(floordiv(x, c2) == c1 && 
floormod(x, c2) == c3,
-                                           floormod(x, c2) == c3 && 
floordiv(x, c2) == c1),
+  TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(floordiv(x, c2) == c1 && floormod(x, 
c2) == c3,
+                                         floormod(x, c2) == c3 && floordiv(x, 
c2) == c1),
                             x == c1 * c2 + c3);
 
   TVM_TRY_RECURSIVE_REWRITE_IF((PMatchesOneOf{
@@ -2079,18 +2078,18 @@ UnchangedOr<PrimExpr> 
RewriteSimplifier::Impl::Mutate_(const prim::AndNode* op,
       (((c1.Eval()->value + 1) % c2.Eval()->value) + c2.Eval()->value) % 
c2.Eval()->value >
           c3.Eval()->value);
 
-  TVM_TRY_RECURSIVE_REWRITE(matches_one_of(floordiv(x, c2) == c1 && 
floormod(x, c2) < c3,
-                                           floormod(x, c2) < c3 && floordiv(x, 
c2) == c1),
+  TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(floordiv(x, c2) == c1 && floormod(x, 
c2) < c3,
+                                         floormod(x, c2) < c3 && floordiv(x, 
c2) == c1),
                             c1 * c2 <= x && x < c1 * c2 + c3);
-  TVM_TRY_RECURSIVE_REWRITE(matches_one_of(floordiv(x, c2) == c1 && 
floormod(x, c2) <= c3,
-                                           floormod(x, c2) <= c3 && 
floordiv(x, c2) == c1),
+  TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(floordiv(x, c2) == c1 && floormod(x, 
c2) <= c3,
+                                         floormod(x, c2) <= c3 && floordiv(x, 
c2) == c1),
                             c1 * c2 <= x && x <= c1 * c2 + c3);
 
-  TVM_TRY_RECURSIVE_REWRITE(matches_one_of(floordiv(x, c2) == c1 && c3 <= 
floormod(x, c2),
-                                           c3 <= floormod(x, c2) && 
floordiv(x, c2) == c1),
+  TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(floordiv(x, c2) == c1 && c3 <= 
floormod(x, c2),
+                                         c3 <= floormod(x, c2) && floordiv(x, 
c2) == c1),
                             c1 * c2 + c3 <= x && x < (c1 + 1) * c2);
-  TVM_TRY_RECURSIVE_REWRITE(matches_one_of(floordiv(x, c2) == c1 && c3 < 
floormod(x, c2),
-                                           c3 < floormod(x, c2) && floordiv(x, 
c2) == c1),
+  TVM_TRY_RECURSIVE_REWRITE(MatchesOneOf(floordiv(x, c2) == c1 && c3 < 
floormod(x, c2),
+                                         c3 < floormod(x, c2) && floordiv(x, 
c2) == c1),
                             c1 * c2 + c3 < x && x < (c1 + 1) * c2);
 
   TVM_TRY_RECURSIVE_REWRITE(x && (y && z), (x && y) && z);
diff --git a/src/sym/rewrite_simplify.h b/src/sym/rewrite_simplify.h
index a374f918..c54d25a9 100644
--- a/src/sym/rewrite_simplify.h
+++ b/src/sym/rewrite_simplify.h
@@ -27,6 +27,7 @@
 #include <tvm/ffi/reflection/registry.h>
 #include <tvm/ir/cow.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 
 #include <algorithm>
@@ -34,7 +35,6 @@
 #include <vector>
 
 #include "const_fold.h"
-#include "pattern_match.h"
 #include "simplify_base.h"
 
 namespace tvm {
diff --git a/src/sym/detect_linear_equation.cc 
b/src/tirx/analysis/linear_analysis.cc
similarity index 96%
rename from src/sym/detect_linear_equation.cc
rename to src/tirx/analysis/linear_analysis.cc
index 2199de96..08c3d0a4 100644
--- a/src/sym/detect_linear_equation.cc
+++ b/src/tirx/analysis/linear_analysis.cc
@@ -18,7 +18,7 @@
  */
 
 /*!
- * \file detect_linear_equation.cc
+ * \file linear_analysis.cc
  * \brief Utility to detect patterns in the expression.
  */
 #include <tvm/ffi/extra/structural_visit.h>
@@ -28,12 +28,12 @@
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
 #include <tvm/sym/analyzer.h>
-#include <tvm/sym/pattern.h>
+#include <tvm/tirx/analysis.h>
 
 #include <unordered_set>
 
 namespace tvm {
-namespace sym {
+namespace tirx {
 using namespace tvm::prim;
 
 // Linear equation, the components can be undefined.
@@ -226,7 +226,7 @@ bool DetectClipBound(const PrimExpr& cond,
     return false;
   }
   LinearEqEntry ret;
-  Analyzer analyzer;
+  sym::Analyzer analyzer;
   if (!LinearEqDetector(var.value()).Detect(canonical, &ret)) return false;
   ret.coeff = analyzer->Simplify(ret.coeff.value());
   IntervalEntry& p = bmap->at(var.value().get());
@@ -281,7 +281,7 @@ void SplitCommExpr(const PrimExpr& e, 
std::vector<PrimExpr>* ret) {
 ffi::Array<ffi::Optional<PrimExpr>> DetectClipBound(const PrimExpr& e,
                                                     const ffi::Array<PrimVar>& 
vars) {
   std::vector<PrimExpr> splits;
-  Analyzer analyzer;
+  sym::Analyzer analyzer;
   SplitCommExpr<prim::AndNode>(analyzer->Simplify(e), &splits);
   std::unordered_map<const VarNode*, IntervalEntry> rmap;
   for (PrimVar v : vars) {
@@ -308,10 +308,10 @@ ffi::Array<ffi::Optional<PrimExpr>> DetectClipBound(const 
PrimExpr& e,
 TVM_FFI_STATIC_INIT_BLOCK() {
   namespace refl = tvm::ffi::reflection;
   refl::GlobalDef()
-      .def("sym.DetectLinearEquation", DetectLinearEquation)
-      .def("sym.DetectClipBound", [](const PrimExpr& e, const 
ffi::Array<PrimVar>& vars) {
+      .def("tirx.analysis.DetectLinearEquation", DetectLinearEquation)
+      .def("tirx.analysis.DetectClipBound", [](const PrimExpr& e, const 
ffi::Array<PrimVar>& vars) {
         return DetectClipBound(e, vars);
       });
 }
-}  // namespace sym
+}  // namespace tirx
 }  // namespace tvm
diff --git a/src/tirx/ir/tensor.cc b/src/tirx/ir/tensor.cc
index a21d8917..00d08bfe 100644
--- a/src/tirx/ir/tensor.cc
+++ b/src/tirx/ir/tensor.cc
@@ -25,6 +25,7 @@
 #include <tvm/ir/expr.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/sym/analyzer.h>
 #include <tvm/tirx/analysis.h>
 #include <tvm/tirx/expr.h>
@@ -36,8 +37,6 @@
 #include <stack>
 #include <utility>
 
-#include "../../sym/pattern_match.h"
-
 namespace tvm {
 
 TensorRegion TensorRegion::FromTensorLoad(TensorLoad value) {
@@ -332,7 +331,7 @@ inline PrimExpr MergeMulMod(sym::AnalyzerObj* analyzer, 
const PrimExpr& base) {
   // The elements in the Mod will be used to match against the elements in Mul.
   // The result will then be split and pushed back to these two lists.
   PrimExpr simplified_base = base;
-  sym::PVar<PrimExpr> x, y;
+  tvm::PVar<PrimExpr> x, y;
   if ((floordiv(x, y) * y + floormod(x, y)).Match(simplified_base)) {
     simplified_base = x.Eval();
   }
diff --git a/src/tirx/op/math.cc b/src/tirx/op/math.cc
index 5f03e3d4..07b9999c 100644
--- a/src/tirx/op/math.cc
+++ b/src/tirx/op/math.cc
@@ -30,7 +30,7 @@ namespace tvm {
 namespace tirx {
 
 using namespace prim;
-using namespace prim::detail;
+using namespace prim::details;
 
 PrimExpr logaddexp(PrimExpr a, PrimExpr b, Location loc) {
   TVM_FFI_ICHECK(a.ty().MatchesCode(DLDataTypeCode::kDLFloat)) << a;
diff --git a/src/tirx/tile/lower.cc b/src/tirx/tile/lower.cc
index 06395251..05219ae0 100644
--- a/src/tirx/tile/lower.cc
+++ b/src/tirx/tile/lower.cc
@@ -30,7 +30,6 @@
 #include <tvm/ir/prim/op.h>
 #include <tvm/runtime/logging.h>
 #include <tvm/sym/analyzer.h>
-#include <tvm/sym/pattern.h>
 #include <tvm/target/target.h>
 #include <tvm/tirx/function.h>
 #include <tvm/tirx/op/annotation.h>
diff --git a/src/tirx/transform/lower_intrin.cc 
b/src/tirx/transform/lower_intrin.cc
index 73f4dc24..79e3b3f5 100644
--- a/src/tirx/transform/lower_intrin.cc
+++ b/src/tirx/transform/lower_intrin.cc
@@ -28,6 +28,7 @@
 #include <tvm/ir/op.h>
 #include <tvm/ir/prim/expr.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/runtime/logging.h>
 #include <tvm/target/target.h>
 #include <tvm/tirx/expr.h>
@@ -38,8 +39,6 @@
 #include <limits>
 #include <unordered_set>
 
-#include "../../sym/pattern_match.h"
-
 namespace tvm {
 namespace tirx {
 using namespace tvm::prim;
@@ -249,7 +248,6 @@ class IntrinInjecter : public StmtExprMutatorWithAnalyzer {
   }
 
   UnchangedOr<PrimExpr> Mutate_(const prim::MaxNode* op, InplaceMode 
inplace_mode) final {
-    using namespace sym;
     PVar<PrimExpr> x, y;
     PVar<IntImm> c;
     auto e = ffi::GetRef<PrimExpr>(op);
@@ -262,7 +260,6 @@ class IntrinInjecter : public StmtExprMutatorWithAnalyzer {
   }
 
   UnchangedOr<PrimExpr> Mutate_(const prim::EQNode* op, InplaceMode 
inplace_mode) final {
-    using namespace sym;
     PVar<PrimExpr> x, y;
     auto e = ffi::GetRef<PrimExpr>(op);
     if ((floormod(x, y) == 0).Match(e)) {
@@ -273,7 +270,6 @@ class IntrinInjecter : public StmtExprMutatorWithAnalyzer {
   }
 
   UnchangedOr<PrimExpr> Mutate_(const prim::NENode* op, InplaceMode 
inplace_mode) final {
-    using namespace sym;
     PVar<PrimExpr> x, y;
     auto e = ffi::GetRef<PrimExpr>(op);
     if ((floormod(x, y) != 0).Match(e)) {
diff --git a/src/tirx/transform/remove_no_op.cc 
b/src/tirx/transform/remove_no_op.cc
index 3fb1d69f..1ee38d43 100644
--- a/src/tirx/transform/remove_no_op.cc
+++ b/src/tirx/transform/remove_no_op.cc
@@ -33,7 +33,6 @@
 #include <tvm/tirx/stmt_functor_with_analyzer.h>
 #include <tvm/tirx/transform.h>
 
-#include "../../sym/const_fold.h"
 #include "ir_utils.h"
 
 namespace tvm {
@@ -120,7 +119,7 @@ class NoOpRemover : public StmtExprMutatorWithAnalyzer {
   UnchangedOr<Stmt> Mutate_(const ForNode* op, InplaceMode inplace_mode) final 
{
     auto extent_range =
         sym::EvalSet(Range::GetExtentFromBeginEnd(op->begin, op->end), 
var_range_map_);
-    if (!sym::is_neg_inf(extent_range.max()) && 
!sym::is_pos_inf(extent_range.max()) &&
+    if (!prim::is_neg_inf(extent_range.max()) && 
!prim::is_pos_inf(extent_range.max()) &&
         analyzer_->CanProve(extent_range.max() <= 0)) {
       return Evaluate(0);
     }
diff --git a/src/tirx/transform/renormalize_split_pattern.cc 
b/src/tirx/transform/renormalize_split_pattern.cc
index 0493c783..b52bab7b 100644
--- a/src/tirx/transform/renormalize_split_pattern.cc
+++ b/src/tirx/transform/renormalize_split_pattern.cc
@@ -24,11 +24,12 @@
 #include <tvm/ffi/function.h>
 #include <tvm/ffi/reflection/registry.h>
 #include <tvm/ir/prim/op.h>
+#include <tvm/ir/prim/pattern_match.h>
 #include <tvm/tirx/stmt.h>
 #include <tvm/tirx/stmt_functor_with_analyzer.h>
 #include <tvm/tirx/transform.h>
 
-#include "../../sym/pattern_match.h"
+#include "../../sym/int_operator.h"
 
 namespace tvm {
 namespace tirx {
diff --git a/tests/cpp/sym/pattern_match_test.cc 
b/tests/cpp/ir/pattern_match_test.cc
similarity index 94%
rename from tests/cpp/sym/pattern_match_test.cc
rename to tests/cpp/ir/pattern_match_test.cc
index 2683c398..24477477 100644
--- a/tests/cpp/sym/pattern_match_test.cc
+++ b/tests/cpp/ir/pattern_match_test.cc
@@ -17,19 +17,17 @@
  * under the License.
  */
 
-#include "../../../src/sym/pattern_match.h"
-
 #include <gtest/gtest.h>
 #include <tvm/ir/prim/expr.h>
+#include <tvm/ir/prim/pattern_match.h>
 
 TEST(Pattern, Basic) {
   using namespace tvm;
-  using namespace tvm::sym;
   tvm::PrimVar x("x"), y("y"), z("z");
   PrimExpr scalable_lanes = prim::Mul(Call(PrimType::Int(32), 
prim::vscale_op(), {}), 4);
-  sym::PVar<PrimExpr> px, py, pz;
-  sym::PVar<DLDataType> pt;
-  sym::PVar<PrimExpr> planes;
+  tvm::PVar<PrimExpr> px, py, pz;
+  tvm::PVar<DLDataType> pt;
+  tvm::PVar<PrimExpr> planes;
 
   // arithmetics
   auto r = 1 + (y + 1);
@@ -130,8 +128,8 @@ TEST(Pattern, Basic) {
 TEST(Pattern, IntImm) {
   using namespace tvm;
   PrimVar tx("tx"), ty("ty");
-  sym::PVar<IntImm> c;
-  sym::PVar<Var> v;
+  tvm::PVar<IntImm> c;
+  tvm::PVar<Var> v;
   {
     // We can match integer and Var, both of which are
     // special case container of Expr
@@ -148,7 +146,7 @@ TEST(Pattern, IntImm) {
 TEST(Pattern, MatchWithType) {
   using namespace tvm;
   // match expr with specified dtype
-  sym::PVarWithDataType<PrimExpr, sym::PConst<DLDataType>> 
pat(DLDataType{kDLFloat, 32, 1});
+  tvm::PVarWithDataType<PrimExpr, tvm::PConst<DLDataType>> 
pat(DLDataType{kDLFloat, 32, 1});
   PrimVar x("x", PrimType::Float(32));
   PrimVar y("y", PrimType::Float(32));
   PrimVar x_int("x", PrimType::Int(32));
@@ -157,8 +155,8 @@ TEST(Pattern, MatchWithType) {
   TVM_FFI_ICHECK(!pat.Match(x_int + y_int * 2));
 
   // match vectorized expr with specified element dtype
-  sym::PVecDataType vec_ty(DLDataType{kDLFloat, 32, 1});
-  sym::PVarWithDataType<PrimExpr, sym::PVecDataType> vpat(vec_ty);
+  tvm::PVecDataType vec_ty(DLDataType{kDLFloat, 32, 1});
+  tvm::PVarWithDataType<PrimExpr, tvm::PVecDataType> vpat(vec_ty);
   PrimVar vx("x", PrimType::Float(32, 8));
   PrimVar vy("y", PrimType::Float(32, 8));
   PrimVar vx_int("x", PrimType::Int(32, 8));
diff --git a/tests/cpp/sym/domain_map_test.cc b/tests/cpp/sym/domain_map_test.cc
index bf2c8ec4..8bd2b7cf 100644
--- a/tests/cpp/sym/domain_map_test.cc
+++ b/tests/cpp/sym/domain_map_test.cc
@@ -20,7 +20,6 @@
 #include <gtest/gtest.h>
 #include <tvm/ir/prim/op.h>
 #include <tvm/sym/analyzer.h>
-#include <tvm/sym/bound.h>
 #include <tvm/sym/int_set.h>
 
 namespace tvm {
diff --git a/tests/python/sym/test_detect_clip_bound.py 
b/tests/python/tirx/analysis/test_detect_clip_bound.py
similarity index 78%
rename from tests/python/sym/test_detect_clip_bound.py
rename to tests/python/tirx/analysis/test_detect_clip_bound.py
index 55143e84..6a2641b5 100644
--- a/tests/python/sym/test_detect_clip_bound.py
+++ b/tests/python/tirx/analysis/test_detect_clip_bound.py
@@ -22,19 +22,23 @@ def test_basic():
     a = tvm_tirx.tirx.Var("a", "int32")
     b = tvm_tirx.tirx.Var("b", "int32")
     c = tvm_tirx.tirx.Var("c", "int32")
-    m = tvm_tirx.sym.detect_clip_bound(tvm_tirx.tirx.all(a * 1 < b * 6, a - 1 
> 0), [a])
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(tvm_tirx.tirx.all(a * 1 < b * 
6, a - 1 > 0), [a])
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], b * 6 - 1)
     assert m[0].value == 2
-    m = tvm_tirx.sym.detect_clip_bound(tvm_tirx.tirx.all(a * 1 < b * 6, a - 1 
> 0), [a, b])
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(
+        tvm_tirx.tirx.all(a * 1 < b * 6, a - 1 > 0), [a, b]
+    )
     assert len(m) == 0
-    m = tvm_tirx.sym.detect_clip_bound(tvm_tirx.tirx.all(a + 10 * c <= 20, b - 
1 > 0), [a, b])
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(
+        tvm_tirx.tirx.all(a + 10 * c <= 20, b - 1 > 0), [a, b]
+    )
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], 20 - 10 * c)
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[2], 2)
-    m = tvm_tirx.sym.detect_clip_bound(
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(
         tvm_tirx.tirx.all(tvm_tirx.tirx.Not(a * 1 > b * 6), a - 1 > 0), [a]
     )
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], b * 6)
-    m = tvm_tirx.sym.detect_clip_bound(
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(
         tvm_tirx.tirx.all(tvm_tirx.tirx.Min(a, b) > 3, a - 10 < 0), [a, b]
     )
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[0], 4)
@@ -45,10 +49,10 @@ def test_basic():
 def test_trivial_eq():
     a = tvm_tirx.tirx.Var("a", "int32")
     b = tvm_tirx.tirx.Var("b", "int32")
-    m = tvm_tirx.sym.detect_clip_bound(b == 3, [a, b])
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(b == 3, [a, b])
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[2], 3)
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[3], 3)
-    m = tvm_tirx.sym.detect_clip_bound(tvm_tirx.tirx.all(a == 4, b == 3), [a, 
b])
+    m = tvm_tirx.tirx.analysis.detect_clip_bound(tvm_tirx.tirx.all(a == 4, b 
== 3), [a, b])
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[0], 4)
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], 4)
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[2], 3)
diff --git a/tests/python/sym/test_detect_linear_equation.py 
b/tests/python/tirx/analysis/test_detect_linear_equation.py
similarity index 65%
rename from tests/python/sym/test_detect_linear_equation.py
rename to tests/python/tirx/analysis/test_detect_linear_equation.py
index 151a8b93..d4706940 100644
--- a/tests/python/sym/test_detect_linear_equation.py
+++ b/tests/python/tirx/analysis/test_detect_linear_equation.py
@@ -21,58 +21,60 @@ import tvm_tirx.testing
 def test_basic():
     a = tvm_tirx.tirx.Var("a", "int32")
     b = tvm_tirx.tirx.Var("b", "int32")
-    m = tvm_tirx.sym.detect_linear_equation(a * 4 + b * 6 + 7, [a])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(a * 4 + b * 6 + 7, [a])
     assert m[0].value == 4
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], b * 6 + 7)
 
-    m = tvm_tirx.sym.detect_linear_equation(a * 4 * (a + 1) + b * 6 + 7, [a])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(a * 4 * (a + 1) + b * 6 
+ 7, [a])
     assert len(m) == 0
 
-    m = tvm_tirx.sym.detect_linear_equation(a * 4 + (a + 1) + b * 6 + 7, [a])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(a * 4 + (a + 1) + b * 6 
+ 7, [a])
     assert m[0].value == 5
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], b * 6 + 7 + 1)
 
-    m = tvm_tirx.sym.detect_linear_equation(a * b + 7, [a])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(a * b + 7, [a])
     assert m[0] == b
 
-    m = tvm_tirx.sym.detect_linear_equation(b * 7, [a])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(b * 7, [a])
     assert m[0].value == 0
 
-    m = tvm_tirx.sym.detect_linear_equation(b * 7, [])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(b * 7, [])
     assert len(m) == 1
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[0], b * 7)
 
     c = tvm_tirx.tirx.Var("c", "uint32")
-    m = tvm_tirx.sym.detect_linear_equation(128 - c, [c])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(128 - c, [c])
     assert m[0].value == -1
 
 
 def test_multivariate():
     v = [tvm_tirx.tirx.Var(f"v{i}", "int32") for i in range(4)]
     b = tvm_tirx.tirx.Var("b", "int32")
-    m = tvm_tirx.sym.detect_linear_equation(v[0] * (b + 4) + v[0] + v[1] * 8, 
v)
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(v[0] * (b + 4) + v[0] + 
v[1] * 8, v)
 
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[0], b + 5)
 
     assert m[1].value == 8
 
-    m = tvm_tirx.sym.detect_linear_equation(v[0] * (b + 4) + v[0] + v[1] * 8 * 
v[2], v)
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(v[0] * (b + 4) + v[0] + 
v[1] * 8 * v[2], v)
     assert len(m) == 0
 
-    m = tvm_tirx.sym.detect_linear_equation(v[0] * (b + 4) + v[0] + v[1] * 8 * 
v[1] + v[3], v)
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(
+        v[0] * (b + 4) + v[0] + v[1] * 8 * v[1] + v[3], v
+    )
     assert len(m) == 0
 
-    m = tvm_tirx.sym.detect_linear_equation(((v[0] * b + v[1]) * 8 + v[2] + 1) 
* 2, v)
+    m = tvm_tirx.tirx.analysis.detect_linear_equation(((v[0] * b + v[1]) * 8 + 
v[2] + 1) * 2, v)
     assert m[1].value == 16
     assert m[2].value == 2
     assert m[len(m) - 1].value == 2
 
-    m = tvm_tirx.sym.detect_linear_equation((v[0] - v[1]), [v[2]])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation((v[0] - v[1]), [v[2]])
     assert m[0].value == 0
 
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[1], v[0] - v[1])
 
-    m = tvm_tirx.sym.detect_linear_equation((v[0] - v[1]), [])
+    m = tvm_tirx.tirx.analysis.detect_linear_equation((v[0] - v[1]), [])
     assert len(m) == 1
     assert tvm_tirx.sym.Analyzer().can_prove_equal(m[0], v[0] - v[1])
 

Reply via email to