395 Commits

Author SHA1 Message Date
Hongyi Jin 05c487d69a [FIX][TIRx] Preserve pointer expression types (#20070)
## Motivation and context

A TIRx pointer carries two pieces of information that later lowering
needs: the pointee element type and the storage scope. Both must survive
when a pointer-producing expression is assigned to a Python name and
then used as the backing storage of a buffer.

A concrete example is accessing an mbarrier in another CTA through
distributed shared memory:

```python
ptr_ty = PointerType(PrimType("uint64"), "shared")
remote_ptr = T.reinterpret(
    ptr_ty,
    T.ptx.map_shared_rank(mbar.ptr_to([0]), T.int32(0)),
)
remote_mbar = T.decl_buffer(
    [1], "uint64", data=remote_ptr, scope="shared"
)
```

`map_shared_rank` returns the raw `uint64` address produced by PTX
`mapa`, and `reinterpret` gives that address the intended
`PointerType(uint64, shared)`. Because `decl_buffer(data=...)` requires
a pointer `Var`, assigning the expression to `remote_ptr` should create
an immutable typed pointer binding.

Before this PR, an unannotated assignment such as `remote_ptr = <pointer
expression>` followed the same parser path as a numeric assignment. That
path allocates a mutable local scalar and therefore cannot represent a
`PointerType`. The pointer expression could not be carried as a
correctly typed `Var` into `decl_buffer` and CUDA lowering.

This PR makes an unannotated pointer-valued assignment emit a TIRx
`Bind`. The bound `Var` has exactly the type of the right-hand side,
including its element type and storage scope. Pointer bindings are
immutable, so reassignment in the same scope is diagnosed; shadowing a
name supplied through `extra_vars` remains valid. Numeric assignments
keep their existing mutable-local behavior.

## Type propagation fixes

The parser fix exposed several other boundaries where pointer type
information must remain consistent:

| Boundary | Previous behavior | Behavior after this PR |
| --- | --- | --- |
| Unannotated pointer assignment | Tried to materialize the value as a
local scalar | Emits an immutable `Bind` with the RHS `PointerType` |
| `address_of(buffer)` / `buffer.ptr_to(...)` | Reused the raw backing
pointer type | Returns a pointer to `buffer.dtype` while preserving the
backing pointer storage scope |
| `tvm_access_ptr` / `ptr_byte_offset` | Accepted strings or annotation
expressions, but not a `PrimType` object directly | Accepts `PrimType`
and produces the corresponding typed pointer |
| Printed `T.ptx.mapa` call | The printer emits all intrinsic attributes
positionally, but the Python helper required keyword-only arguments |
Accepts the canonical printed form so pointer code round-trips through
TVMScript |

The `address_of` distinction matters for typed views over byte-addressed
storage. For example, if a `float32` buffer is backed by a `uint8*`
allocation in `shared.dyn`, the address of a buffer element must be
`PointerType(float32, shared.dyn)`, not `PointerType(uint8,
shared.dyn)`.

With these changes, the DSMEM example above round-trips through
TVMScript and CUDA codegen declares the remote buffer pointer as
`uint64_t*`.

## TMA dtype normalization

This PR also contains a small, separate type-representation fix in TMA
descriptor construction. `TmaPlan.elem_dtype` is a string consumed by
the host-side `runtime.cuTensorMapEncodeTiled` packed call, but
`_assemble_plan` stored `g_buf.dtype`, which is a `PrimType`. Converting
it with `str(g_buf.dtype)` ensures that the generated packed-call
argument is `StringImm("float16")` rather than an IR type object. This
does not change the pointer-binding semantics described above.

## Testing

- Verify that an unannotated pointer expression creates a `Bind` whose
`Var` type matches the RHS type.
- Verify that pointer reassignment is rejected while shadowing an
`extra_vars` name is allowed.
- Verify parser/printer structural round-tripping for the pointer
binding and canonical `T.ptx.mapa` call.
- Verify that `address_of` uses the logical buffer element type and
preserves the storage scope for byte-backed buffer views.
- Verify that `tvm_access_ptr` and `ptr_byte_offset` accept `PrimType`
inputs.
- Compile the DSMEM `map_shared_rank` example through the CUDA TIRx
pipeline and check for a typed `uint64_t*` remote buffer pointer.
- Verify that the TMA host initialization passes the descriptor dtype as
a `StringImm`.
2026-07-29 14:01:14 -04:00
Hongyi Jin ae99c3fd92 [TVMSCRIPT][TIRx] Preserve parser source spans in IR (#20073)
## Motivation and context

The TVMScript parser already tracks Python AST locations for
diagnostics, but TIRx statements and expression results emitted through
`IRBuilder` did not retain those locations. After parsing, a direct
intrinsic call, an inlined helper body, or a `TilePrimitiveCall`
therefore could not be traced back to the source range that produced it.

Inline expansion also needs more than a single flat location. The
generated IR should retain both the caller location and the
helper-definition location, while ordinary nested AST evaluation within
one source should not accumulate redundant enclosing spans.

## Changes

- Add an active source-span stack to `IRBuilder`, with scoped push/pop
support.
- Make the parser activate the current AST source range while visiting
statements and evaluating expressions.
- Attach the active span to emitted TIRx statements and to expression
results that do not already carry an explicit span.
- Normalize nested spans from the same source to the innermost relevant
range.
- Preserve cross-source inline expansion history as a `SequentialSpan`,
ordered from the call site to the expanded definition.
- Reuse the same source-coordinate calculation for diagnostics and IR
spans so their line and column conventions remain consistent.

Source spans remain diagnostic metadata: functions parsed from different
source locations keep the same structural hash and remain structurally
equal.

## Testing

- Verify exact parser source coordinates against diagnostic coordinates.
- Verify spans on direct intrinsic calls and `TilePrimitiveCall` nodes.
- Verify that inline expansion produces a `SequentialSpan` containing
caller and callee ranges.
- Verify direct `IRBuilder.with_source_span` behavior.
- Verify that source spans do not affect structural identity.
- Run changed-files pre-commit checks, including clang-format.

Focused result: 9 tests passed.
2026-07-29 13:51:57 -04:00
Tianqi Chen c717c5b217 [IR][Relax][TIRx] Unify Var identity (#20004) 2026-07-15 17:12:40 +08:00
Tianqi Chen 275114b327 [REFACTOR][IR] Unify PrimExpr with Expr typed view (#19910)
## 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.
2026-07-01 18:55:33 -04:00
Tianqi Chen 1e1920bcbd [REFACTOR][IR] Unify PrimExpr type mechanism to PrimType instead of DataType (#19875)
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
2026-06-24 21:31:47 -04:00
Shushi Hong 07e60343bc [Script][Tests] Fix dialect redirect module re-execution and stray category-less tirx.intrin_test op (#19731)
This PR fixes two independent test-isolation issues that only surface
when certain test files run together in one pytest session.

1. Fix `_DialectRedirectFinder` duplicate module execution

`_DialectRedirectFinder.find_spec` used to pre-register the redirect
target module under the legacy alias name before returning the alias
spec.

This interacts badly with CPython import logic: when the requested
module name is already in `sys.modules`, CPython may ignore the returned
alias spec and reuse the target module's original spec instead. As a
result, the target source can be executed again under the canonical
module name, creating a duplicate module object.

This caused patches on aliased modules to silently miss the module
object used by existing code. For example,
`unittest.mock.patch("tvm.tirx.script.builder.buffer_store")` patched
the duplicate module, while the tirx parser still held references to the
original one, so `test_scalar_assign_error_not_swallowed` failed with
`DID NOT RAISE`.

This pr removes the pre-registration and let the import machinery
register the alias normally. Since the alias spec is now used,
`_AliasLoader.exec_module` also restores the canonical `__spec__` and
`__loader__` to avoid stale alias metadata on the loaded module.

2. Remove unused `tirx.intrin_test` op registration

`test_s_tir_transform_lower_match_buffer.py` registered a dummy op:

```python
tvm.ir.register_op_attr("tirx.intrin_test", "")
```

This was a leftover from the old TVMScript parser and is no longer
needed. The modern tirx parser eagerly evaluates `intrin_test(...)`
calls into `T.evaluate(0)`, so this op never appears in parsed IR.

The only remaining effect was adding a category-less `tirx.intrin_test`
entry to the global op registry, which could break
`test_registered_tirx_ops_have_exactly_one_category` depending on test
import order.

This pr removes the unused registration.
2026-06-11 14:59:34 -04:00
Tianqi Chen 96cba60464 [PYTHON] Autoload backends; simplify library loading; remove TVMError for native errors (#19727)
This PR adds an autoload mechanism for out-of-tree backends, simplifies
TVM's Python library loading, and removes `TVMError` in favor of native
Python errors.

## Autoload out-of-tree backends

Out-of-tree packages can register an autoload callable under the
`tvm.backends` entry-point group (mirroring torch's device-backend
autoload). At `import tvm` startup each entry point is discovered and
its callable invoked once, after the core runtime and the `tvm`
namespace are fully initialized, so an extension can register
ops/targets/funcs or load extra libraries.

```toml
[project.entry-points."tvm.backends"]
tvm_foo = "tvm_foo:_autoload"
```

A failing extension is caught and surfaced via `warnings.warn` so it
cannot break `import tvm`. Autoload can be disabled with
`TVM_DEVICE_BACKEND_AUTOLOAD=0`.

## Simplify library loading

The library-loading path in `base.py` is consolidated around a single
`_LOADED_LIBS` dict (basename to ctypes handle) so downstream and
autoloaded extensions can skip already-loaded libraries; the per-backend
runtime DSO list is folded into `load_backend_libs`. Accumulated cruft
is removed: the Python-3.9 check, the readline shim, the `_FFI_MODE`
ctypes check, the `base.__version__` re-export, and `py_str` (call sites
inline `.decode("utf-8")`).

## Remove TVMError in favor of native Python errors

`TVMError` added a layer atop `RuntimeError` that downstream code had to
import and learn. It is removed; the registered FFI error kinds
(`InternalError`, `RPCError`, `OpError`, `DiagnosticError`,
`ScheduleError`) now subclass `RuntimeError` directly while staying
registered, so the FFI keeps throwing the right kinds. All `TVMError`
imports, `except`/`raise`/`isinstance` uses, and
`pytest.raises(tvm.TVMError)` sites move to the `RuntimeError` builtin.
2026-06-11 13:50:38 -04:00
Tianqi Chen 4d28424268 [REFACTOR][IR] Phase out diagnostic.h for visit-context-aware pass errors (#19722)
Replace TVM's `Diagnostic` / `DiagnosticContext` machinery with the
tvm-ffi
`visit_error_context` mechanism. Validators throw an `ffi::Error` seeded
with the
offending node; leaf pass executors (`ModulePass` / relax `Function` /
`DataflowBlock`) catch and rethrow `EnrichPassErrorWithContext`, which
appends the
failing pass name and a TVMScript-rendered, underlined source location.

`relax.analysis.well_formed` now throws on the first violation; a new
`check_well_formed` returns a bool, and all C++/Python/test callers are
routed
accordingly. `include/tvm/ir/diagnostic.h` and `src/ir/diagnostic.cc`
are deleted.
The enrichment renders with `num_context_lines=10` so a small function
shows in
full with no skipped-lines marker, while a large module stays bounded.

The TVMScript parser diagnostics
(`python/tvm/script/parser/core/diagnostics.py`)
stay self-contained pure-Python with no `DiagnosticContext` dependency,
and
restore multi-line source rendering: a diagnostic whose offending AST
node spans
multiple source lines now renders every spanned line with its gutter
line number
and an underline covering the span. `tvm.error.DiagnosticError` (used by
the
TVMScript parser) is retained.

A rendered end-to-end enriched-error example is posted as a comment
below.
2026-06-10 20:13:33 -04:00
Bohan Hou 9db74c7cee [TIRx] Update scoped ops and CUDA launch bounds (#19677)
## Summary

- replace the block-structured TIRx exec-scope surface with
scope-qualified `Tx.<scope>.<op>` namespaces and migrate call sites
- split TIRx op namespaces and remove the unused dynamic generic-op
fallback
- add explicit CUDA launch bounds plumbing through TIRx attrs and
split-host-device lowering

## Validation

- `git diff --check apache/main..HEAD`
- `pre-commit run --from-ref apache/main --to-ref HEAD`
2026-06-05 21:02:36 -04:00
Bohan Hou 859498dc01 [TIRx] Bringup TIRx Infrastructure (#19581)
## Summary

This PR adds the initial TIRx support needed for low-level programming
of Blackwell-class GPU architectures. As part of the ongoing TIRx
refactor, it introduces TVMScript support for directly scripting
advanced hardware features without relying on scheduling as the primary
programming interface.

The change keeps existing `s_tir` script support intact while making
direct scripting a first-class path for TIRx programs.

## Main Changes

- Add TIRx operator dispatch and layout infrastructure.
- Add TVMScript support for new low-level TIRx operations.
- Add analysis, transform, and lowering support for TIRx IR nodes.
- Add CUDA/Blackwell-oriented codegen and intrinsic coverage.
- Add Python and C++ integration points for TIRx scripting and runtime
support.

## Validation

- `pre-commit run --all-files`
- `ninja -C build -j32`
- `CUDA_VISIBLE_DEVICES=2 pytest tests/python/tirx/ -n 16`
  - `1723 passed, 47 skipped, 32 warnings`
- `CUDA_VISIBLE_DEVICES=2 python -m pytest -v
tests/python/all-platform-minimal-test`
  - `37 passed, 105 skipped`
- `TVM_TEST_TARGETS=llvm python -m pytest -v tests/python/tirx-analysis
tests/python/tirx-base tests/python/tirx-transform -n 16`
  - `664 passed, 25 skipped, 9 xfailed, 1 xpassed`

## Local CI Notes

Some full CI-equivalent jobs were not locally reproducible because this
machine is missing parts of the Apache TVM CI environment, including
`llvm-config-15/17`, Vulkan, ROCm, Maven, Sphinx, Doxygen, Emscripten,
and ARM/QEMU cross-toolchain components. Metal-specific tests were
skipped locally because no Metal runtime is available.
2026-05-18 16:44:43 -07:00
Tianqi Chen 7504e3ed1a [REFACTOR][SCRIPT] TVMScript dialect-friendly refactor: per-dialect restructure + dialect registry (#19479)
## Summary

Restructure TVMScript to be dialect-agnostic at the script-core layer
while letting each extension dialect (TIRX, Relax) own its own
per-dialect script subtree.  IR is below script in the dependency
stack and is NOT a peer dialect — its script handlers stay in the
shared core.

This PR folds together two coupled refactors that were initially
opened as separate PRs (#19478 and the original #19479); they
share rename / relocation surface so they ship as one cohesive
change.

## What this PR does

### Per-dialect script subtree (originally #19479)

- Moves per-dialect printer + builder from
  `src/script/{printer,ir_builder}/{tirx,relax}/` to
  `src/{tirx,relax}/script/{printer,builder}/`.
- Tightens `src/script/*.cc` CMake glob to the dialect-free core.
- Refactors `IRBuilder::DeclFunction` to dispatch via FFI registry
  (`script.ir_builder.decl_function.<type-key>`); removes
  cross-dialect includes from the shared core.
- Adds `tvm.script.register_dialect` API + `__getattr__` + a
  `sys.meta_path` finder for Python-side dialect discovery.
  In-tree dialects (tirx, relax) registered centrally in
  `python/tvm/__init__.py`.
- Drops the obsolete static re-export shims at
  `python/tvm/script/{parser,ir_builder}/{tirx,relax}/`.

### Dialect-agnostic printer config (originally #19478)

- Relocates `include/tvm/ir/script_printer.h` →
  `include/tvm/script/printer/config.h` next to the rest of the
  printer's public surface.  The header is not IR-specific.
- Renames `TVM_SCRIPT_REPR` → `TVM_REGISTER_SCRIPT_AS_REPR` for
  clarity (the macro registers Script as the kRepr callback +
  per-type vtable dispatch).  Aligns with the `TVM_REGISTER_*`
  family.
- Drops dialect-hardcoded `PrinterConfig` fields (`tir_prefix`,
  `relax_prefix`, `show_all_struct_info`, `buffer_dtype`) in favor
  of a generic `ffi::Map<String, Any> extra_config` keyed by
  `"<dialect>.<knob>"`.  Each call site reads via the templated
  accessor `config->GetExtraConfig<T>("...", default)`.
- Promotes `std::string` config fields to `ffi::String`.

After this lands, the script-printer core knows nothing specific
about any dialect — new dialects plug in via the registry pattern
with zero core edits.  Public Python API surface unchanged.
2026-04-30 07:22:56 -04:00
Tianqi Chen 6e8f77d664 [REFACTOR][RUNTIME][CODEGEN] Backend specific target and runtime to enable cross-compile fallback (#19465)
## Why

This refactor reshapes each backend into a self-contained
`src/target/<X>/`
cluster (with optional `src/target/<X>/llvm/` for LLVM-dependent
codegen) and
introduces a per-backend fallback module that absorbs the cross-compile
role
cleanly — without `target/opt/` stubs, without `DeviceSourceModuleNode`,
and
without leaking a synthetic `kind()` to consumers.

## High-level principles

- **One directory per backend.** All codegen-side files for backend
`<X>` live
under `src/target/<X>/`. Optional `src/target/<X>/llvm/` subdir for
files
  that require `USE_LLVM` at build time. Backend grouping wins over
build-dependency grouping (the latter being upstream's `target/llvm/`).
- **Plugin-only runtime modules.** `src/runtime/<X>/<X>_module.h` is
deleted.
The runtime's real `<X>ModuleNode` is reachable only via the FFI
registry
  (`ffi.Module.create.<kind>`, `ffi.Module.load_from_bytes.<kind>`). No
  C++ API surface other than the static registrations.
- **Per-backend fallback module for cross-compile.** Each `<X>` gets a
`<X>FallbackModuleNode` in `src/target/<X>/<X>_fallback_module.{h,cc}`.
Same `kind()` as the real module. Codegen-time only — never reachable
via
load. `GetFunction` errors with a backend-specific "runtime not linked"
  message; `InspectSource` works.
- **Codegen-side wrapper does the fallback selection.** Codegen calls
`<X>ModuleCreateWithFallback(...)`, which tries
`ffi.Module.create.<kind>`
  via the registry; on miss, falls through to `<X>FallbackModuleCreate`
(plain C++; reachable directly from the fallback header). When
`USE_<X>=ON`
  is in effect, the registry hit returns the real module; when
  `USE_<X>=OFF`, the fallback is what codegen gets. No CMake `if/else`
  gating; fallback always compiled.

## Specific changes

### New per-backend directories (codegen + fallback)

- `src/target/cuda/` — `codegen_cuda.cc` + `intrin_rule_cuda.cc` +
fallback module pair + `llvm/codegen_nvptx.cc`
- `src/target/rocm/` — fallback module pair + `llvm/codegen_amdgpu.cc` +
`llvm/intrin_rule_rocm.cc`
- `src/target/hexagon/` — fallback module pair +
`llvm/codegen_hexagon.cc` + `llvm/intrin_rule_hexagon.cc`
- `src/target/metal/` — `codegen_metal.cc` + `intrin_rule_metal.cc` +
fallback module pair
- `src/target/vulkan/` — `build_vulkan.cc` + the rest of `target/spirv/`
absorbed + fallback module pair
- `src/target/opencl/` — `codegen_opencl.cc` + `intrin_rule_opencl.cc` +
fallback module pair
- `src/target/webgpu/` — `codegen_webgpu.cc` + fallback module pair (was
`WebGPUSourceModuleNode`, renamed)

### New fallback classes

`<X>FallbackModuleNode` for X in {`CUDA`, `ROCm`, `Hexagon`, `Metal`,
`Vulkan`, `OpenCL`, `WebGPU`}. Each:
- `kind()` matches the real backend
- Stores `(code or smap, fmt, fmap, source)` — no driver/runtime calls
- `GetFunction` errors with backend-specific "runtime not linked"
message
- `InspectSource` works fully
- `SaveToBytes` byte-identical to real
2026-04-29 14:48:31 -04:00
Tianqi Chen 9edd5bd958 [REFACTOR] Remove tvm.runtime.packed_func and container shims; route via tvm_ffi (#19442)
## Summary

- Delete the three Python shim modules that re-exported tvm-ffi types
under `tvm.runtime` / `tvm.ir`:
`python/tvm/runtime/packed_func.py`, `python/tvm/runtime/container.py`,
`python/tvm/ir/container.py`.
- Drop the matching re-exports from `tvm.runtime`, `tvm.ir`, and `tvm`
package init files, so
`tvm.runtime.PackedFunc`, `tvm.runtime.ShapeTuple`,
`tvm.runtime.String`, `tvm.ir.Array`,
  `tvm.ir.Map`, and `tvm.container.Array` no longer exist.
- Migrate every productive caller, test, and tutorial to the canonical
names: `tvm_ffi.Function`,
`tvm_ffi.Shape`, `tvm_ffi.core.String`, `tvm_ffi.Array`, and
`tvm_ffi.Map`.

## Test plan

- [x] `pytest tests/python/all-platform-minimal-test` (75 passed, 77
skipped)
- [x] `pytest tests/python/runtime/test_runtime_container.py
tests/python/all-platform-minimal-test/test_runtime_packed_func.py` (20
passed)
- [x] `pytest tests/python/ir/test_node_reflection.py
tests/python/ir/test_container_structural_equal.py` (32 passed)
- [x] `pytest tests/python/relax/test_vm_build.py
tests/python/relax/test_vm_execbuilder.py
tests/python/relax/test_vm_codegen_only.py` (125 passed, 2 xfailed)
- [x] `pytest tests/python/relax/test_runtime_builtin.py
tests/python/relax/test_op_misc.py` (19 passed)
- [x] `pytest tests/python/target/test_target_target.py` (37 passed, 3
skipped)
- [x] `pre-commit run` clean on touched files
2026-04-25 11:02:08 -04:00
Shushi Hong 2345e6ea26 [Docs] Add API reference documentation for tvm.script module (#19366)
Add API reference documentation for tvm.script module
2026-04-08 00:58:00 -04:00
Soowon Jeong 93e28d1126 [BugFix][TVMScript] Fix invalid f-string format spec causing TypeError on Python 3.14 (#19362)
## Problem

On Python 3.14, any use of TVMScript raises a `TypeError` before the
module body is even parsed:

```
TypeError: unsupported format string passed to type.__format__
```

The traceback points to
`python/tvm/script/parser/core/diagnostics.py:120`:

```python
raise TypeError(f"Source for {obj:!r} not found")
```

## Root Cause

`{obj:!r}` is an invalid f-string expression. The `:` introduces a
`format_spec`, so `!r` is passed to `type.__format__` as a format string
— which it does not support.

The intended syntax for a `repr()` conversion is `{obj!r}` (no colon).

Python 3.14 re-implemented f-string parsing under [PEP
701](https://peps.python.org/pep-0701/) and now strictly validates
format specs, surfacing this latent bug. Python 3.10–3.13 silently
passed the invalid spec to `__format__` and happened not to raise in
most code paths, so the bug went unnoticed.

## Fix

```diff
- raise TypeError(f"Source for {obj:!r} not found")
+ raise TypeError(f"Source for {obj!r} not found")
```

One character change. Valid across all Python versions >= 3.6.

## Testing

Verified on Python 3.14.2 (darwin/arm64):

- TVMScript `ir_module` + `prim_func` parses and compiles correctly
after the fix
- Full TVMScript test suite: **628 passed, 1 xfailed** (the 1 failure in
`test_tvmscript_roundtrip.py::test_roundtrip[relax_symbolic_size_var]`
is pre-existing and unrelated to this change)
2026-04-06 14:49:23 -04:00
liggest 36a82f5159 [BugFix][TVMScript] Add doc.keyword handling for ExprEvaluator._visit (#19352)
Add handling for `doc.keyword` nodes in `ExprEvaluator._visit` to ensure
expressions (e.g. `BoolOp`) in keyword arguments are processed with
correct evaluation methods.

Fix #18972 . For more details, please refer to this issue.
2026-04-05 12:27:09 -04:00
Tianqi Chen 141c22fd8a [Refactor] Bring up tirx namespace (#18913)
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
2026-03-19 21:27:54 -07:00
Tianqi Chen 87bd8af37d [TVMScript] Remove T.Bind backward-compat alias (#18891)
## Summary
- Remove `Bind = bind` backward-compat alias from `ir.py`
- Remove `"Bind"` from `__all__` exports
- Follows #18889 which renamed `T.Bind` → `T.bind`

## Test plan
- [x] tvmscript roundtrip/printer/ir_builder tests pass (232 passed)
- [x] pre-commit lint passes
2026-03-09 08:09:06 -04:00
Tianqi Chen f83cebb54c [TVMScript] Normalize T.Bind to T.bind for statement builder convention (#18889)
## Summary
- Rename `T.Bind` (capitalized) to `T.bind` (lowercase) to match
TVMScript naming convention: statement builders use lowercase
(`T.evaluate`, `T.buffer_store`, `T.bind`), expression constructors use
capitalized (`T.Cast`, `T.Select`, `T.Let`)
- Keep `Bind = bind` backward-compat alias
- Update parser, printer references, and all test files

## Test plan
- [x] tvmscript tests (771 passed)
- [x] tir-transform tests (346 passed)
- [x] tir-base tests (224 passed)
- [x] pre-commit lint passes
2026-03-08 18:29:24 -04:00
Tianqi Chen 72de122676 [TIR][REFACTOR] Revamp Common Subexpression Elimination (#18886)
## Summary

This PR do a rebuild of TIR Common Subexpression Elimination (CSE) using
a two-phase architecture:

- **Phase 1 — CSEPlanner**: Read-only visitor that builds a scope tree
and expression DAG. Computes a plan (InsertBeforeTable + ExprRemapTable)
in a single pass using shallower-first processing with repr propagation
— no cascade loop needed.
- **Phase 2 — CSERewriter**: Mechanical mutator that inserts
`Bind(cse_var, expr)` statements and substitutes expressions per the
plan.

Key improvements over the old implementation:
- **Simpler architecture**: Two clean classes (planner + rewriter)
instead of interleaved analysis/mutation
- **No cascade loop**: Shallower-first processing with repr propagation
resolves all CSE opportunities in one plan + one rewrite
- **Incremental DAG construction**: Expression depth, children, and
consumed counts computed during bottom-up scan — no separate traversals
- **No single-use bindings**: Consumed count tracking avoids introducing
bindings that would only be used once
- **Unified insertion via VisitStmt**: SeqStmt flattening handles all
insertion contexts uniformly

Other changes:
- Rename `CommonSubexprElimTIR` → `CommonSubexprElim`, remove
`enable_cse_tir` and `identify_equiv_terms` params
- Move old CSE tools (used by cache_index) to
`cache_index_helpers.{cc,h}`
- Remove unused `arith.detect_common_subexpr` API
- Add `T.bind` as lowercase alias for `T.Bind`
2026-03-07 18:38:50 -05:00
Tianqi Chen 689d2b51b2 [REFACTOR][TIR] Remove body from AllocBuffer and DeclBuffer (#18876)
## Summary

- Remove `body` field from `AllocBufferNode` and `DeclBufferNode`,
making them flat statements consistent with `Bind`
- Buffer scope extends to end of enclosing scope via flat `SeqStmt`
semantics
- 60 files changed across core IR, codegen backends, transforms, script
IR builder, and tests

## Test plan

- All existing test suites pass (tir-transform, tir-base, tvmscript,
s_tir, codegen, C++)
2026-03-06 06:47:20 -05:00
Tianqi Chen 079e4af391 [REFACTOR][TIR] Rename LetStmt to Bind and flatten to sequential semantics (#18874)
## Summary

Rename `LetStmtNode`/`LetStmt` to `BindNode`/`Bind` and remove the
`body` field.
The variable defined by `Bind(var, value)` is now visible in all
subsequent
statements within the same enclosing scope, rather than being scoped to
a nested body.

This flattens deeply nested let-chains into sequential
`SeqStmt([Bind(...), Bind(...), ...])`,
making the IR easier to read, transform, and analyze.

## Key Changes

- **New `BindNode`**: `{var, value}` — no body field. Variable scope is
the enclosing
  statement's body (For, IfThenElse, AllocBuffer, etc.)
- **ScopeStack pattern**: Passes that need scope-aware cleanup
(ConvertSSA, CSE,
tir_visitor_with_path) use `ScopeStack` instead of manual save/restore
or RAII wrappers
- **All passes migrated**: 89 files updated across codegen backends, TIR
transforms,
  S-TIR transforms, analyses, TVMScript printer/parser/ir_builder
2026-03-05 08:55:02 -05:00
Tianqi Chen 0fba1606be [REFACTOR][TIR] Introduce AllocBuffer and phase out Allocate+DeclBuffer (#18865)
## Summary

This PR introduces `AllocBufferNode`/`AllocBuffer` as a single TIR
statement that both allocates memory and declares a buffer into scope.
This replaces the previous pattern of `Allocate(var, dtype, shape, cond,
DeclBuffer(buf, body))` with the simpler `AllocBuffer(buf, body)`.

### Main changes

- **New IR node** `AllocBufferNode` with fields `{buffer, annotations,
body}` — same semantics as `DeclBuffer` but also allocates memory
- **TVMScript**: `T.alloc_buffer(shape, dtype, scope)` now emits
`AllocBuffer` directly (statement-level allocation).
`T.sblock_alloc_buffer(...)` for SBlock-level buffer allocation (full
parameter set)
- **All codegen backends** (C, CUDA, Metal, OpenCL, WebGPU, LLVM, NVPTX,
AMDGPU, SPIR-V) updated to handle `AllocBufferNode`
- **All TIR transforms** (storage_rewrite, flatten_buffer,
vectorize_loop, lower_warp_memory, etc.) updated
- **All S-TIR transforms** (compact_buffer_region, merge_shared_memory,
inject_double_buffer, etc.) updated
- **Removed `AllocateNode`** entirely — `AllocBuffer` is now the sole
allocation primitive
- **Removed `AllocDescriptor`** from merge_shared_memory_allocations —
uses `Buffer` objects directly
- **Added `AllocBuffer::ConstantAllocationSize()`** inline helper method

### Design rationale

The old `Allocate + DeclBuffer` pair was a historical artifact:
`AllocateNode` stored raw fields (`buffer_var`, `dtype`, `extents`,
`condition`) separate from the `Buffer` object, requiring pattern
matching (`IsAllocateDeclBufferPattern`) to reconstruct the buffer
association. `AllocBuffer` unifies this into a single node with a proper
`Buffer` reference, simplifying codegen backends and transform passes.

225 files changed, ~3500 insertions/deletions (net near-zero, mostly
mechanical migration).

## Test plan

- [x] All TIR base tests pass
- [x] All TIR transform tests pass
- [x] TVMScript roundtrip tests pass
- [x] S-TIR transform tests pass
- [x] Codegen tests pass
- [x] All-platform minimal tests pass
- [x] C++ functor tests pass
- [x] Pre-commit clean (clang-format, ruff, etc.)
2026-03-04 11:59:20 -05:00
Tianqi Chen 611a815dc1 [TIR][Refactor] Enhance error reporting with structured AssertStmt and TVMFFIABIBuilder (#18857) 2026-03-02 07:52:53 -05:00
Tianqi Chen 61f80814e6 [TVMScript] Fix PEP 563 closure variable resolution (#18856)
With `from __future__ import annotations`, Python stores annotations as
strings
and does not capture annotation-only variables in `__closure__`. This
broke
TVMScript when buffer shapes/dtypes referenced closure variables.

Fix: wrap `extra_vars` in a `collections.ChainMap` with snapshots of all
live
caller-frame locals (from `inspect.stack()`) as fallback layers in both
`tir/entry.py` (`prim_func`) and `ir/entry.py` (`ir_module`). The
`ir_module`
function now also captures `outer_stack = inspect.stack()` at its entry
point,
mirroring the existing pattern in `prim_func`. Lookup falls back to
frame locals
only on cache miss, preserving existing behavior for non-PEP-563 code.

Add `tests/python/tvmscript/test_tvmscript_pep563_closure.py` (requires
`from __future__ import annotations` at the top) covering closure
variables in
buffer shapes, dtypes, nested scopes, ir_module, and mixed
annotation+body use.
2026-02-28 22:38:50 -05:00
Tianqi Chen 2fd4e11194 [PYTHON] Fix PEP 563 compat and remove args_converter (#18847) 2026-02-28 10:41:10 -05:00
Tianqi Chen 9a8320acbd [LINT][PYTHON] Modernize annotations with ruff UP rules (#18830)
This PR enables ruff pyupgrade (UP) rules with py310 target, auto-fixing
~5600 annotation modernizations (PEP 585 generics, PEP 604 unions,
deprecated typing imports).

Also removes from __future__ import annotations from ir/module.py and
rmsnorm.py, bumps requires-python to >=3.10, and removes absolute_import
aliases from topi/contrib files.
2026-02-27 21:29:47 -05:00
Tianqi Chen 33dcea1686 [REFACTOR][LINT] Modernize ruff config (#18810)
This PR removes the extra lint violations from the codebase so lint
aligns with the latest style
2026-02-23 07:29:21 -05:00
Tianqi Chen 7ac12ebdd8 [CI] Add GitHub Actions lint workflow (#18809) 2026-02-22 13:31:19 -05:00
Tianqi Chen aa2e609136 [LINT] Modernize lint to use pre-commit hooks (#18807)
This PR migrates existing lint to use pre-commit hooks
2026-02-22 11:03:21 -05:00
Tianqi Chen 6e08d90425 [REFACTOR][TIR] Phaseout BufferRealize (#18763)
This PR Phases out BufferRealize which is a legacy node in TE schedule
and no longer needed here.
2026-02-12 09:13:18 -05:00
Tianqi Chen c08a701ad1 [REFATOR][TIR] Phase out AllocConst (#18761)
This PR phases out alloc const node in the TIR.
This node was oroginally introduced to include embedded weights into the
allocation. However, the presence of the particular IR couples the data
allocation and the weight placement, which is not as desirable especialy
when weights get large. A better approach is to have extra annotation on
the allocation and store weights separately either outside module or as
part of module/function attribute.

As a result, we phases out this node which can help us to simplify code
logic in the codebase.
2026-02-11 21:17:33 -05:00
Tianqi Chen adda179705 [REFACTOR][S-TIR] Lift dlight into s_tir namespace (#18734)
This PR migrates dlight into s_tir namespace, so s_tir related
components are closely grouped together.
2026-02-08 20:20:11 -05:00
Tianqi Chen 87c1e471b0 [REFACTOR] Migrate old tir.ir_builder to tvmscript or builder (#18716)
This PR migrates legacy tir.ir_builder infavor of tvmscript or builder.
2026-02-06 10:34:13 -05:00
Tianqi Chen 877b448b02 [REFACTOR][TIR] Rename tir.Block to SBlock (#18689)
This PR renames tir.Block to SBlock. This clearly indicate the
scheduable property of the block and is a prereq for followup stir
passes refactor.

Main changes:

- Data structure change from Block to SBlock
- Syntax change from T.block to T.sblock
2026-01-28 08:02:10 -05:00
Kathryn (Jinqi) Chen 2004a8bcbf [NVRTC] Add NVSHMEM support to NVRTC compilation path (#18681) 2026-01-24 14:52:51 -05:00
Guan-Ming (Wesley) Chiu fed71ef6a6 [Relax] Add native size operator (#18667)
## Why

ONNX models use the Size operator to get total element count of a
tensor. Relax didn't have a native equivalent.

## How

- Adds R.size(tensor) operator that returns the total number of elements
in a tensor as a scalar int64
2026-01-20 21:34:36 +08:00
Siva 8e40211388 [ADRENO][TEXTURE] Texture based lowering (#18523)
Introduces the below features over texture annotation

- Lowering, codegen and runtime for texture.
- image2d_array_t support - Added depth dimension allows more
allocations using texture instead of falling back to buffer when the
texture limits exceeds.
- A comprehensive set of schedules for Adreno textures.
- Texture packing of arbitrary types up to 128 bit (FP16-NCHW8c,
INT8-NCHW16c ...etc.).
- A clBufferDescriptor debug dump controlled by cmake options.
- Pipeline definition for adreno target.


While covering these features the below interfaces or passes or enhanced
which need a review.

- alloc_tensor: VDevice information is passed across these API's. The
way of texture allocation is ```alloc_storage``` allocates buffer/image
objects as requested followed by alloc_tensor being a view of any scope.
This takes care of optimum utilization backing memory across different
image objects or scopes.
- Constants Saving: Handled by adding memory scope section in
executable. This introduces a new header magic to retain the backward
compatibility.
- Static Memory Planing: Mostly port from Relay static memory planner
with mixed mode allocator.

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Sanjay <sanjs@qti.qualcomm.com>
2026-01-09 14:15:08 -05:00
Kathryn (Jinqi) Chen fa905d2b69 [Compile] accelerate compilation speed using NVRTC (#18519)
This PR supports NVRTC as an alternative to NVCC for faster, device-side
JIT compilation of CUDA kernels, in favor of the PR
[https://github.com/apache/tvm-ffi/pull/283](https://github.com/apache/tvm-ffi/pull/283).

It enhances the CUDA compilation backend by:
- Adding Python NVRTC support using cuda-python bindings
- Removing legacy C++ NVRTC fallback in favor of a Python-first approach
- Keeping nvcc as the default compiler with fatbin output (no behavior
change for existing users)

Users can choose the compilation backend using an environment variable
`TVM_CUDA_COMPILE_MODE`, choosing from "nvcc" and "nvrtc". For example,

`TVM_CUDA_COMPILE_MODE=nvrtc python3 your_program.py`

Here is a short benchmark of the compilation speed of kernels in
`test_target_codegen_cuda.py`.

### NVCC vs NVRTC Compilation Time Comparison (Python-side Call)

| Test Case | Code Size | NVCC Time (ms) | NVRTC Time (ms) | Speedup |
| :--- | :--- | :--- | :--- | :--- |
| `test_crossthread_reduction1` | 1945 B | 241.27 | 51.23 | **4.7x** |
| `test_cuda_bf16_vectorize_add` | 3760 B | 342.72 | 44.50 | **7.7x** |
| `test_cuda_const_float_to_half` | 12394 B | 272.85 | 31.99 | **8.5x**
|
| `test_cuda_device_func_call` | 975 B | 215.58 | 21.47 | **10.0x** |
| `test_cuda_float_const_hex_format` | 685 B | 217.39 | 20.52 |
**10.6x** |
| `test_cuda_floordiv_with_vectorization` | 1050 B | 213.88 | 23.32 |
**9.2x** |
| `test_cuda_inf_nan` | 673 B | 214.33 | 24.94 | **8.6x** |
| `test_cuda_tensormap` | 755 B | 213.91 | 20.74 | **10.3x** |
| `test_cuda_thread_sync_inside_condition` | 1007 B | 213.43 | 28.29 |
**7.5x** |
| `test_cuda_vectorize_add` | 908 B | 226.81 | 40.39 | **5.6x** |
| `test_cuda_vectorize_load` | 734 B | 217.25 | 24.02 | **9.0x** |
| `test_device_host_call_same_func` | 924 B | 216.03 | 21.21 | **10.2x**
|
| `test_vectorized_intrin1` | 847 B | 226.15 | 26.34 | **8.6x** |

### NVSHMEM Support

Currently, NVSHMEM is **not** supported via NVRTC.
- Fallback Behavior: When NVSHMEM is required, the compilation pipeline
will automatically fall back to NVCC, even if `TVM_CUDA_COMPILE_MODE` is
set to nvrtc.
- Future Roadmap: Support for NVRTC with NVSHMEM is planned for
follow-up PRs.
2026-01-08 11:08:06 -05:00
Nguyen Duy Loc 899556d2da [Relax][Op][PyTorch] Supported Median operator (#18626)
## Summary:
- Supported Median operator: Add relax.median & Apply median op into
exported_program_translator
- Input: Tensor, Axis, KeepDim
- Output: (Values, Indices)
## Expected:
### 1. Axis = None, KeepDim = False
```
class MedianWithoutDim(nn.Module):
    def forward(self, x):
        return torch.median(x)
```

```
class Module:
    def main(x: R.Tensor((2, 3, 4), dtype="float32")) -> R.Tuple(R.Tensor((), dtype="float32")):
        with R.dataflow():
            lv: R.Tensor((), dtype="float32") = R.median(x, axis=None, keepdims=False)
            gv: R.Tuple(R.Tensor((), dtype="float32")) = (lv,)
            R.output(gv)
        return gv
```


### 2. Axis = 0, KeepDim = False
```
class MedianDim(nn.Module):
    def forward(self, x):
        return torch.median(x, dim=0)
```
```
class Module:
    def main(x: R.Tensor((2, 3, 4), dtype="float32")) -> R.Tuple(R.Tensor((3, 4), dtype="float32"), R.Tensor((3, 4), dtype="int64")):
        with R.dataflow():
            lv: R.Tuple(R.Tensor((3, 4), dtype="float32"), R.Tensor((3, 4), dtype="int64")) = R.median(x, axis=[0], keepdims=False)
            lv1: R.Tensor((3, 4), dtype="float32") = lv[0]
            lv2: R.Tensor((3, 4), dtype="int64") = lv[1]
            gv: R.Tuple(R.Tensor((3, 4), dtype="float32"), R.Tensor((3, 4), dtype="int64")) = lv1, lv2
            R.output(gv)
        return gv
```
### 3. Axis = -1, KeepDim = True
```
class MedianKeepDim(nn.Module):
    def forward(self, x):
        return torch.median(x, dim=-1, keepdim=True)
```
```
class Module:
    def main(x: R.Tensor((2, 3, 4), dtype="float32")) -> R.Tuple(R.Tensor((2, 3, 1), dtype="float32"), R.Tensor((2, 3, 1), dtype="int64")):
        with R.dataflow():
            lv: R.Tuple(R.Tensor((2, 3, 1), dtype="float32"), R.Tensor((2, 3, 1), dtype="int64")) = R.median(x, axis=[-1], keepdims=True)
            lv1: R.Tensor((2, 3, 1), dtype="float32") = lv[0]
            lv2: R.Tensor((2, 3, 1), dtype="int64") = lv[1]
            gv: R.Tuple(R.Tensor((2, 3, 1), dtype="float32"), R.Tensor((2, 3, 1), dtype="int64")) = lv1, lv2
            R.output(gv)
        return gv
```
2026-01-02 23:12:48 +08:00
Guan-Ming (Wesley) Chiu 26b107fa12 [Relax][PyTorch] Add support for masked_select (#18535)
## How

Add support for masked_select
2025-12-07 14:59:25 -05:00
Guan-Ming (Wesley) Chiu ced7181708 [TVMScript] Add block name suffix management for TIR macros (#18465)
## Related Issue

closes https://github.com/apache/tvm/issues/18344

## Why

When a `T.macro` containing a block was called multiple times in a TIR
function, all expanded blocks had the same name, causing a "Duplicated
block name" error in meta_schedule.

## How

Implemented automatic block name suffixing during macro expansion
2025-11-25 01:34:23 -05:00
wrongtest 13ea9dc104 [TIR] Add step attribute to ForNode (Initial codes) (#18421)
An initial change to add `ForNode::step`.

- Add `Optional<PrimExpr>` typed step attribute to ForNode. Then add
minimal codes for
    - Roundtrip support for TIR tvmscript grammar
    - Correctness of TIR lowering pipeline:
        - Canonicalize the loop in default pipeline
- Ensure the original `ForNode::step` is not dropped by mutations on
`ForNode`.
    - CodeGen support for non-zero min and non-trivial step.

- TODOs in the future (hopefully)
- For **all transformations and analysis tools**, make adaptions to
non-consecutive loop iteration indices
    - Correctness of TensorIR schedule and MetaSchedule

---------

Co-authored-by: baoxinqi <bao.xinqi@intellif.com>
2025-11-24 08:30:16 -05:00
Tianqi Chen b6ac0721a0 [DataType] Update to use explicit Bool Type Aligning with DLPack (#18453)
This PR updates the project to use explicit bool type which helps us to
align with dlpack. It will also streamline explicit use of bool types.
2025-11-14 20:47:42 -05:00
Shushi Hong c00c66259a [Relax][ONNX] Support AllClassNMS Operator for ONNX Frontend (#18321)
Follow #18175 , this PR supports AllClassNMS Operator for ONNX Frontend
2025-10-01 16:09:59 -04:00
Siyuan Feng 36e473f58b [TIR] Support sequence comparisons in TVMScript (#18341)
Implement proper parsing and evaluation of chained comparison operators
(e.g., `0 < i < 128`) in TVMScript. The sequence comparisons are now
correctly expanded to their logical equivalents (e.g., `(0 < i and i < 128)`).

Changes:
- Updated expression evaluator to handle sequence comparisons correctly
- Added test case to verify sequence comparison functionality
2025-09-25 15:12:31 -04:00
Siyuan Feng 7ec2d35665 [TIR] Add support for conditional expressions in TVMScript (#18323)
Add support for conditional expressions in TVMScript

This PR adds support for conditional expressions in TVMScript parser,
which allows developers to use Python-style conditional expressions

```python
@T.prim_func
def func(A: T.buffer((128, 128), "float32")):
    for i, j in T.grid(128, 128):
        A[i, j] = i if i < j else j

@T.prim_func
def expected(A: T.buffer((128, 128), "float32")):
    for i, j in T.grid(128, 128):
        A[i, j] = T.if_then_else(i < j, i, j)
```
2025-09-20 09:13:52 -04:00
Shushi Hong 4041f890ce [Relax] Introduce R.call_py_func operator for calling Python functions from Relax IR (#18313)
This PR allows calling Python functions directly from Relax IR,
where integration between Relax computations and Python/PyTorch
operations can be supported.

### Usage Example
```python
@I.ir_module
class MyModule(BasePyModule):
    @I.pyfunc
    def pytorch_add(self, x, y):
        return x + y
    
    @R.function
    def compute(x: R.Tensor((5,), "float32"), y: R.Tensor((5,), "float32")) -> R.Tensor((5,), "float32"):
        result = R.call_py_func("pytorch_add", (x, y), out_sinfo=R.Tensor((5,), "float32"))
        return result
```
2025-09-19 09:28:05 -04:00
wrongtest 657ebbb217 [TVMScript] Support continue and break in tvmscript (#17804)
* support continue and break in tvmscript

* fix black format

* fix pylint issue

* Update tests/python/tvmscript/test_tvmscript_syntax_sugar.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* add printer/parser test, fix lint

* Fit to latest ffi update

* Skip i386 numpy-related test

* Introduce AnnotateIrregularLoop before any lowering loop expansions.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-19 10:00:56 +08:00
Tianqi Chen 543e64dbb1 [FFI][REFACTOR] Cleanup tvm_ffi python API and types (#18277)
This PR cleans up the python API to make things more consistent
with existing python array api and torch.

Device update
- device_id => index, to be consistent with torch
- device_type => dlpack_device_type() returns int
- added type property same as torch.device

API updates:

- Move the convenient method like cpu() out into tvm runtime to keep device minimal
- tvm_ffi._init_api => tvm_ffi.init_ffi_api
- tvm_ffi.register_func => tvm_ffi.register_global_func
2025-09-07 10:38:50 -04:00