## Summary
- Make `PrimExpr` a typed C++ view over `Expr` values whose
`ExprNode::ty` is `PrimType`, instead of using a separate runtime node
class as the proof of primitive-ness.
- Use the shared `ir::Call` node for Relax, TIRX, and primitive-valued
calls, while keeping primitive-only APIs explicit at their semantic
boundaries.
- Keep Python on the general `Expr` surface for primitive-typed values
so `isinstance` behavior does not imply a nominal primitive-expression
subclass.
## Design Rationale
The main advantage of this change is that common expression nodes such
as `Call` can be unified without specializing each one to `PrimType`. A
single `ir::Call` can represent a Relax tensor call, a Relax scalar
call, or a primitive-valued intrinsic call; the result type stored in
`ExprNode::ty` determines whether that particular value can be viewed as
`PrimExpr`.
This keeps the IR node hierarchy focused on expression structure rather
than result-type categories. Nodes that are intrinsically primitive,
such as integer and floating-point literals or TIRX primitive operators,
still have strongly typed C++ APIs and data structures. General nodes
whose result type may vary, such as `Call`, remain general `Expr` nodes
and are narrowed to `PrimExpr` only where primitive-only semantics are
required.
The PR also keeps the compatibility surface practical: C++
primitive-only APIs continue to accept `PrimExpr`, Python exposes a
compatibility predicate for checking the primitive typed category, and
visitors/printers use one natural `Call` path rather than duplicating
Relax and primitive call handling. Missing expression types are
represented explicitly with `Type::Missing()` so constructors can leave
type inference to later analysis without relying on nullable `Type`
values.
This PR lets Relax expressions directly take `PrimExpr` values without
requiring the explicit `PrimValue` wrapper, continuing the Relax IR
unification work by removing Relax-specific leaf/base expression layers.
Summary:
- Remove `LeafExpr` / `LeafExprNode` and use direct expression-node
checks where needed.
- Converge Relax expression typing onto the shared IR `Expr` base.
- Remove the `PrimValue` node wrapper while keeping `relax.prim_value` /
`R.prim_value` as conversion helpers that return existing `PrimExpr`
values unchanged.
- Register direct `PrimExpr` handling through exact concrete node
dispatch, aligned with the `tirx` expression visitor list and excluding
arith iter-map intermediate nodes.
- Inline the private Python primitive conversion helper into public
`relax.prim_value`.
- Handle direct `PrimExpr` values in frontend scalar paths without
assuming a `.value` field on non-immediate expressions.
DPL (`tvm.relax.dpl`) is heavily used across the TVM stack — operator
fusion, CUTLASS/cuBLAS/cuDNN backend dispatch, and user-defined graph
transforms all rely on it. Since there is no doc explaining how to use
it, this pr adds deep-dive documentation
(`docs/deep_dive/relax/dpl.rst`) covering DPL's pattern construction,
matching, rewriting APIs, and integration with `FuseOpsByPattern`
backend dispatch passes.
This PR is a follow-up of #18965
- Fix incorrect variable names in Relax dataflow code example (`lv0` →
`lv`, `b` → `n`) in
`docs/deep_dive/relax/learning.rst`
- Fix `func.time_evaluator(func.entry_name, ...)` to
`func.time_evaluator("add_one", ...)`
in `docs/how_to/tutorials/cross_compilation_and_rpc.py`, since
`entry_name` is a class
constant `"main"` but the compiled function is named `"add_one"`
- Fix typo `tvfm.testing` → `tvm.testing` in
`docs/how_to/dev/pytest_target_parametrization.rst`
- Add missing `tvm.relax.frontend.tflite` automodule entry to
`docs/reference/api/python/relax/frontend.rst`
- Fix incorrect function names (`lnumpy_matmul`→`lnumpy_linear`,
`lnumpy_relu`→`lnumpy_relu0`) and undefined variables (`lv0`→`lv`,
`b`→`n`) in Relax learning tutorial
- Add missing `I`, `T`, `R` imports in Relax and TensorIR learning
tutorials
- Update `pass_infra.rst` to match current source: fix `PassInfoNode`
field order and add `traceable`, correct `PassContextNode`
array types (`Expr`→`String`), remove obsolete `StringImm` cast in
`SequentialNode`, and add `traceable` param to `Create*Pass`
signatures
- Replace stale `PrintIRBefore`/`PrintAfter` TODOs with
already-implemented instruments (`PrintBeforeAll`, `PrintAfterAll`,
`PassPrintingInstrument`, `DumpIR`)
- Add missing `tvm.relax.op.vision` and `tvm.relax.op.vm` to API
reference
- Add `PythonDomain.find_obj` patch to resolve ambiguous
cross-references for classes that exist in multiple TVM namespaces (e.g.
`StringImm` in both `tvm.relax` and `tvm.tirx`). This is a general
solution that reuses the existing `tvm_class_name_rewrite_map` and also
benefits `Var`, `Call`, etc.
[REFACTOR] Phase out getattr based attribute handling
This PR phases out getattar based attribute handling as they are slower
and introduces extra code path.
This does mean that if an Object is not explicitly registered
in python side, we will no longer be able to access the field by name.
Likely this is also desirable as we would like to enable faster use that
updates the python end and do not rely on these behavior.
* [Docs] Introduce Relax API and move legacy part to standalone page
As the TVM project evolves, the Unity strategy has been the recommended
way to use Apache TVM applications. Hence, we are pushing documentation
for the Relax API to the forefront and moving the legacy part to a
standalone page, which may be removed in the future.
* update for ci
* update for ci