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

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


The following commit(s) were added to refs/heads/main by this push:
     new c7931c6200 [REFACTOR][IR] Add scalar integer expression signatures 
(#20521)
c7931c6200 is described below

commit c7931c6200924b1d049bf6ff5dd5d89613b537ca
Author: Tianqi Chen <[email protected]>
AuthorDate: Fri Oct 2 13:49:42 2026 -0400

    [REFACTOR][IR] Add scalar integer expression signatures (#20521)
    
    Introduce IntExpr as a scalar signed or unsigned integer view for
    operator signatures while retaining PrimExpr implementation APIs and
    integer literal conversions. Update tvm-ffi and simplify expression
    traits to use inherited casting with specialized semantic checks.
---
 3rdparty/tvm-ffi                                 |   2 +-
 include/tvm/ir/base_expr.h                       | 112 ++++++------
 src/backend/cuda/codegen/intrin_rule_cuda.cc     |  24 +--
 src/backend/cuda/op/iket.cc                      |   2 +-
 src/backend/cuda/op/target_builtin.cc            | 222 +++++++++++++----------
 src/backend/metal/codegen/intrin_rule_metal.cc   |   6 +-
 src/backend/metal/op/target_builtin.cc           |  30 +--
 src/backend/webgpu/codegen/intrin_rule_webgpu.cc |   6 +-
 src/relax/op/op.cc                               |  46 ++---
 src/relax/op/tensor/create.cc                    |   8 +-
 src/relax/op/tensor/inspect.cc                   |   4 +-
 src/relax/op/tensor/manipulate.cc                |  10 +-
 src/tirx/op/builtin.cc                           | 155 +++++++++-------
 src/tirx/op/op.cc                                |  15 +-
 tests/cpp/expr_test.cc                           |  21 +++
 tests/python/tirx-base/test_tir_op_types.py      |  11 ++
 16 files changed, 378 insertions(+), 296 deletions(-)

diff --git a/3rdparty/tvm-ffi b/3rdparty/tvm-ffi
index c96f9e31b2..df463f9bd2 160000
--- a/3rdparty/tvm-ffi
+++ b/3rdparty/tvm-ffi
@@ -1 +1 @@
-Subproject commit c96f9e31b279ddfecf543539263c0f3e082feeeb
+Subproject commit df463f9bd269867fc7f4d578d62d80cc2a11d004
diff --git a/include/tvm/ir/base_expr.h b/include/tvm/ir/base_expr.h
index 87855537b4..4302a570b2 100644
--- a/include/tvm/ir/base_expr.h
+++ b/include/tvm/ir/base_expr.h
@@ -427,6 +427,18 @@ class PrimExpr : public TypedExpr<PrimType> {
   static constexpr bool _type_container_is_exact = false;
 };
 
+/*!
+ * \brief View over a scalar signed or unsigned integer expression of any bit 
width.
+ *
+ * IntExpr validates integer operands in operator signatures without changing 
the
+ * underlying expression node or its PrimExpr implementation API.
+ */
+class IntExpr : public PrimExpr {
+ public:
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(IntExpr, PrimExpr, ExprNode);
+  static constexpr bool _type_container_is_exact = false;
+};
+
 /*!
  * \brief Base class for other IR constructs that can be converted to PrimExpr.
  * This is useful for the FFI to convert the expressions to PrimExpr.
@@ -464,15 +476,6 @@ inline constexpr bool 
use_default_type_traits_v<TypedExpr<ExpectedType>> = false
 template <typename ExpectedType>
 struct TypeTraits<TypedExpr<ExpectedType>>
     : public ObjectRefTypeTraitsBase<TypedExpr<ExpectedType>> {
-  using Base = ObjectRefTypeTraitsBase<TypedExpr<ExpectedType>>;
-  using Base::CopyFromAnyViewAfterCheck;
-  using Base::CopyToAnyView;
-  using Base::GetMismatchTypeInfo;
-  using Base::MoveFromAnyAfterCheck;
-  using Base::MoveToAny;
-  using Base::TypeSchema;
-  using Base::TypeStr;
-
   TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
     if (src->type_index == TypeIndex::kTVMFFINone) {
       return TypedExpr<ExpectedType>::_type_is_nullable;
@@ -484,58 +487,25 @@ struct TypeTraits<TypedExpr<ExpectedType>>
     // Non-owning: this only reads `ty`, and the owning form's incref/decref 
pair costs two
     // atomics per check on a path every typed field assignment takes.
     const auto* expr = 
details::ObjectUnsafe::RawObjectPtrFromUnowned<ExprNode>(src->v_obj);
-    return 
details::AnyUnsafe::CheckAnyViewStrict<ExpectedType>(AnyView(expr->ty));
-  }
-
-  TVM_FFI_INLINE static std::optional<TypedExpr<ExpectedType>> 
TryCastFromAnyView(
-      const TVMFFIAny* src) {
-    if (CheckAnyStrict(src)) {
-      if (src->type_index == TypeIndex::kTVMFFINone) {
-        return 
details::ObjectUnsafe::ObjectRefFromObjectPtr<TypedExpr<ExpectedType>>(nullptr);
-      }
-      return 
details::ObjectUnsafe::ObjectRefFromObjectPtr<TypedExpr<ExpectedType>>(
-          details::ObjectUnsafe::ObjectPtrFromUnowned<ExprNode>(src->v_obj));
-    }
-    return std::nullopt;
+    return details::AnyUnsafe::CheckAnyViewStrict<ExpectedType>(expr->ty);
   }
 };
 
 template <>
 inline constexpr bool use_default_type_traits_v<PrimExpr> = false;
 
-template <typename ObjectRefType, typename ExpectedType, typename... 
FallbackTypes>
-struct TypedExprWithFallbackTraitsBase
-    : public ObjectRefWithFallbackTraitsBase<ObjectRefType, FallbackTypes...> {
-  using Base = ObjectRefWithFallbackTraitsBase<ObjectRefType, 
FallbackTypes...>;
-
-  TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
-    return TypeTraits<TypedExpr<ExpectedType>>::CheckAnyStrict(src);
-  }
-
-  TVM_FFI_INLINE static std::optional<ObjectRefType> TryCastFromAnyView(const 
TVMFFIAny* src) {
-    if (TypeTraits<TypedExpr<ExpectedType>>::TryCastFromAnyView(src)) {
-      return details::ObjectUnsafe::ObjectRefFromObjectPtr<ObjectRefType>(
-          details::ObjectUnsafe::ObjectPtrFromUnowned<ExprNode>(src->v_obj));
-    }
-    return Base::template TryFallbackTypes<FallbackTypes...>(src);
-  }
-};
-
 // define automatic conversion from bool, int64_t, double to PrimExpr
 // These functions are declared early to avoid circular dependency
 template <>
-struct TypeTraits<PrimExpr>
-    : public TypedExprWithFallbackTraitsBase<PrimExpr, PrimType, StrictBool, 
int64_t, double,
-                                             PrimExprConvertible> {
-  using Base = TypedExprWithFallbackTraitsBase<PrimExpr, PrimType, StrictBool, 
int64_t, double,
-                                               PrimExprConvertible>;
-  using Base::CheckAnyStrict;
-  using Base::CopyFromAnyViewAfterCheck;
-  using Base::CopyToAnyView;
-  using Base::MoveFromAnyAfterCheck;
-  using Base::MoveToAny;
-  using Base::TryCastFromAnyView;
-  using Base::TypeSchema;
+struct TypeTraits<PrimExpr> : public ObjectRefWithFallbackTraitsBase<PrimExpr, 
StrictBool, int64_t,
+                                                                     double, 
PrimExprConvertible> {
+  using Base =
+      ObjectRefWithFallbackTraitsBase<PrimExpr, StrictBool, int64_t, double, 
PrimExprConvertible>;
+
+  TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
+    if (src->type_index == TypeIndex::kTVMFFINone) return 
PrimExpr::_type_is_nullable;
+    return TypeTraits<TypedExpr<PrimType>>::CheckAnyStrict(src);
+  }
 
   TVM_FFI_INLINE static std::string TypeStr() { return "ir.PrimExpr"; }
 
@@ -543,8 +513,7 @@ struct TypeTraits<PrimExpr>
     if (source->type_index >= TypeIndex::kTVMFFIStaticObjectBegin && 
source->v_obj != nullptr &&
         details::IsObjectInstance<ExprNode>(source->type_index)) {
       const auto* expr = 
details::ObjectUnsafe::RawObjectPtrFromUnowned<ExprNode>(source->v_obj);
-      if (expr->ty.defined() &&
-          
!details::AnyUnsafe::CheckAnyViewStrict<PrimType>(AnyView(expr->ty))) {
+      if (expr->ty.defined() && 
!details::AnyUnsafe::CheckAnyViewStrict<PrimType>(expr->ty)) {
         return TypeIndexToTypeKey(source->type_index) + "[ty=" + 
expr->ty.GetTypeKey() + "]";
       }
     }
@@ -559,6 +528,41 @@ struct TypeTraits<PrimExpr>
   }
 };
 
+template <>
+inline constexpr bool use_default_type_traits_v<IntExpr> = false;
+
+template <>
+struct TypeTraits<IntExpr> : public ObjectRefWithFallbackTraitsBase<IntExpr, 
int64_t> {
+  using Base = ObjectRefWithFallbackTraitsBase<IntExpr, int64_t>;
+
+  TVM_FFI_INLINE static bool CheckAnyStrict(const TVMFFIAny* src) {
+    if (!Base::CheckAnyStrict(src)) return false;
+    if (src->type_index == TypeIndex::kTVMFFINone) return true;
+    const auto* expr = 
details::ObjectUnsafe::RawObjectPtrFromUnowned<ExprNode>(src->v_obj);
+    const auto* ty = expr->ty.as<PrimTypeNode>();
+    return ty != nullptr && ty->dtype.lanes == 1 &&
+           (ty->dtype.code == kDLInt || ty->dtype.code == kDLUInt);
+  }
+
+  TVM_FFI_INLINE static IntExpr ConvertFallbackValue(int64_t value) {
+    return 
TypeTraits<PrimExpr>::ConvertFallbackValue(value).as_or_throw<IntExpr>();
+  }
+
+  TVM_FFI_INLINE static std::string TypeStr() { return "ir.IntExpr"; }
+
+  TVM_FFI_INLINE static std::string GetMismatchTypeInfo(const TVMFFIAny* src) {
+    if (src->type_index >= TypeIndex::kTVMFFIStaticObjectBegin &&
+        details::IsObjectInstance<ExprNode>(src->type_index)) {
+      const auto* expr = 
details::ObjectUnsafe::RawObjectPtrFromUnowned<ExprNode>(src->v_obj);
+      if (const auto* ty = expr->ty.as<PrimTypeNode>()) {
+        return TypeIndexToTypeKey(src->type_index) +
+               "[dtype=" + ffi::DLDataTypeToString(ty->dtype) + "]";
+      }
+    }
+    return TypeTraits<PrimExpr>::GetMismatchTypeInfo(src);
+  }
+};
+
 template <>
 inline constexpr bool use_default_type_traits_v<Expr> = false;
 
diff --git a/src/backend/cuda/codegen/intrin_rule_cuda.cc 
b/src/backend/cuda/codegen/intrin_rule_cuda.cc
index bbbbcca4f7..8b9a96b929 100644
--- a/src/backend/cuda/codegen/intrin_rule_cuda.cc
+++ b/src/backend/cuda/codegen/intrin_rule_cuda.cc
@@ -281,10 +281,10 @@ void RegisterCudaIntrinRules() {
   // Register low-level CUDA device intrinsics.
   // TODO(tvm-team): consider make CUDA its own subfolder and create a file 
for low-level builtins.
   OpDef("tirx.cuda.__shfl_sync")
-      .signature(sig::arg("mask", "The thread mask."),
+      .signature(sig::arg<IntExpr>("mask", "The thread mask."),
           sig::arg("var", "The variable to sync."),
-          sig::arg("lane", "The source thread id."),
-          sig::arg("width", "The warp thread width, must be a power of 2."))
+          sig::arg<IntExpr>("lane", "The source thread id."),
+          sig::arg<IntExpr>("width", "The warp thread width, must be a power 
of 2."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("cuda"))
@@ -295,10 +295,10 @@ void RegisterCudaIntrinRules() {
       .set_attr<bool>("cuda.need_warp_shuffle", true);
 
   OpDef("tirx.cuda.__shfl_up_sync")
-      .signature(sig::arg("mask", "The thread mask."),
+      .signature(sig::arg<IntExpr>("mask", "The thread mask."),
           sig::arg("var", "The variable to sync."),
-          sig::arg("delta", "The source lane id offset to be added."),
-          sig::arg("width", "The warp thread width, must be a power of 2."))
+          sig::arg<IntExpr>("delta", "The source lane id offset to be added."),
+          sig::arg<IntExpr>("width", "The warp thread width, must be a power 
of 2."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("cuda"))
@@ -309,10 +309,10 @@ void RegisterCudaIntrinRules() {
       .set_attr<bool>("cuda.need_warp_shuffle", true);
 
   OpDef("tirx.cuda.__shfl_down_sync")
-      .signature(sig::arg("mask", "The thread mask."),
+      .signature(sig::arg<IntExpr>("mask", "The thread mask."),
           sig::arg("var", "The variable to sync."),
-          sig::arg("delta", "The source lane id offset to be subtracted."),
-          sig::arg("width", "The warp thread width, must be a power of 2."))
+          sig::arg<IntExpr>("delta", "The source lane id offset to be 
subtracted."),
+          sig::arg<IntExpr>("width", "The warp thread width, must be a power 
of 2."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("cuda"))
@@ -323,10 +323,10 @@ void RegisterCudaIntrinRules() {
       .set_attr<bool>("cuda.need_warp_shuffle", true);
 
   OpDef("tirx.cuda.__shfl_xor_sync")
-      .signature(sig::arg("mask", "The thread mask."),
+      .signature(sig::arg<IntExpr>("mask", "The thread mask."),
           sig::arg("var", "The variable to sync."),
-          sig::arg("lane_mask", "The lane mask."),
-          sig::arg("width", "The warp thread width, must be a power of 2."))
+          sig::arg<IntExpr>("lane_mask", "The lane mask."),
+          sig::arg<IntExpr>("width", "The warp thread width, must be a power 
of 2."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("cuda"))
diff --git a/src/backend/cuda/op/iket.cc b/src/backend/cuda/op/iket.cc
index 0186402fa4..2e8c4fdcb4 100644
--- a/src/backend/cuda/op/iket.cc
+++ b/src/backend/cuda/op/iket.cc
@@ -45,7 +45,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.cuda.iket_range_end")
-      .signature(sig::arg("token", "The token."), sig::var_args("args"))
+      .signature(sig::arg<IntExpr>("token", "The token."), 
sig::var_args("args"))
       .set_attr<TFixedReturnType>("TFixedReturnType", PrimType::Void())
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("device_intrin"))
       .set_attr<TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("cuda"))
diff --git a/src/backend/cuda/op/target_builtin.cc 
b/src/backend/cuda/op/target_builtin.cc
index 73b511e96a..4ac2b7b8ee 100644
--- a/src/backend/cuda/op/target_builtin.cc
+++ b/src/backend/cuda/op/target_builtin.cc
@@ -61,48 +61,57 @@ void RegisterCudaTargetBuiltins() {
   registered = true;
 
   OpDef("tirx.tvm_load_matrix_sync")
-      .signature(sig::arg("fragment", "The matrix fragment."), sig::arg("m", 
"The M dimension."),
-                 sig::arg("n", "The N dimension."), sig::arg("k", "The K 
dimension."),
-                 sig::arg("index", "The index."), sig::arg("buffer_ptr", "The 
buffer pointer."),
-                 sig::arg("stride", "The stride."), sig::arg("layout", "The 
layout."))
+      .signature(
+          sig::arg("fragment", "The matrix fragment."), sig::arg<IntExpr>("m", 
"The M dimension."),
+          sig::arg<IntExpr>("n", "The N dimension."), sig::arg<IntExpr>("k", 
"The K dimension."),
+          sig::arg<IntExpr>("index", "The index."), sig::arg("buffer_ptr", 
"The buffer pointer."),
+          sig::arg<IntExpr>("stride", "The stride."), sig::arg("layout", "The 
layout."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_load_matrix_sync"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind",
                                  
static_cast<int64_t>(CallEffectKind::kReadState));
 
   OpDef("tirx.tvm_mma_sync")
-      .signature(
-          sig::arg("fragment_d", "The D fragment."), sig::arg("index_d", "The 
D fragment index."),
-          sig::arg("fragment_a", "The A fragment."), sig::arg("index_a", "The 
A fragment index."),
-          sig::arg("fragment_b", "The B fragment."), sig::arg("index_b", "The 
B fragment index."),
-          sig::arg("fragment_c", "The C fragment."), sig::arg("index_c", "The 
C fragment index."))
+      .signature(sig::arg("fragment_d", "The D fragment."),
+                 sig::arg<IntExpr>("index_d", "The D fragment index."),
+                 sig::arg("fragment_a", "The A fragment."),
+                 sig::arg<IntExpr>("index_a", "The A fragment index."),
+                 sig::arg("fragment_b", "The B fragment."),
+                 sig::arg<IntExpr>("index_b", "The B fragment index."),
+                 sig::arg("fragment_c", "The C fragment."),
+                 sig::arg<IntExpr>("index_c", "The C fragment index."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_mma_sync"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_bmma_sync")
-      .signature(
-          sig::arg("fragment_d", "The D fragment."), sig::arg("index_d", "The 
D fragment index."),
-          sig::arg("fragment_a", "The A fragment."), sig::arg("index_a", "The 
A fragment index."),
-          sig::arg("fragment_b", "The B fragment."), sig::arg("index_b", "The 
B fragment index."),
-          sig::arg("fragment_c", "The C fragment."), sig::arg("index_c", "The 
C fragment index."))
+      .signature(sig::arg("fragment_d", "The D fragment."),
+                 sig::arg<IntExpr>("index_d", "The D fragment index."),
+                 sig::arg("fragment_a", "The A fragment."),
+                 sig::arg<IntExpr>("index_a", "The A fragment index."),
+                 sig::arg("fragment_b", "The B fragment."),
+                 sig::arg<IntExpr>("index_b", "The B fragment index."),
+                 sig::arg("fragment_c", "The C fragment."),
+                 sig::arg<IntExpr>("index_c", "The C fragment index."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_bmma_sync"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_fill_fragment")
-      .signature(sig::arg("fragment", "The matrix fragment."), sig::arg("m", 
"The M dimension."),
-                 sig::arg("n", "The N dimension."), sig::arg("k", "The K 
dimension."),
-                 sig::arg("index", "The index."), sig::arg("value", "The value 
to use."))
+      .signature(
+          sig::arg("fragment", "The matrix fragment."), sig::arg<IntExpr>("m", 
"The M dimension."),
+          sig::arg<IntExpr>("n", "The N dimension."), sig::arg<IntExpr>("k", 
"The K dimension."),
+          sig::arg<IntExpr>("index", "The index."), sig::arg("value", "The 
value to use."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_fill_fragment"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_store_matrix_sync")
-      .signature(sig::arg("fragment", "The matrix fragment."), sig::arg("m", 
"The M dimension."),
-                 sig::arg("n", "The N dimension."), sig::arg("k", "The K 
dimension."),
-                 sig::arg("index", "The index."), sig::arg("buffer_ptr", "The 
buffer pointer."),
-                 sig::arg("stride", "The stride."), sig::arg("layout", "The 
layout."))
+      .signature(
+          sig::arg("fragment", "The matrix fragment."), sig::arg<IntExpr>("m", 
"The M dimension."),
+          sig::arg<IntExpr>("n", "The N dimension."), sig::arg<IntExpr>("k", 
"The K dimension."),
+          sig::arg<IntExpr>("index", "The index."), sig::arg("buffer_ptr", 
"The buffer pointer."),
+          sig::arg<IntExpr>("stride", "The stride."), sig::arg("layout", "The 
layout."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_store_matrix_sync"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
@@ -113,18 +122,20 @@ void RegisterCudaTargetBuiltins() {
   // to its thread-local index. Used by the s_tir tensor_intrin tensorize
   // path so per-thread fragment offsets stay element-accurate.
   OpDef("tirx.mma_store_legacy")
-      .signature(sig::arg("m", "The M dimension."), sig::arg("n", "The N 
dimension."),
+      .signature(sig::arg<IntExpr>("m", "The M dimension."),
+                 sig::arg<IntExpr>("n", "The N dimension."),
                  sig::arg("dst_ptr", "The destination pointer."),
                  sig::arg("src_ptr", "The source pointer."),
-                 sig::arg("src_offset", "The source offset."),
-                 sig::arg("dst_stride", "The destination stride."))
+                 sig::arg<IntExpr>("src_offset", "The source offset."),
+                 sig::arg<IntExpr>("dst_stride", "The destination stride."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.mma_store_legacy"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.mma_fill_legacy")
-      .signature(sig::arg("local_size", "The local allocation size."),
-                 sig::arg("local_ptr", "The local pointer."), 
sig::arg("offset", "The offset."))
+      .signature(sig::arg<IntExpr>("local_size", "The local allocation size."),
+                 sig::arg("local_ptr", "The local pointer."),
+                 sig::arg<IntExpr>("offset", "The offset."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.mma_fill_legacy"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
@@ -134,10 +145,10 @@ void RegisterCudaTargetBuiltins() {
   // and prints it dtype-first; user-issued copies go through T.ptx instead.
   OpDef("tirx.s_tir.cp_async_raw")
       .signature(sig::arg("dst_ptr", "The destination pointer."),
-                 sig::arg("dst_offset", "The destination offset."),
+                 sig::arg<IntExpr>("dst_offset", "The destination offset."),
                  sig::arg("src_ptr", "The source pointer."),
-                 sig::arg("src_offset", "The source offset."),
-                 sig::arg("cp_size", "The copy size."), sig::var_args("args"))
+                 sig::arg<IntExpr>("src_offset", "The source offset."),
+                 sig::arg<IntExpr>("cp_size", "The copy size."), 
sig::var_args("args"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("device_intrin"))
       .set_attr<TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("s_tir"))
@@ -146,11 +157,12 @@ void RegisterCudaTargetBuiltins() {
                                            
static_cast<int64_t>(ScriptDtypePrintLocation::kFirst));
 
   OpDef("tirx.mma_store")
-      .signature(sig::arg("m", "The M dimension."), sig::arg("n", "The N 
dimension."),
+      .signature(sig::arg<IntExpr>("m", "The M dimension."),
+                 sig::arg<IntExpr>("n", "The N dimension."),
                  sig::arg("dst_ptr", "The destination pointer."),
                  sig::arg("src_ptr", "The source pointer."),
-                 sig::arg("src_offset", "The source offset."),
-                 sig::arg("dst_stride", "The destination stride."))
+                 sig::arg<IntExpr>("src_offset", "The source offset."),
+                 sig::arg<IntExpr>("dst_stride", "The destination stride."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.mma_store"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque))
@@ -158,8 +170,9 @@ void RegisterCudaTargetBuiltins() {
                                            
static_cast<int64_t>(ScriptDtypePrintLocation::kFirst));
 
   OpDef("tirx.mma_fill")
-      .signature(sig::arg("local_size", "The local allocation size."),
-                 sig::arg("local_ptr", "The local pointer."), 
sig::arg("offset", "The offset."))
+      .signature(sig::arg<IntExpr>("local_size", "The local allocation size."),
+                 sig::arg("local_ptr", "The local pointer."),
+                 sig::arg<IntExpr>("offset", "The offset."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.mma_fill"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque))
@@ -169,9 +182,9 @@ void RegisterCudaTargetBuiltins() {
   OpDef("tirx.timer_init_cuda")
       .signature(sig::arg("profiler_buffer", "The profiler buffer."),
                  sig::arg("profiler_tag", "The profiler tag."),
-                 sig::arg("profiler_write_offset", "The profiler write 
offset."),
-                 sig::arg("num_groups", "The number of groups."),
-                 sig::arg("group_id", "The group identifier."))
+                 sig::arg<IntExpr>("profiler_write_offset", "The profiler 
write offset."),
+                 sig::arg<IntExpr>("num_groups", "The number of groups."),
+                 sig::arg<IntExpr>("group_id", "The group identifier."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.timer_init"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
@@ -180,8 +193,8 @@ void RegisterCudaTargetBuiltins() {
       .signature(sig::arg("event_type", "The event type."),
                  sig::arg("profiler_buffer", "The profiler buffer."),
                  sig::arg("profiler_tag", "The profiler tag."),
-                 sig::arg("profiler_write_offset", "The profiler write 
offset."),
-                 sig::arg("profiler_write_stride", "The profiler write 
stride."),
+                 sig::arg<IntExpr>("profiler_write_offset", "The profiler 
write offset."),
+                 sig::arg<IntExpr>("profiler_write_stride", "The profiler 
write stride."),
                  sig::arg("leader_cond", "The leader condition."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.timer_start"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -191,8 +204,8 @@ void RegisterCudaTargetBuiltins() {
       .signature(sig::arg("event_type", "The event type."),
                  sig::arg("profiler_buffer", "The profiler buffer."),
                  sig::arg("profiler_tag", "The profiler tag."),
-                 sig::arg("profiler_write_offset", "The profiler write 
offset."),
-                 sig::arg("profiler_write_stride", "The profiler write 
stride."),
+                 sig::arg<IntExpr>("profiler_write_offset", "The profiler 
write offset."),
+                 sig::arg<IntExpr>("profiler_write_stride", "The profiler 
write stride."),
                  sig::arg("leader_cond", "The leader condition."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.timer_end"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -201,8 +214,8 @@ void RegisterCudaTargetBuiltins() {
   OpDef("tirx.timer_finalize_cuda")
       .signature(sig::arg("profiler_buffer", "The profiler buffer."),
                  sig::arg("profiler_tag", "The profiler tag."),
-                 sig::arg("profiler_write_offset", "The profiler write 
offset."),
-                 sig::arg("profiler_write_stride", "The profiler write 
stride."),
+                 sig::arg<IntExpr>("profiler_write_offset", "The profiler 
write offset."),
+                 sig::arg<IntExpr>("profiler_write_stride", "The profiler 
write stride."),
                  sig::arg("leader_cond", "The leader condition."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.cuda.timer_finalize"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -261,7 +274,7 @@ void RegisterDeviceIntrinsic(const char* op_name, const 
char* op_namespace,
 }
 
 void RegisterDeviceIntrinsicAliases() {
-  RegisterDeviceIntrinsic("cuda_any_sync", "cuda", CallEffectKind::kPure, 
sig::arg("mask"),
+  RegisterDeviceIntrinsic("cuda_any_sync", "cuda", CallEffectKind::kPure, 
sig::arg<IntExpr>("mask"),
                           sig::arg("pred"));
   RegisterDeviceIntrinsic("cuda_atomic_add", "cuda", CallEffectKind::kOpaque, 
sig::arg("res_addr"),
                           sig::arg("value"));
@@ -269,16 +282,16 @@ void RegisterDeviceIntrinsicAliases() {
                           sig::arg("old_val"), sig::arg("new_val"));
   RegisterDeviceIntrinsic("cuda_wait_until", "cuda", CallEffectKind::kOpaque, 
sig::arg("dst"),
                           sig::arg("ptr"), sig::arg("condition"), 
sig::arg("scope"),
-                          sig::arg("space"), sig::arg("ptx_type"), 
sig::arg("backoff_ns"));
-  RegisterDeviceIntrinsic("cuda_ballot_sync", "cuda", CallEffectKind::kOpaque, 
sig::arg("mask"),
-                          sig::arg("pred"));
+                          sig::arg("space"), sig::arg("ptx_type"), 
sig::arg<IntExpr>("backoff_ns"));
+  RegisterDeviceIntrinsic("cuda_ballot_sync", "cuda", CallEffectKind::kOpaque,
+                          sig::arg<IntExpr>("mask"), sig::arg("pred"));
   RegisterDeviceIntrinsic("cuda_bfloat1622float2", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("packed"));
   RegisterDeviceIntrinsic("cuda_bfloat162float", "cuda", 
CallEffectKind::kOpaque, sig::arg("src"));
   RegisterDeviceIntrinsic("cuda_clock64", "cuda", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("cuda_cluster_sync", "cuda", 
CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("cuda_cta_reduce", "cuda", CallEffectKind::kOpaque, 
sig::arg("value"),
-                          sig::arg("op"), sig::arg("num_warps"), 
sig::arg("scratch"));
+                          sig::arg("op"), sig::arg<IntExpr>("num_warps"), 
sig::arg("scratch"));
   RegisterDeviceIntrinsic("cuda_cta_sync", "cuda", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("cuda_cvta_generic_to_shared", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("ptr"));
@@ -287,7 +300,8 @@ void RegisterDeviceIntrinsicAliases() {
                           sig::arg("b"));
   RegisterDeviceIntrinsic("cuda_fdividef", "cuda", CallEffectKind::kPure, 
sig::arg("x"),
                           sig::arg("y"));
-  RegisterDeviceIntrinsic("cuda_ffs_u32", "cuda", CallEffectKind::kOpaque, 
sig::arg("value"));
+  RegisterDeviceIntrinsic("cuda_ffs_u32", "cuda", CallEffectKind::kOpaque,
+                          sig::arg<IntExpr>("value"));
   RegisterDeviceIntrinsic("cuda_float22bfloat162_rn", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("v0"), sig::arg("v1"));
   RegisterDeviceIntrinsic("cuda_float22bfloat162_rn_from_float2", "cuda", 
CallEffectKind::kOpaque,
@@ -306,7 +320,7 @@ void RegisterDeviceIntrinsicAliases() {
   RegisterDeviceIntrinsic("cuda_func_call", "cuda", CallEffectKind::kOpaque, 
sig::arg("func_name"),
                           sig::var_args("args"));
   RegisterDeviceIntrinsic("cuda_get_tmem_addr", "cuda", 
CallEffectKind::kOpaque, sig::arg("addr"),
-                          sig::arg("row_offset"), sig::arg("col_offset"));
+                          sig::arg<IntExpr>("row_offset"), 
sig::arg<IntExpr>("col_offset"));
   RegisterDeviceIntrinsic("cuda_grid_sync", "cuda", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("cuda_half2float", "cuda", CallEffectKind::kOpaque, 
sig::arg("src"));
   RegisterDeviceIntrinsic("cuda_half8tofloat8", "cuda", 
CallEffectKind::kOpaque,
@@ -319,102 +333,110 @@ void RegisterDeviceIntrinsicAliases() {
   RegisterDeviceIntrinsic("cuda_make_float2", "cuda", CallEffectKind::kOpaque, 
sig::arg("x"),
                           sig::arg("y"));
   RegisterDeviceIntrinsic("cuda_mbarrier_wait", "cuda", 
CallEffectKind::kOpaque, sig::arg("bar"),
-                          sig::arg("phase"));
+                          sig::arg<IntExpr>("phase"));
   RegisterDeviceIntrinsic("cuda_mbarrier_wait_acquire_cluster", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("bar"), sig::arg("phase"));
-  RegisterDeviceIntrinsic("cuda_mov_sreg", "cuda", CallEffectKind::kPure, 
sig::arg("bits"),
+                          sig::arg("bar"), sig::arg<IntExpr>("phase"));
+  RegisterDeviceIntrinsic("cuda_mov_sreg", "cuda", CallEffectKind::kPure, 
sig::arg<IntExpr>("bits"),
                           sig::arg("reg_name"));
-  RegisterDeviceIntrinsic("cuda_nano_sleep", "cuda", CallEffectKind::kOpaque, 
sig::arg("time"));
+  RegisterDeviceIntrinsic("cuda_nano_sleep", "cuda", CallEffectKind::kOpaque,
+                          sig::arg<IntExpr>("time"));
   RegisterDeviceIntrinsic("cuda_printf", "cuda", CallEffectKind::kOpaque, 
sig::arg("fmt"),
                           sig::var_args("args"));
   RegisterDeviceIntrinsic("cuda_reduce_add_sync_u32", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("mask"), sig::arg("value"));
+                          sig::arg<IntExpr>("mask"), 
sig::arg<IntExpr>("value"));
   RegisterDeviceIntrinsic("cuda_reduce_min_sync_u32", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("mask"), sig::arg("value"));
+                          sig::arg<IntExpr>("mask"), 
sig::arg<IntExpr>("value"));
   RegisterDeviceIntrinsic("cuda_runtime_instr_desc", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("desc"), sig::arg("sf_id"));
+                          sig::arg("desc"), sig::arg<IntExpr>("sf_id"));
   RegisterDeviceIntrinsic("cuda_sm100_2sm_leader_smem_addr", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("ptr"));
   RegisterDeviceIntrinsic("cuda_smem_addr_from_uint64", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("cluster_addr"));
+                          sig::arg<IntExpr>("cluster_addr"));
   RegisterDeviceIntrinsic("cuda_syncthreads_and", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("cond"));
   RegisterDeviceIntrinsic("cuda_syncthreads_or", "cuda", 
CallEffectKind::kOpaque, sig::arg("cond"));
-  RegisterDeviceIntrinsic(
-      "cuda_tcgen05_encode_instr_descriptor", "cuda", CallEffectKind::kOpaque, 
sig::arg("desc"),
-      sig::arg("d_dtype"), sig::arg("a_dtype"), sig::arg("b_dtype"), 
sig::arg("M"), sig::arg("N"),
-      sig::arg("K"), sig::arg("trans_a"), sig::arg("trans_b"), 
sig::arg("n_cta_groups"),
-      sig::arg("neg_a"), sig::arg("neg_b"), sig::arg("sat_d"), 
sig::arg("is_sparse"));
+  RegisterDeviceIntrinsic("cuda_tcgen05_encode_instr_descriptor", "cuda", 
CallEffectKind::kOpaque,
+                          sig::arg("desc"), sig::arg("d_dtype"), 
sig::arg("a_dtype"),
+                          sig::arg("b_dtype"), sig::arg<IntExpr>("M"), 
sig::arg<IntExpr>("N"),
+                          sig::arg<IntExpr>("K"), sig::arg("trans_a"), 
sig::arg("trans_b"),
+                          sig::arg<IntExpr>("n_cta_groups"), 
sig::arg("neg_a"), sig::arg("neg_b"),
+                          sig::arg("sat_d"), sig::arg("is_sparse"));
   RegisterDeviceIntrinsic("cuda_tcgen05_encode_instr_descriptor_block_scaled", 
"cuda",
                           CallEffectKind::kOpaque, sig::arg("desc"), 
sig::arg("d_dtype"),
                           sig::arg("a_dtype"), sig::arg("b_dtype"), 
sig::arg("sfa_dtype"),
                           sig::arg("sfb_dtype"), sig::arg("sfa_tmem_addr"),
-                          sig::arg("sfb_tmem_addr"), sig::arg("M"), 
sig::arg("N"), sig::arg("K"),
-                          sig::arg("trans_a"), sig::arg("trans_b"), 
sig::arg("n_cta_groups"),
-                          sig::arg("neg_a"), sig::arg("neg_b"), 
sig::arg("is_sparse"));
+                          sig::arg("sfb_tmem_addr"), sig::arg<IntExpr>("M"), 
sig::arg<IntExpr>("N"),
+                          sig::arg<IntExpr>("K"), sig::arg("trans_a"), 
sig::arg("trans_b"),
+                          sig::arg<IntExpr>("n_cta_groups"), 
sig::arg("neg_a"), sig::arg("neg_b"),
+                          sig::arg("is_sparse"));
   RegisterDeviceIntrinsic("cuda_tcgen05_encode_matrix_descriptor", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("desc"), sig::arg("addr"), sig::arg("ldo"), 
sig::arg("sdo"),
-                          sig::arg("swizzle"));
+                          sig::arg("desc"), sig::arg("addr"), 
sig::arg<IntExpr>("ldo"),
+                          sig::arg<IntExpr>("sdo"), 
sig::arg<IntExpr>("swizzle"));
   RegisterDeviceIntrinsic("cuda_thread_fence", "cuda", 
CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("cuda_thread_rank", "cuda", CallEffectKind::kPure);
   RegisterDeviceIntrinsic("cuda_trap_when_assert_failed", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("cond"));
-  RegisterDeviceIntrinsic("cuda_uint_as_float", "cuda", 
CallEffectKind::kOpaque, sig::arg("bits"));
+  RegisterDeviceIntrinsic("cuda_uint_as_float", "cuda", 
CallEffectKind::kOpaque,
+                          sig::arg<IntExpr>("bits"));
   RegisterDeviceIntrinsic("cuda_warp_reduce", "cuda", CallEffectKind::kOpaque, 
sig::arg("value"),
-                          sig::arg("op"), sig::arg("width"));
+                          sig::arg("op"), sig::arg<IntExpr>("width"));
   RegisterDeviceIntrinsic("cuda_warp_sync", "cuda", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("cuda_warpgroup_sync", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("bar_no"));
+                          sig::arg<IntExpr>("bar_no"));
   RegisterDeviceIntrinsic("cuda_wgmma_encode_matrix_descriptor", "cuda", 
CallEffectKind::kOpaque,
-                          sig::arg("desc"), sig::arg("addr"), sig::arg("ldo"), 
sig::arg("sdo"),
-                          sig::arg("swizzle"));
+                          sig::arg("desc"), sig::arg("addr"), 
sig::arg<IntExpr>("ldo"),
+                          sig::arg<IntExpr>("sdo"), 
sig::arg<IntExpr>("swizzle"));
   RegisterDeviceIntrinsic("cuda_wgmma_noop_barrier", "cuda", 
CallEffectKind::kOpaque,
                           sig::arg("reg"));
   RegisterDeviceIntrinsic("nvshmem_barrier_all", "nvshmem", 
CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("nvshmem_fence", "nvshmem", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("nvshmem_getmem_nbi", "nvshmem", 
CallEffectKind::kOpaque, sig::arg("dst"),
-                          sig::arg("src"), sig::arg("nelems"), sig::arg("pe"));
+                          sig::arg("src"), sig::arg<IntExpr>("nelems"), 
sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_getmem_nbi_block", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), 
sig::arg("nelems"), sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_getmem_nbi_warp", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), 
sig::arg("nelems"), sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_my_pe", "nvshmem", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("nvshmem_n_pes", "nvshmem", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("nvshmem_putmem_nbi", "nvshmem", 
CallEffectKind::kOpaque, sig::arg("dst"),
-                          sig::arg("src"), sig::arg("nelems"), sig::arg("pe"));
+                          sig::arg("src"), sig::arg<IntExpr>("nelems"), 
sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_putmem_nbi_block", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), 
sig::arg("nelems"), sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_putmem_nbi_warp", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), 
sig::arg("nelems"), sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_putmem_signal_nbi", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), sig::arg("nelems"),
-                          sig::arg("sig_addr"), sig::arg("signal"), 
sig::arg("sig_op"),
-                          sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg("sig_addr"), sig::arg<IntExpr>("signal"), 
sig::arg("sig_op"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_putmem_signal_nbi_block", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), sig::arg("nelems"),
-                          sig::arg("sig_addr"), sig::arg("signal"), 
sig::arg("sig_op"),
-                          sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg("sig_addr"), sig::arg<IntExpr>("signal"), 
sig::arg("sig_op"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_putmem_signal_nbi_warp", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("dst"), sig::arg("src"), sig::arg("nelems"),
-                          sig::arg("sig_addr"), sig::arg("signal"), 
sig::arg("sig_op"),
-                          sig::arg("pe"));
+                          sig::arg("dst"), sig::arg("src"), 
sig::arg<IntExpr>("nelems"),
+                          sig::arg("sig_addr"), sig::arg<IntExpr>("signal"), 
sig::arg("sig_op"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_quiet", "nvshmem", CallEffectKind::kOpaque);
   RegisterDeviceIntrinsic("nvshmem_signal_op", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("sig_addr"), sig::arg("signal"), 
sig::arg("sig_op"),
-                          sig::arg("pe"));
+                          sig::arg("sig_addr"), sig::arg<IntExpr>("signal"), 
sig::arg("sig_op"),
+                          sig::arg<IntExpr>("pe"));
   RegisterDeviceIntrinsic("nvshmem_wait_until", "nvshmem", 
CallEffectKind::kOpaque,
-                          sig::arg("ivar"), sig::arg("cmp"), 
sig::arg("cmp_value"),
+                          sig::arg("ivar"), sig::arg("cmp"), 
sig::arg<IntExpr>("cmp_value"),
                           sig::arg("type"));
   RegisterDeviceIntrinsic("ptx_legacy_ldmatrix", "ptx_legacy", 
CallEffectKind::kOpaque,
-                          sig::arg("trans"), sig::arg("num"), 
sig::arg("dtype"),
-                          sig::arg("local_ptr"), sig::arg("local_offset"), 
sig::arg("smem_ptr"),
-                          sig::arg("smem_offset"));
-  RegisterDeviceIntrinsic("ptx_legacy_mma", "ptx_legacy", 
CallEffectKind::kOpaque,
-                          sig::arg("shape"), sig::arg("a_layout"), 
sig::arg("b_layout"),
-                          sig::arg("a_dtype"), sig::arg("b_dtype"), 
sig::arg("c_dtype"),
-                          sig::arg("a_ptr"), sig::arg("a_offset"), 
sig::arg("b_ptr"),
-                          sig::arg("b_offset"), sig::arg("acc_ptr"), 
sig::arg("c_offset"),
-                          sig::arg("saturate"), sig::var_args("args"));
+                          sig::arg("trans"), sig::arg<IntExpr>("num"), 
sig::arg("dtype"),
+                          sig::arg("local_ptr"), 
sig::arg<IntExpr>("local_offset"),
+                          sig::arg("smem_ptr"), 
sig::arg<IntExpr>("smem_offset"));
+  RegisterDeviceIntrinsic(
+      "ptx_legacy_mma", "ptx_legacy", CallEffectKind::kOpaque, 
sig::arg("shape"),
+      sig::arg("a_layout"), sig::arg("b_layout"), sig::arg("a_dtype"), 
sig::arg("b_dtype"),
+      sig::arg("c_dtype"), sig::arg("a_ptr"), sig::arg<IntExpr>("a_offset"), 
sig::arg("b_ptr"),
+      sig::arg<IntExpr>("b_offset"), sig::arg("acc_ptr"), 
sig::arg<IntExpr>("c_offset"),
+      sig::arg("saturate"), sig::var_args("args"));
 
   for (const char* name : {
            "tirx.cuda.tcgen05_encode_matrix_descriptor",
diff --git a/src/backend/metal/codegen/intrin_rule_metal.cc 
b/src/backend/metal/codegen/intrin_rule_metal.cc
index 2f3d559ff2..402ebb6293 100644
--- a/src/backend/metal/codegen/intrin_rule_metal.cc
+++ b/src/backend/metal/codegen/intrin_rule_metal.cc
@@ -155,7 +155,7 @@ void RegisterMetalIntrinRules() {
   // Register low-level Metal device intrinsics.
   OpDef("tirx.metal.simd_shuffle")
       .signature(sig::arg("var", "The variable to sync."),
-          sig::arg("lane", "The source thread id."))
+          sig::arg<IntExpr>("lane", "The source thread id."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<0>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("metal"))
@@ -166,7 +166,7 @@ void RegisterMetalIntrinRules() {
 
   OpDef("tirx.metal.simd_shuffle_up")
       .signature(sig::arg("var", "The variable to sync."),
-          sig::arg("delta", "The source lane id offset to be added."))
+          sig::arg<IntExpr>("delta", "The source lane id offset to be added."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<0>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("metal"))
@@ -177,7 +177,7 @@ void RegisterMetalIntrinRules() {
 
   OpDef("tirx.metal.simd_shuffle_down")
       .signature(sig::arg("var", "The variable to sync."),
-          sig::arg("delta", "The source lane id offset to be subtracted."))
+          sig::arg<IntExpr>("delta", "The source lane id offset to be 
subtracted."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<0>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("metal"))
diff --git a/src/backend/metal/op/target_builtin.cc 
b/src/backend/metal/op/target_builtin.cc
index d9f3be63c0..794c802019 100644
--- a/src/backend/metal/op/target_builtin.cc
+++ b/src/backend/metal/op/target_builtin.cc
@@ -37,37 +37,41 @@ void RegisterMetalTargetBuiltins() {
   registered = true;
 
   OpDef("tirx.make_filled_simdgroup_matrix")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index", "The 
index."),
-                 sig::arg("value", "The value to use."), sig::arg("col", "The 
column index."),
-                 sig::arg("row", "The row index."))
+      .signature(sig::arg("d", "The D operand."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg("value", "The value to use."),
+                 sig::arg<IntExpr>("col", "The column index."),
+                 sig::arg<IntExpr>("row", "The row index."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.metal.make_filled_simdgroup_matrix"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.simdgroup_load")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index", "The 
index."),
-                 sig::arg("ptr", "The pointer."), sig::arg("stride", "The 
stride."),
-                 sig::arg("col", "The column index."), sig::arg("row", "The 
row index."),
+      .signature(sig::arg("d", "The D operand."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg("ptr", "The pointer."), sig::arg<IntExpr>("stride", 
"The stride."),
+                 sig::arg<IntExpr>("col", "The column index."),
+                 sig::arg<IntExpr>("row", "The row index."),
                  sig::arg("transpose_matrix", "Whether to transpose the 
matrix."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.metal.simdgroup_load"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.simdgroup_store")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index", "The 
index."),
-                 sig::arg("ptr", "The pointer."), sig::arg("stride", "The 
stride."),
-                 sig::arg("col", "The column index."), sig::arg("row", "The 
row index."),
+      .signature(sig::arg("d", "The D operand."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg("ptr", "The pointer."), sig::arg<IntExpr>("stride", 
"The stride."),
+                 sig::arg<IntExpr>("col", "The column index."),
+                 sig::arg<IntExpr>("row", "The row index."),
                  sig::arg("transpose_matrix", "Whether to transpose the 
matrix."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.metal.simdgroup_store"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.simdgroup_multiply_accumulate")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index_d", "The D 
fragment index."),
-                 sig::arg("a", "The A operand."), sig::arg("index_a", "The A 
fragment index."),
-                 sig::arg("b", "The B operand."), sig::arg("index_b", "The B 
fragment index."),
-                 sig::arg("c", "The C operand."), sig::arg("index_c", "The C 
fragment index."))
+      .signature(
+          sig::arg("d", "The D operand."), sig::arg<IntExpr>("index_d", "The D 
fragment index."),
+          sig::arg("a", "The A operand."), sig::arg<IntExpr>("index_a", "The A 
fragment index."),
+          sig::arg("b", "The B operand."), sig::arg<IntExpr>("index_b", "The B 
fragment index."),
+          sig::arg("c", "The C operand."), sig::arg<IntExpr>("index_c", "The C 
fragment index."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.metal.simdgroup_multiply_accumulate"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
diff --git a/src/backend/webgpu/codegen/intrin_rule_webgpu.cc 
b/src/backend/webgpu/codegen/intrin_rule_webgpu.cc
index b55c517000..6178cc6d8b 100644
--- a/src/backend/webgpu/codegen/intrin_rule_webgpu.cc
+++ b/src/backend/webgpu/codegen/intrin_rule_webgpu.cc
@@ -182,7 +182,7 @@ void RegisterWebGPUIntrinRules() {
   // Register low-level WebGPU device intrinsics.
   OpDef("tirx.webgpu.subgroup_shuffle")
       .signature(sig::arg("var", "The variable to sync."),
-          sig::arg("lane", "The source thread id."))
+          sig::arg<IntExpr>("lane", "The source thread id."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<0>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("webgpu"))
@@ -193,7 +193,7 @@ void RegisterWebGPUIntrinRules() {
 
   OpDef("tirx.webgpu.subgroup_shuffle_up")
       .signature(sig::arg("var", "The variable to sync."),
-          sig::arg("delta", "The source lane id offset to be added."))
+          sig::arg<IntExpr>("delta", "The source lane id offset to be added."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<0>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("webgpu"))
@@ -204,7 +204,7 @@ void RegisterWebGPUIntrinRules() {
 
   OpDef("tirx.webgpu.subgroup_shuffle_down")
       .signature(sig::arg("var", "The variable to sync."),
-          sig::arg("delta", "The source lane id offset to be subtracted."))
+          sig::arg<IntExpr>("delta", "The source lane id offset to be 
subtracted."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<0>>())
       .set_attr<tirx::TIRxOpCategory>("TIRxOpCategory", 
ffi::String("device_intrin"))
       .set_attr<tirx::TDeviceIntrinsicNamespace>("TDeviceIntrinsicNamespace", 
ffi::String("webgpu"))
diff --git a/src/relax/op/op.cc b/src/relax/op/op.cc
index fb776eda1e..5b4185fe90 100644
--- a/src/relax/op/op.cc
+++ b/src/relax/op/op.cc
@@ -1195,14 +1195,15 @@ Type InferTypeAllocateTensor(const Call& call, const 
BlockBuilder& ctx) {
 
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.builtin.alloc_tensor")
-      .signature(sig::arg("shape", "The shape of the tensor to allocate."),
-                 sig::arg("dtype", "The dtype of the tensor to allocate."),
-                 sig::arg("runtime_device_index",
-                          "The device index indicating on which device the 
tensor is to be "
-                          "allocated at runtime. Index -1 is reserved for the 
host device."),
-                 sig::arg("storage_scope",
-                          "The storage scope of the storage to allocate. 
Default is global."),
-                 sig::var_ty_args("out_type", "Optional output type used by 
allocation rewrites."))
+      .signature(
+          sig::arg("shape", "The shape of the tensor to allocate."),
+          sig::arg("dtype", "The dtype of the tensor to allocate."),
+          sig::arg<IntExpr>("runtime_device_index",
+                            "The device index indicating on which device the 
tensor is to be "
+                            "allocated at runtime. Index -1 is reserved for 
the host device."),
+          sig::arg("storage_scope",
+                   "The storage scope of the storage to allocate. Default is 
global."),
+          sig::var_ty_args("out_type", "Optional output type used by 
allocation rewrites."))
       .set_attr<FInferTypeWithBuilder>("relax.FInferTypeWithBuilder", 
InferTypeAllocateTensor)
       // memory allocation isn't considered a "visible effect" as far as 
purity is concerned
       .set_attr<bool>("FPurity", true)
@@ -1277,13 +1278,14 @@ Type InferTypeMemAllocTensor(const Call& call, const 
BlockBuilder& ctx) {
 
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.memory.alloc_tensor")
-      .signature(sig::arg("storage", "The storage to allocate the tensor to."),
-                 sig::arg("offset", "Storage offset to allocate the tensor."),
-                 sig::arg("shape", "The shape of the tensor to allocate."),
-                 sig::arg("dtype", "The dtype of the tensor to allocate."),
-                 sig::arg("runtime_device_index",
-                          "The device index indicating on which device the 
tensor is to be "
-                          "allocated at runtime. Index -1 is reserved for the 
host device."))
+      .signature(
+          sig::arg("storage", "The storage to allocate the tensor to."),
+          sig::arg<IntExpr>("offset", "Storage offset to allocate the 
tensor."),
+          sig::arg("shape", "The shape of the tensor to allocate."),
+          sig::arg("dtype", "The dtype of the tensor to allocate."),
+          sig::arg<IntExpr>("runtime_device_index",
+                            "The device index indicating on which device the 
tensor is to be "
+                            "allocated at runtime. Index -1 is reserved for 
the host device."))
       .set_attr<FInferTypeWithBuilder>("relax.FInferTypeWithBuilder", 
InferTypeMemAllocTensor)
       // memory allocation isn't considered a "visible effect" as far as 
purity is concerned
       .set_attr<bool>("FPurity", true)
@@ -1352,9 +1354,9 @@ TVM_FFI_STATIC_INIT_BLOCK() {
 
   OpDef("relax.vm.alloc_storage")
       .signature(sig::arg("size", "The size of the storage to allocate."),
-                 sig::arg("runtime_device_index",
-                          "The device index indicating on which device the 
tensor is "
-                          "to be allocated at runtime."),
+                 sig::arg<IntExpr>("runtime_device_index",
+                                   "The device index indicating on which 
device the tensor is "
+                                   "to be allocated at runtime."),
                  sig::arg("dtype", "The dtype of the tensor to allocate."),
                  sig::arg("storage_scope",
                           "The storage scope of the storage to allocate. 
Default is global."))
@@ -1405,12 +1407,12 @@ Type InferTypeVMAllocTensor(const Call& call, const 
BlockBuilder& ctx) {
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.vm.alloc_tensor")
       .signature(sig::arg("storage", "The storage to allocate the tensor to."),
-                 sig::arg("offset", "Storage offset to allocate the tensor."),
+                 sig::arg<IntExpr>("offset", "Storage offset to allocate the 
tensor."),
                  sig::arg("shape", "The shape of the tensor to allocate."),
                  sig::arg("dtype", "The dtype of the tensor to allocate."),
-                 sig::arg("runtime_device_index",
-                          "The device index indicating on which device the 
tensor is "
-                          "to be allocated at runtime."))
+                 sig::arg<IntExpr>("runtime_device_index",
+                                   "The device index indicating on which 
device the tensor is "
+                                   "to be allocated at runtime."))
       .set_attr<FInferTypeWithBuilder>("relax.FInferTypeWithBuilder", 
InferTypeVMAllocTensor)
       // memory allocation isn't considered a "visible effect" as far as 
purity is concerned
       .set_attr<bool>("FPurity", true)
diff --git a/src/relax/op/tensor/create.cc b/src/relax/op/tensor/create.cc
index e48c62f32e..76c887c6bd 100644
--- a/src/relax/op/tensor/create.cc
+++ b/src/relax/op/tensor/create.cc
@@ -450,7 +450,7 @@ Type InferTypeHammingWindow(const CallNode* call_node) {
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.hamming_window")
       .signature(
-          sig::arg("window_size", "The size of the window"),
+          sig::arg<IntExpr>("window_size", "The size of the window"),
           sig::arg("periodic",
                    "If True, returns a window to be used as periodic function. 
If False, return a "
                    "symmetric window"),
@@ -495,12 +495,14 @@ Type InferTypeTrilTriu(const CallNode* call_node) {
 
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.tril")
-      .signature(sig::arg("x", "The input tensor."), sig::arg("k", "The offset 
of the diagonal."))
+      .signature(sig::arg("x", "The input tensor."),
+                 sig::arg<IntExpr>("k", "The offset of the diagonal."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeTrilTriu>())
       .set_attr<bool>("FPurity", true);
 
   OpDef("relax.triu")
-      .signature(sig::arg("x", "The input tensor."), sig::arg("k", "The offset 
of the diagonal."))
+      .signature(sig::arg("x", "The input tensor."),
+                 sig::arg<IntExpr>("k", "The offset of the diagonal."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeTrilTriu>())
       .set_attr<bool>("FPurity", true);
 }
diff --git a/src/relax/op/tensor/inspect.cc b/src/relax/op/tensor/inspect.cc
index 1e62cf350e..ca60f3e135 100644
--- a/src/relax/op/tensor/inspect.cc
+++ b/src/relax/op/tensor/inspect.cc
@@ -313,7 +313,7 @@ Expr LegalizeTensorShape(const BlockBuilder& bb, const 
Call& call) {
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.inspect.tensor_shape_i")
       .signature(sig::arg("tensor", "The tensor to be inspected"),
-                 sig::arg("axis", "The axis whose extent should be returned"))
+                 sig::arg<IntExpr>("axis", "The axis whose extent should be 
returned"))
       .set_attr<FInferTypeWithBuilder>("relax.FInferTypeWithBuilder", 
InferTypeTensorShape)
       .set_attr<FLegalize>("FLegalize", LegalizeTensorShape)
       .set_attr<bool>("RequiresArgumentShapes", false)
@@ -362,7 +362,7 @@ Type InferTypeTensorStride(const Call& call, const 
BlockBuilder&) {
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.inspect.tensor_stride_i")
       .signature(sig::arg("tensor", "The tensor to be inspected"),
-                 sig::arg("axis", "The axis whose extent should be returned"))
+                 sig::arg<IntExpr>("axis", "The axis whose extent should be 
returned"))
       .set_attr<FInferTypeWithBuilder>("relax.FInferTypeWithBuilder", 
InferTypeTensorStride)
       .set_attr<bool>("RequiresArgumentShapes", false)
       .set_attr<FNormalize>("FNormalize", NormalizeToKnownPrimExpr)
diff --git a/src/relax/op/tensor/manipulate.cc 
b/src/relax/op/tensor/manipulate.cc
index 38eb54a039..24a46d5105 100644
--- a/src/relax/op/tensor/manipulate.cc
+++ b/src/relax/op/tensor/manipulate.cc
@@ -3105,11 +3105,11 @@ Type InferTypeSliceScatter(const Call& call, const 
BlockBuilder& ctx) {
 
 TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("relax.slice_scatter")
-      .signature(sig::arg("input", "The input tensor."),
-                 sig::arg("src", "The source tensor to scatter."),
-                 sig::arg("start", "The starting index of the slice 
(inclusive)."),
-                 sig::arg("end", "The ending index of the slice (exclusive)."),
-                 sig::arg("step", "The step of the slice."), 
sig::call_attrs<SliceScatterAttrs>())
+      .signature(
+          sig::arg("input", "The input tensor."), sig::arg("src", "The source 
tensor to scatter."),
+          sig::arg<IntExpr>("start", "The starting index of the slice 
(inclusive)."),
+          sig::arg<IntExpr>("end", "The ending index of the slice 
(exclusive)."),
+          sig::arg<IntExpr>("step", "The step of the slice."), 
sig::call_attrs<SliceScatterAttrs>())
       .set_attr<FInferTypeWithBuilder>("relax.FInferTypeWithBuilder", 
InferTypeSliceScatter)
       .set_attr<bool>("FPurity", true);
 }
diff --git a/src/tirx/op/builtin.cc b/src/tirx/op/builtin.cc
index 1b757ffda2..eaa0465f58 100644
--- a/src/tirx/op/builtin.cc
+++ b/src/tirx/op/builtin.cc
@@ -365,7 +365,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
                                            
static_cast<int64_t>(ScriptDtypePrintLocation::kFirst));
 
   OpDef("tirx.call_llvm_intrin")
-      .signature(sig::arg("intrin_id", "The intrinsic identifier."), 
sig::var_args("args"))
+      .signature(sig::arg<IntExpr>("intrin_id", "The intrinsic identifier."), 
sig::var_args("args"))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.call_llvm_intrin"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque))
@@ -373,7 +373,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
                                            
static_cast<int64_t>(ScriptDtypePrintLocation::kFirst));
 
   OpDef("tirx.call_llvm_pure_intrin")
-      .signature(sig::arg("intrin_id", "The intrinsic identifier."), 
sig::var_args("args"))
+      .signature(sig::arg<IntExpr>("intrin_id", "The intrinsic identifier."), 
sig::var_args("args"))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.call_llvm_pure_intrin"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kPure))
@@ -382,28 +382,30 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .set_attr<TVectorizable>("TVectorizable", true);
 
   OpDef("tirx.call_spirv_pure_glsl450")
-      .signature(sig::arg("intrin_id", "The intrinsic identifier."), 
sig::var_args("args"))
+      .signature(sig::arg<IntExpr>("intrin_id", "The intrinsic identifier."), 
sig::var_args("args"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kPure));
 
   OpDef("tirx.prefetch")
-      .signature(sig::arg("ptr", "The pointer."), sig::arg("rw", "The 
read/write mode."),
-                 sig::arg("locality", "The locality hint."),
-                 sig::arg("cache_type", "The cache policy."))
+      .signature(sig::arg("ptr", "The pointer."), sig::arg<IntExpr>("rw", "The 
read/write mode."),
+                 sig::arg<IntExpr>("locality", "The locality hint."),
+                 sig::arg<IntExpr>("cache_type", "The cache policy."))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_access_ptr")
       .signature(sig::arg("ptype", "The pointer type."), sig::arg("data", "The 
input data."),
-                 sig::arg("offset", "The offset."), sig::arg("extent", "The 
extent."),
-                 sig::arg("rw_mask", "The read/write mask."))
+                 sig::arg<IntExpr>("offset", "The offset."),
+                 sig::arg<IntExpr>("extent", "The extent."),
+                 sig::arg<IntExpr>("rw_mask", "The read/write mask."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_access_ptr"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind",
                                  
static_cast<int64_t>(CallEffectKind::kSpecialCallArg));
 
   OpDef("tirx.ptr_byte_offset")
-      .signature(sig::arg("data", "Base pointer."), sig::arg("byte_offset", 
"Offset in bytes."),
+      .signature(sig::arg("data", "Base pointer."),
+                 sig::arg<IntExpr>("byte_offset", "Offset in bytes."),
                  sig::arg("dtype", "Type annotation for pointed-to elements."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.ptr_byte_offset"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -415,15 +417,15 @@ TVM_FFI_STATIC_INIT_BLOCK() {
                                  
static_cast<int64_t>(CallEffectKind::kSpecialCallArg));
 
   OpDef("tirx.handle_add_byte_offset")
-      .signature(sig::arg("handle", "The handle."), sig::arg("offset", "The 
offset."))
+      .signature(sig::arg("handle", "The handle."), 
sig::arg<IntExpr>("offset", "The offset."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     ffi::String("tirx.handle_add_byte_offset"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kPure));
 
   OpDef("tirx.tvm_struct_get")
-      .signature(sig::arg("arr", "The array."), sig::arg("index", "The 
index."),
-                 sig::arg("field", "The field index."))
+      .signature(sig::arg("arr", "The array."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg<IntExpr>("field", "The field index."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_struct_get"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind",
@@ -432,8 +434,9 @@ TVM_FFI_STATIC_INIT_BLOCK() {
                                            
static_cast<int64_t>(ScriptDtypePrintLocation::kLast));
 
   OpDef("tirx.tvm_struct_set")
-      .signature(sig::arg("arr", "The array."), sig::arg("index", "The 
index."),
-                 sig::arg("field", "The field index."), sig::arg("value", "The 
value to use."))
+      .signature(sig::arg("arr", "The array."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg<IntExpr>("field", "The field index."),
+                 sig::arg("value", "The value to use."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_struct_set"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind",
@@ -446,22 +449,23 @@ TVM_FFI_STATIC_INIT_BLOCK() {
 
   OpDef("tirx.tvm_stack_alloca")
       .signature(sig::arg("dtype_str", "The data type name."),
-                 sig::arg("num", "The number of entries."))
+                 sig::arg<IntExpr>("num", "The number of entries."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_stack_alloca"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_stack_make_shape")
-      .signature(sig::var_args("args"))
+      .signature(sig::var_args<IntExpr>("args"))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_stack_make_shape"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_stack_make_array")
       .signature(sig::arg("data", "The input data."), sig::arg("shape", "The 
shape."),
-                 sig::arg("strides", "The strides."), sig::arg("ndim", "The 
number of dimensions."),
+                 sig::arg("strides", "The strides."),
+                 sig::arg<IntExpr>("ndim", "The number of dimensions."),
                  sig::arg("arr_dtype", "The array data type."),
-                 sig::arg("elem_offset", "The element offset."))
+                 sig::arg<IntExpr>("elem_offset", "The element offset."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_stack_make_array"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
@@ -501,7 +505,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("tirx.tvm_call_packed_lowered")
       .signature(sig::arg("func_name", "The function name."),
                  sig::arg("args_stack", "The argument stack."),
-                 sig::arg("begin", "The start index."), sig::arg("end", "The 
end index."))
+                 sig::arg<IntExpr>("begin", "The start index."),
+                 sig::arg<IntExpr>("end", "The end index."))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.call_packed_lowered"));
@@ -509,7 +514,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
   OpDef("tirx.tvm_call_cpacked_lowered")
       .signature(sig::arg("func_name", "The function name."),
                  sig::arg("args_stack", "The argument stack."),
-                 sig::arg("begin", "The start index."), sig::arg("end", "The 
end index."))
+                 sig::arg<IntExpr>("begin", "The start index."),
+                 sig::arg<IntExpr>("end", "The end index."))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.call_cpacked_lowered"));
@@ -531,36 +537,40 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_warp_shuffle")
-      .signature(sig::arg("mask", "The mask."), sig::arg("value", "The value 
to use."),
-                 sig::arg("warp_id", "The warp identifier."), 
sig::arg("width", "The width."),
-                 sig::arg("warp_size", "The number of threads per warp."))
+      .signature(sig::arg<IntExpr>("mask", "The mask."), sig::arg("value", 
"The value to use."),
+                 sig::arg<IntExpr>("warp_id", "The warp identifier."),
+                 sig::arg<IntExpr>("width", "The width."),
+                 sig::arg<IntExpr>("warp_size", "The number of threads per 
warp."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_warp_shuffle"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_warp_shuffle_up")
-      .signature(sig::arg("mask", "The mask."), sig::arg("value", "The value 
to use."),
-                 sig::arg("offset", "The offset."), sig::arg("width", "The 
width."),
-                 sig::arg("warp_size", "The number of threads per warp."))
+      .signature(sig::arg<IntExpr>("mask", "The mask."), sig::arg("value", 
"The value to use."),
+                 sig::arg<IntExpr>("offset", "The offset."),
+                 sig::arg<IntExpr>("width", "The width."),
+                 sig::arg<IntExpr>("warp_size", "The number of threads per 
warp."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_warp_shuffle_up"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_warp_shuffle_down")
-      .signature(sig::arg("mask", "The mask."), sig::arg("value", "The value 
to use."),
-                 sig::arg("offset", "The offset."), sig::arg("width", "The 
width."),
-                 sig::arg("warp_size", "The number of threads per warp."))
+      .signature(sig::arg<IntExpr>("mask", "The mask."), sig::arg("value", 
"The value to use."),
+                 sig::arg<IntExpr>("offset", "The offset."),
+                 sig::arg<IntExpr>("width", "The width."),
+                 sig::arg<IntExpr>("warp_size", "The number of threads per 
warp."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_warp_shuffle_down"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_warp_shuffle_xor")
-      .signature(sig::arg("mask", "The mask."), sig::arg("value", "The value 
to use."),
-                 sig::arg("lane_mask", "The lane mask."), sig::arg("width", 
"The width."),
-                 sig::arg("warp_size", "The number of threads per warp."))
+      .signature(sig::arg<IntExpr>("mask", "The mask."), sig::arg("value", 
"The value to use."),
+                 sig::arg<IntExpr>("lane_mask", "The lane mask."),
+                 sig::arg<IntExpr>("width", "The width."),
+                 sig::arg<IntExpr>("warp_size", "The number of threads per 
warp."))
       .set_attr<FInferType>("FInferType", 
FInferType::FromNative<&InferTypeReturnArgType<1>>())
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_warp_shuffle_xor"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -573,59 +583,61 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.tvm_thread_allreduce")
-      .signature(sig::arg("size", "The size."), sig::var_args("args"))
+      .signature(sig::arg<IntExpr>("size", "The size."), sig::var_args("args"))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.tvm_thread_allreduce"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.cooperative_tensor_fill")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index", "The 
index."),
-                 sig::arg("value", "The value to use."), sig::arg("rows", "The 
number of rows."),
-                 sig::arg("cols", "The number of columns."))
+      .signature(sig::arg("d", "The D operand."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg("value", "The value to use."),
+                 sig::arg<IntExpr>("rows", "The number of rows."),
+                 sig::arg<IntExpr>("cols", "The number of columns."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.cooperative_tensor_fill"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.cooperative_tensor_load")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index", "The 
index."),
-                 sig::arg("ptr", "The pointer."), sig::arg("stride", "The 
stride."),
-                 sig::arg("rows", "The number of rows."),
-                 sig::arg("cols", "The number of columns."),
+      .signature(sig::arg("d", "The D operand."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg("ptr", "The pointer."), sig::arg<IntExpr>("stride", 
"The stride."),
+                 sig::arg<IntExpr>("rows", "The number of rows."),
+                 sig::arg<IntExpr>("cols", "The number of columns."),
                  sig::arg("transpose_matrix", "Whether to transpose the 
matrix."),
-                 sig::arg("mma_M", "The M dimension of the matrix operation."),
-                 sig::arg("mma_N", "The N dimension of the matrix operation."),
-                 sig::arg("mma_K", "The K dimension of the matrix operation."),
-                 sig::arg("operand_role", "The matrix operand role."))
+                 sig::arg<IntExpr>("mma_M", "The M dimension of the matrix 
operation."),
+                 sig::arg<IntExpr>("mma_N", "The N dimension of the matrix 
operation."),
+                 sig::arg<IntExpr>("mma_K", "The K dimension of the matrix 
operation."),
+                 sig::arg<IntExpr>("operand_role", "The matrix operand role."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.cooperative_tensor_load"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.cooperative_tensor_store")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index", "The 
index."),
-                 sig::arg("ptr", "The pointer."), sig::arg("stride", "The 
stride."),
-                 sig::arg("rows", "The number of rows."),
-                 sig::arg("cols", "The number of columns."),
+      .signature(sig::arg("d", "The D operand."), sig::arg<IntExpr>("index", 
"The index."),
+                 sig::arg("ptr", "The pointer."), sig::arg<IntExpr>("stride", 
"The stride."),
+                 sig::arg<IntExpr>("rows", "The number of rows."),
+                 sig::arg<IntExpr>("cols", "The number of columns."),
                  sig::arg("transpose_matrix", "Whether to transpose the 
matrix."),
-                 sig::arg("mma_M", "The M dimension of the matrix operation."),
-                 sig::arg("mma_N", "The N dimension of the matrix operation."),
-                 sig::arg("mma_K", "The K dimension of the matrix operation."),
-                 sig::arg("operand_role", "The matrix operand role."))
+                 sig::arg<IntExpr>("mma_M", "The M dimension of the matrix 
operation."),
+                 sig::arg<IntExpr>("mma_N", "The N dimension of the matrix 
operation."),
+                 sig::arg<IntExpr>("mma_K", "The K dimension of the matrix 
operation."),
+                 sig::arg<IntExpr>("operand_role", "The matrix operand role."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.cooperative_tensor_store"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.cooperative_tensor_multiply_accumulate")
-      .signature(sig::arg("d", "The D operand."), sig::arg("index_d", "The D 
fragment index."),
-                 sig::arg("a", "The A operand."), sig::arg("index_a", "The A 
fragment index."),
-                 sig::arg("b", "The B operand."), sig::arg("index_b", "The B 
fragment index."),
-                 sig::arg("c", "The C operand."), sig::arg("index_c", "The C 
fragment index."),
-                 sig::arg("M", "The M dimension."), sig::arg("N", "The N 
dimension."),
-                 sig::arg("K", "The K dimension."),
-                 sig::arg("transpose_a", "Whether to transpose A."),
-                 sig::arg("transpose_b", "Whether to transpose B."))
+      .signature(
+          sig::arg("d", "The D operand."), sig::arg<IntExpr>("index_d", "The D 
fragment index."),
+          sig::arg("a", "The A operand."), sig::arg<IntExpr>("index_a", "The A 
fragment index."),
+          sig::arg("b", "The B operand."), sig::arg<IntExpr>("index_b", "The B 
fragment index."),
+          sig::arg("c", "The C operand."), sig::arg<IntExpr>("index_c", "The C 
fragment index."),
+          sig::arg<IntExpr>("M", "The M dimension."), sig::arg<IntExpr>("N", 
"The N dimension."),
+          sig::arg<IntExpr>("K", "The K dimension."),
+          sig::arg("transpose_a", "Whether to transpose A."),
+          sig::arg("transpose_b", "Whether to transpose B."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.cooperative_tensor_multiply_accumulate"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -672,24 +684,26 @@ TVM_FFI_STATIC_INIT_BLOCK() {
 
   OpDef("tirx.nd_mem_alloc_with_scope")
       .signature(sig::arg("storage_scope", "The storage scope."),
-                 sig::arg("ndim", "The number of dimensions."), 
sig::arg("shape", "The shape."),
-                 sig::var_args("args"))
+                 sig::arg<IntExpr>("ndim", "The number of dimensions."),
+                 sig::arg("shape", "The shape."), sig::var_args("args"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.texture2d_store")
-      .signature(sig::arg("texture", "The texture."), sig::arg("x", "The input 
value."),
-                 sig::arg("y", "The second input value."), sig::arg("z", "The 
third input value."),
-                 sig::arg("channel_size", "The number of channels."),
+      .signature(sig::arg("texture", "The texture."), sig::arg<IntExpr>("x", 
"The input value."),
+                 sig::arg<IntExpr>("y", "The second input value."),
+                 sig::arg<IntExpr>("z", "The third input value."),
+                 sig::arg<IntExpr>("channel_size", "The number of channels."),
                  sig::arg("value", "The value to use."))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TVectorizable>("TVectorizable", true)
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.texture2d_load")
-      .signature(sig::arg("texture", "The texture."), sig::arg("x", "The input 
value."),
-                 sig::arg("y", "The second input value."), sig::arg("z", "The 
third input value."),
-                 sig::arg("channel_size", "The number of channels."),
+      .signature(sig::arg("texture", "The texture."), sig::arg<IntExpr>("x", 
"The input value."),
+                 sig::arg<IntExpr>("y", "The second input value."),
+                 sig::arg<IntExpr>("z", "The third input value."),
+                 sig::arg<IntExpr>("channel_size", "The number of channels."),
                  sig::arg("element_index", "The element index within a texture 
channel."))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TVectorizable>("TVectorizable", true)
@@ -709,7 +723,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
                                  
static_cast<int64_t>(CallEffectKind::kReadState));
 
   OpDef("tirx.get_active_lane_mask")
-      .signature(sig::arg("base", "The base value."), sig::arg("limit", "The 
limit value."))
+      .signature(sig::arg<IntExpr>("base", "The base value."),
+                 sig::arg<IntExpr>("limit", "The limit value."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.get_active_lane_mask"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kPure))
@@ -778,7 +793,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .signature(sig::arg("data", "The input data."), sig::arg("dtype", "The 
data type."),
                  sig::arg("is_string", "Whether to print as a string."),
                  sig::arg("is_scalar", "Whether to print as a scalar."),
-                 sig::arg("ndim", "The number of dimensions."), 
sig::var_args("args"))
+                 sig::arg<IntExpr>("ndim", "The number of dimensions."), 
sig::var_args("args"))
       .set_attr<TScriptPrinterName>("TScriptPrinterName", 
ffi::String("tirx.print_buffer"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
diff --git a/src/tirx/op/op.cc b/src/tirx/op/op.cc
index aa662a0aac..877e5f583e 100644
--- a/src/tirx/op/op.cc
+++ b/src/tirx/op/op.cc
@@ -699,11 +699,11 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kPure));
 
   OpDef("tirx.TVMBackendAllocWorkspace")
-      .signature(sig::arg("device_type", "The device type."),
-                 sig::arg("device_id", "The device index."),
-                 sig::arg("nbytes", "The number of bytes."),
-                 sig::arg("dtype_code_hint", "The data type code hint."),
-                 sig::arg("dtype_bits_hint", "The data type bit-width hint."))
+      .signature(sig::arg<IntExpr>("device_type", "The device type."),
+                 sig::arg<IntExpr>("device_id", "The device index."),
+                 sig::arg<IntExpr>("nbytes", "The number of bytes."),
+                 sig::arg<IntExpr>("dtype_code_hint", "The data type code 
hint."),
+                 sig::arg<IntExpr>("dtype_bits_hint", "The data type bit-width 
hint."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.TVMBackendAllocWorkspace"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
@@ -711,8 +711,9 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .set_attr<TCallEffectKind>("TCallEffectKind", 
static_cast<int64_t>(CallEffectKind::kOpaque));
 
   OpDef("tirx.TVMBackendFreeWorkspace")
-      .signature(sig::arg("device_type", "The device type."),
-                 sig::arg("device_id", "The device index."), sig::arg("ptr", 
"The pointer."))
+      .signature(sig::arg<IntExpr>("device_type", "The device type."),
+                 sig::arg<IntExpr>("device_id", "The device index."),
+                 sig::arg("ptr", "The pointer."))
       .set_attr<TScriptPrinterName>("TScriptPrinterName",
                                     
ffi::String("tirx.TVMBackendFreeWorkspace"))
       .set_attr<TIRxOpCategory>("TIRxOpCategory", ffi::String("builtin"))
diff --git a/tests/cpp/expr_test.cc b/tests/cpp/expr_test.cc
index 04bedfce99..067962a6e3 100644
--- a/tests/cpp/expr_test.cc
+++ b/tests/cpp/expr_test.cc
@@ -90,6 +90,27 @@ TEST(Expr, PrimTypeBoolLanes) {
   TVM_FFI_ICHECK(boolx4.MatchesElementType(DLDataTypeCode::kDLBool, 8));
 }
 
+TEST(Expr, IntegerView) {
+  using namespace tvm;
+  for (PrimType ty : {PrimType::Int(8), PrimType::UInt(64), 
PrimType::Int(128)}) {
+    ffi::Any value = Var("i", ty);
+    EXPECT_TRUE(value.cast<IntExpr>().same_as(value.cast<PrimExpr>()));
+    EXPECT_TRUE(value.cast<TypedExpr<PrimType>>().ty() == ty);
+  }
+  for (PrimType ty : {PrimType::Float(32), PrimType::Bool(), PrimType::Int(32, 
4),
+                      PrimType::ScalableVector(kDLInt, 32, 4)}) {
+    ffi::Any value = Var("x", ty);
+    EXPECT_FALSE(value.try_cast<IntExpr>());
+    EXPECT_TRUE(value.try_cast<PrimExpr>());
+  }
+  ffi::Any nonprimitive = Var("x", AnyType());
+  EXPECT_FALSE(nonprimitive.try_cast<IntExpr>());
+  EXPECT_FALSE(nonprimitive.try_cast<PrimExpr>());
+  EXPECT_FALSE(nonprimitive.try_cast<TypedExpr<PrimType>>());
+  EXPECT_EQ(ffi::Any(1).cast<IntExpr>().ty().bits(), 32);
+  EXPECT_EQ(ffi::Any(int64_t{1} << 40).cast<IntExpr>().ty().bits(), 64);
+}
+
 TEST(ExprNodeRef, Basic) {
   using namespace tvm;
   using namespace tvm::tirx;
diff --git a/tests/python/tirx-base/test_tir_op_types.py 
b/tests/python/tirx-base/test_tir_op_types.py
index 6ff7c05e6e..085b0c69f6 100644
--- a/tests/python/tirx-base/test_tir_op_types.py
+++ b/tests/python/tirx-base/test_tir_op_types.py
@@ -29,6 +29,17 @@ def test_tir_op_tvm_struct_get():
     assert expr.op.name == "tirx.tvm_struct_get"
 
 
+def test_scalar_integer_signature():
+    ptr = tirx.Var("ptr", ty="handle")
+    for dtype in ("int8", "uint32", "int64", "uint64"):
+        index = tirx.Var("index", dtype)
+        assert tirx.tvm_struct_get(ptr, index, 2, 
dtype="int32").args[1].same_as(index)
+    assert tirx.tvm_struct_get(ptr, 1 << 40, 2, 
dtype="int32").args[1].ty.dtype == "int64"
+    for dtype in ("float32", "bool", "int32x4", "int32xvscalex4"):
+        with pytest.raises(TypeError, match=r"index.*expected 
`ir.IntExpr`.*dtype="):
+            tirx.tvm_struct_get(ptr, tirx.Var("index", dtype), 2, 
dtype="int32")
+
+
 def test_tir_op_tvm_struct_set():
     x = tirx.Var("x", ty="handle")
     expr = tirx.tvm_struct_set(x, 1, 2, 3)

Reply via email to