Rename the reflected local `Var` field from `name_hint` to `name` and
update its typed C++ consumers. Preserve distinct named-node APIs and
the Python constructor keyword compatibility path, while making `.name`
the sole stored Var property. Upgrade legacy compact JSON records for
current and pre-unification Var schemas.
Validation: full runtime/compiler build, focused C++ Var copy-helper
test, focused Python IR/Relax/TIRx/script tests, Vulkan codegen syntax
build, touched-file pre-commit checks, and `git diff --check`.
## Rationale
TIRx variables use inherited `ExprNode::ty` as their single semantic
type. Retaining a primitive handle surrogate erases the distinction
between scalar values, typed pointers, and true opaque pointers, then
forces later passes and code generators to reconstruct information that
the IR already owns.
## Changes
- Remove the duplicate reflected `Var::type_annotation` state and
preserve exact `PrimType` or `PointerType` through construction,
visitors, transforms, specialization, builders, printers, and code
generation.
- Keep scalar-only boundaries explicit through `PrimExpr`, `PrimVar`,
and `PrimType`; pointer-capable values remain general `Expr` or `Var`.
- Keep helper boundaries no broader than their contracts: TE tensor
variable indices use `PrimVar`, while expression deep equality recurses
through general `Expr` only where pointer-bearing `Call` arguments
require it and does not generalize private arithmetic subclasses.
- Keep core statement reflection typed as `Expr`, name general
reinterpret targets as `target_ty`, and preserve exact pointer calls in
the general vectorization path with explicit scalarization behavior.
- Delete `PrimType::Handle()` and `PrimType::IsHandle()`. True opaque
pointers use `PointerType::VoidPointerTy()`; TVMScript renders the
canonical global type as `T.handle`, standalone values as `T.handle()`,
and scoped void pointers with a keyword-only storage scope.
- Make `CodeGenSourceBase::SSAGetID` a single `Type` boundary across
source backends, without a separate primitive-type or runtime-dtype
variant.
- Keep WebGPU semantic argument classification type-aware: storage
buffers are identified from `PointerType`, POD arguments from
`PrimType`, and only the final `FunctionInfo` launch ABI is serialized
to `DLDataType`.
- Preserve exact pointer semantics at runtime boundaries, including
access pointers, packed calls and returns, external calls, storage
rewrites, and target-specific lowering.
## Migration guide
- **Variable types:** In C++, replace `var->type_annotation` with
`var->ty`; in Python, replace `var.type_annotation` with `var.ty`. The
result is the exact `Type`: scalar variables carry `PrimType`, while
pointer variables carry `PointerType`.
- **Scalar boundaries:** Use `PrimVar` and `PrimExpr` for variables and
expressions that are semantically scalar. When starting from a general
view, narrow explicitly with `var.as_or_throw<PrimVar>()` or
`expr.as_or_throw<PrimExpr>()`. Keep pointer-capable fields and call
arguments as `Var` or `Expr`. A default-constructed `PrimVar` is
nullable, so construct local scalar variables explicitly, for example
`PrimVar i("i")`.
- **Opaque pointers:** Replace `PrimType::Handle()` with
`PointerType::VoidPointerTy()`. Replace `IsHandle()` tests with explicit
`PointerType` inspection; use `PointerType(element_type, storage_scope)`
when the pointee type is known instead of erasing it to a runtime handle
dtype.
- **TVMScript handles:** Use `arg: T.handle` for a global void-pointer
annotation and `arg = T.handle()` for a standalone value. Use
`T.handle(storage_scope="shared")` for a scoped void pointer. Typed
pointers use forms such as `T.handle("float32")`, `T.handle("float32",
"global")`, or `T.handle("float32", "shared")`. Legacy
`T.handle("void")` input remains parse-compatible, but the printer
canonicalizes it to `T.handle` (or the keyword-only scoped form).
- The separate `tirx.type_annotation` intrinsic used by access-pointer
APIs is unchanged; this migration removes only the duplicate variable
field.
## Validation
- Complete native C++ test executable: 122/122 passed, including
`IRF.CountVar`.
- Relax binding-rewrite suite: 12/12 passed, including transferred-user
bookkeeping.
- Canonical typed/void/scoped TVMScript handle printer and round-trip
checks: 5/5 passed.
In the past we have been using `DataType` in PrimExpr.dtype field to
check type information for PrimExpr while still having BaseExpr.ty for
richer type information. DataType is also used both in runtime and
compiler. This PR streamlines the boundary:
- PrimExpr.ty now carries PrimType that replaces original use of
`DataType`
- Runtime use will now favor DLPack DLDataType, removing one layer of
indirection.
- Constants attributes where values are usually runtime values, will use
`DLDataType`
- DataType will be phased out after this PR
We also brings up helper functions in PrimType, but also limits them to
a more concise set so the functions do not grow with the data type codes
in DLPack.
This is a major refactor that changes the IR primitive. It helps to
bring possible future benefits:
- Unified type mechanism through Expr.ty
- Possibility of carry future Type nodes
Migration Guide:
- Use `PrimType` when code reasons about compiler expression types,
tensor element compiler types, or constructs a `PrimExpr`/compiler type.
- Use existing source types such as `expr.ty()`, `ExprOp.expr_ty()`, or
TE tensor element `dtype` where possible instead of rebuilding a type
from dtype text.
- Use raw `DLDataType` for runtime constants, ABI paths, dtype-valued
attrs, and storage/runtime helper logic.
- Prefer direct `PrimType` equality, `MatchesCode(...)`,
`MatchesElementType(...)`, and `WithCode(...)` over local wrappers or
string dtype checks.
Performance:
Using Object type instead of DLDataType would indeed bring some
performance impact to the IR. We have done the following performance
optimizations:
- Make sure most of the outputs reuse one of the PrimType from inputs
- Cache a thread local PrimType based on input so we don't repeatly
realloc
We did benchmarks show that rewrite simplify operation stays within
+-10% overhead of original one. Which merits the refactor given the
benefit the unfication brings
This PR phases out the legacy `Downcast` helper and removes
`tvm/ir/cast.h`, replacing mandatory object casts with the strict
`as_or_throw` style APIs after bumping tvm-ffi to the latest fix.
The migration keeps nullable-object behavior explicit. Optional `Any`
conversions that need to preserve null use the nullable
`value_or(nullptr).as_or_throw<ffi::Optional<T>>()` pattern, while
simple mandatory casts use direct receivers such as
`obj.as_or_throw<T>()`.
## Summary
include/tvm/runtime/object.h was a vestige of the pre-tvm-ffi world — a
thin compat layer re-exporting
Object/ObjectRef/ObjectPtr/GetRef/GetObjectPtr
aliases into tvm::runtime:: and tvm::, plus a few TVM-specific macros
and
an enum TypeIndex with mostly-dead constants.
This PR phases the header out entirely, with no shim:
- `TVM_DEFINE_OBJECT_REF_COW_METHOD` relocated to a new
`include/tvm/ir/cow.h`
(its consumer set is entirely IR/TIRX/relax/arith/te).
-
`TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE_WITHOUT_DEFAULT_CONSTRUCTOR`
inlined at its 2 callers (rare; not worth a new home).
- `TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN` inlined at its 1 caller.
- `TVM_STR_CONCAT` removed; callers switch to `TVM_FFI_STR_CONCAT`
(already in tvm-ffi; the local copy was a duplicate).
- `kRuntimeRPCObjectRef` / `kRuntimeDiscoDRef` inlined into
`rpc_session.h`
/ `disco/session.h` respectively (the only live type-index constants).
- All using-aliases (`tvm::runtime::Object` etc.) rewritten to fully-
qualified `tvm::ffi::Object` at use sites — no using-injections
anywhere.
- `include/tvm/runtime/object.h` deleted.
## Test plan
- ninja build clean (USE_LLVM=ON, default targets) — exit 0.
- ./cpptest — 118/118.
- pytest tests/python/all-platform-minimal-test/ — green.
- pytest tests/python/runtime/ — green.
- pre-commit clean.
## Summary
`include/tvm/node/` is a leftover separation from when "node" was a
distinct concept from "ir". Today everything in `include/tvm/node/` is
just lower-level IR plumbing routinely included from `ir/`. This PR
collapses the two by moving surviving headers into `ir/`, deleting dead
ones, and redirecting the rest to tvm-ffi where the machinery already
lives.
Main changes:
- Migrate
`include/tvm/node/{functor,cast,script_printer,attr_registry_map,repr}.h`
→ `include/tvm/ir/` (functor renamed to `node_functor.h` to preserve
type-name connection)
- Delete `repr_printer.h`, `structural_equal.h`, `structural_hash.h`
(post-#19461 shims and forwarding stubs; redirect 3 cpptest consumers to
`tvm/ffi/extra/structural_equal.h`)
- Remove inline `AccessStep`/`AccessPath` `operator<<` definitions
(existing `__ffi_repr__` registrations already cover these; migrate to
generic ObjectRef streaming via kRepr)
- Move `src/node/{repr,script_printer}.cc` → `src/ir/`
- Delete `src/node/` and empty `include/tvm/node/` directories entirely
(no shims)
- Update 35 includers across IR, relax, script, target, tirx, and tests
This PR brings up the tirx namespace. We have been spliting out the
original tir namespace to include high-level component s_tir and this PR
updates the remaining low-level part as tirx namespace
* [FFI][REFACTOR] Cleanup namespace
This PR cleansup the namespace to ensure all ffi classes
are accessed through ffi:: namespace.
It will helps to cleanup the ffi package before isolation.
* fix hexagon
* cleanup relay c++
* [REFACTOR] Phase out relay c++ components
This PR phases out the relay C++ components and
simplifies the overall codegen runtime logic.
---------
Co-authored-by: Siyuan Feng <hzfengsy@sjtu.edu.cn>
This PR introduces support for TIR fragment printing.
Fragment printing makes it possible to print TIR fragments in the text
format consistency with TVMScript PrimFunc/IRModule printing.
This PR still preserves the legacy ReprPrinter format by introducing an
API `LegacyTIRPrint` for TIR PrimExpr. This method is used in
AutoScheduler and TIR CSE for full backward compatibility.
* Canonicalize type annotation during construction of Var and SizeVar
* Update tests/cpp/expr_test.cc
Co-authored-by: Junru Shao <junrushao1994@gmail.com>
* lint
* fix
Co-authored-by: Junru Shao <junrushao1994@gmail.com>
This change enables `cpplint` for the tests in `tests/cpp` and corrects any current linting errors. I had to use `NOLINT` in some of the PackedFunc tests due to a bug (see: https://github.com/cpplint/cpplint/issues/131) in CPPLint where `int(int)` is picked up as a cast rather than a nameless argument.
By using the `gtest_discover_tests` CMake macro the CPP and CRT tests can be configured to build binaries with a single test runner each. Once CTest has information about tests it can be used in IDE extensions such as [CMake Test Explorer](https://marketplace.visualstudio.com/items?itemName=fredericbonnet.cmake-test-adapter).
`ctest` can also run tests in parallel using the `-j` flag, which could be interesting in future.
TIR is the new namespace for low-level IR
for tensor-level optimizations and loop transformations.
This PR establishes the namespace and files.
- lowered_func.h,buffer.h,data_layout.h -> tir/buffer.h,tir/data_layout.h,tir/lowered_func.h
- ir.h -> tir/expr.h, tir/stmt.h
- ir_functor_ext.h -> tir/expr_functor.h, tir/stmt_functor.h
* [REFACTOR] introduce top - Tensor Operation DSL.
Historically we put Tensor, Schedule and compute under the root tvm namespace.
This is no longer a good idea as the project's scope grows larger
than the tensor operation DSL.
This PR introduces top -- a namespace for tensor operational
DSL concepts such as schedule, tensor, compute.
We moved the related files to the new top subfolder.
* Move relevant files into include/tvm/top and src/top
* [REFACTOR][IR] tvm::Expr -> PrimExpr(Primitive Expr)
As part of unified IR, we will need to unify relay::Expr
and the current tvm::Expr under the same base type.
From the techinical point of view. tvm::Expr is a "primitive"
expression that only contains POD types and handles and does
not do life-cycle management.
This PR renames Expr->PrimExpr to clarify that.
We will send a subsequent PR to introduce the base expr class.
* Remove legacy VarExpr and ExprHash/Equal
* [REFACTOR][OBJECT] Consoldiate NodePtr/Ref/Hash/Equal and macros to Object.
Historically, we have classes like NodePtr/Ref/HashEqual.
After unified object protocol, these names are just alias of the object counterpart.
Moreover, there are helper macros defined over the places for defining these object.
This PR consoldiate the terminologies into the corresponding ones
in the Object system so we have a clean and consistent API moving forward.
* Update include/tvm/attrs.h
Co-Authored-By: Wei Chen <ipondering.weic@gmail.com>
* fix compilation
Co-authored-by: Wei Chen <ipondering.weic@gmail.com>
* [REFACTOR][NODE][RUNTIME] Move Node to the new Object protocol.
This PR removes the original node system, and make node as a subclass of Object.
This is a major refactor towards a better unified runtime object system.
List of changes in the refactor:
- We now hide data_ field, use Downcast explicitly to get a sub-class object.
- Removed the node system FFI in python.
- Removed the node C API, instead use PackedFunc for list and get attrs.
- Change relay::Op::set_attr_type_key(attr_key_name) to relay::Op::set_attr_type<AttrType>().
- This change was necessary because of the new Object registration mechanism.
- Subsequent changes to the op registrations
- The change revealed a few previous problems that is now fixed.
- Patched up a few missing node type registration.
- Now we will raise an error if we register object that is not registered.
- The original node.h and container.h are kept in the same location.
- Calling convention: kObjectHandle now equals the old kNodeHandle, kNodeHandle is removed.
- IRFunctor now dispatches on ObjectRef.
- Update to the new type checking API: is_type, derived_from are replaced by IsInstance.
- Removed .hash member function, instead use C++ convention hasher functors.
* Address review comments