Skip to content

[Relax][Frontend][ONNX] Support dynamic index for Gather on shape#19967

Closed
hamzaqureshi5 wants to merge 297 commits into
apache:v0.24.0from
hamzaqureshi5:fix/onnx-gather-dynamic-shape-index
Closed

[Relax][Frontend][ONNX] Support dynamic index for Gather on shape#19967
hamzaqureshi5 wants to merge 297 commits into
apache:v0.24.0from
hamzaqureshi5:fix/onnx-gather-dynamic-shape-index

Conversation

@hamzaqureshi5

Copy link
Copy Markdown

The ONNX importer's Gather converter asserted that indices must be a constant whenever the data operand is a ShapeExpr, raising "Only constant indices supported for shape gather." for any runtime-computed index. Detection post-processing graphs such as FasterRCNN feed a dynamic index into a Gather whose data comes from a Shape node, so import failed before compilation could start.

Keep the constant-index fast path, which resolves a single dimension to a PrimValue and preserves shape-specialized handling downstream. For a dynamic index, materialize the shape as an int64 tensor via shape_to_tensor and gather from it at runtime, mirroring how Reshape already handles ShapeExpr inputs.

Adds a regression test that gathers a dimension out of a Shape result using a non-constant index and checks it against onnxruntime.

Fixes part of #19965.

tqchen and others added 30 commits May 26, 2026 15:30
…elete the util (apache#19612)

## Summary

`ApplyPassToFunction` is a general-purpose wrapper that runs a pass on
only the functions in an IRModule whose name matches a regex. Its sole
in-tree production callers are `DecomposeOpsForInference` /
`DecomposeOpsForTraining` in `src/relax/transform/decompose_ops.cc`, and
both callers always supply a literal function name (never a regex
pattern). Inlining the logic as a file-local helper simplifies the
module-level context and removes an abstraction that exists only to
support one use case.

- Inline the helper as `ApplyDecomposeToFunction` (exact-name match, not
regex) in `src/relax/transform/decompose_ops.cc`
- Delete `src/ir/apply_pass_to_function.cc`, its `transform.h`
declaration, and the Python wrapper in `python/tvm/ir/transform.py`
- Remove two DCE tests
(`test_compatibility_with_apply_pass_to_function`,
`test_well_formed_output_with_restricted_scope`) that tested the
utility's plumbing rather than DCE behavior
…ression, and rename Simplify to StmtSimplify (apache#19604)

## Summary

This PR cleans up technical debt in the TIR simplification machinery via
two commits:

**Commit 1: Phase out ControlFlowGraph and NarrowPredicateExpression**

- Remove `ControlFlowGraph` (~2360 lines) from `src/tirx/analysis/` —
used only in
  non-default config paths that are no longer maintained
- Remove `NarrowPredicateExpression` from `src/arith/` — sole non-test
caller was `ControlFlowGraph`
- Remove gated config fields `propagate_knowns_to_prove_conditional` and
  `propagate_knowns_to_simplify_expressions` from `SimplifyConfig`
- Remove `use_dataflow_analysis` from `RemoveNoOpConfig`
- Delete the associated test files and test cases that tested the
now-removed paths
- ~3800 lines deleted

**Commit 2: Rename Simplify → StmtSimplify**

- Rename `src/tirx/transform/simplify.{h,cc}` → `stmt_simplify.{h,cc}`
- Rename C++ identifiers: `Simplify` → `StmtSimplify`, `SimplifyConfig`
→ `StmtSimplifyConfig`
- Rename FFI keys: `"tirx.Simplify"` → `"tirx.StmtSimplify"`,
`"tirx.transform.Simplify"` → `"tirx.transform.StmtSimplify"`
- Update Python wrappers and all call sites (~40 files)
- Clarifies that this pass operates on statements (distinct from
expression-level `arith::Analyzer::Simplify()`)

## Test plan

- [x] `tests/python/tirx-transform/test_tir_transform_simplify.py` — 52
tests pass
- [x] `tests/python/tirx-transform/test_tir_transform_remove_no_op.py` —
18 pass, 5 xfail
- [x] `tests/python/arith/` — full arith test suite passes
- [x] `tests/python/tirx-transform/` — full suite: 315 passed, 8
xfailed, 1 xpassed (pre-existing vectorize failure unrelated to this
change)
- [x] `pre-commit run --all-files` — all hooks pass
…ssConfig (apache#19614)

## Summary

Now that the ffi container machinery (Array, Optional, Map, Variant)
accepts bare int64_t and bool, the Integer/Bool ObjectRef wrappers add
no value in attribute fields, pass-config options, function-attr flags,
and OpAttrMap registries — every reader paid an extra .IntValue() /
->value unbox per access for no information gain. This PR is the first
stage of phasing out class Integer and class Bool: migrate the bulk of
those sites at the field-declaration and call-site level. A follow-up
will rewrite the remaining IR-position `Integer(N)` / `Bool(b)`
constructors to `IntImm(...)` / `const_true()` / `const_false()` and
delete the two classes entirely.

- Relax Attrs fields and their container forms (`Array<Integer>` /
`Optional<Array<Integer>>` / `Optional<Integer>` / `Optional<Bool>`)
migrated to bare `int64_t` / `bool` (manipulate.h, nn.h, op.h,
statistical.h, script/builder/frame.h, target/virtual_device.h,
distributed/global_info.h, relax/expr.h).
- OpAttrMap registry (`set_attr<Bool>("FPurity", Bool(true))` ↔
`GetAttrMap<Bool>("FPurity")`) migrated to `bool` across ~38 files.
- PassContext config registrations + `GetConfig<Bool>` /
`GetConfig<Integer>` readers, and function-attr `GetAttr<Bool>` /
`GetAttr<Integer>` readers (~42 files), all migrated; `HasNonzeroAttr`
in `ir/attrs.h` dropped its `.IntValue()` unbox.
- Schedule decision arrays (SampleCategorical candidates, perfect-tile
factors, autobind thread_extents, multi-level-tiling levels) migrated to
`Array<int64_t>` / `Optional<int64_t>` — this is a virtual-signature
change on `ConcreteScheduleNode::SampleCategorical` and related methods,
acceptable per the phase-out intent.
- `Variant<Bool, Array<String>>` for
`LiftTransformParams.shared_transform` migrated to `Variant<bool,
Array<String>>`.
…che#19617)

In continuation of apache#19594 **(DSO
modularization)**, fixes for```tvm_rpc``` backend pickups

---

### Issue

* Errors during remote ```tvm_rpc``` metaschedule sessions:
  ```
AttributeError: Unable to find function
"tvm.contrib.random.random_fill_for_measure"
on the remote RPC server. Please make sure 'USE_RANDOM' is turned ON in
the config.cmake
  on the RPC server.
  ```
This error is due to missing ```libtvm_runtime_extra.so``` (home of
contrib modules, e.g *random*) from ```tvm_rpc```.

----

### Fixes

* Before:
```
# readelf -a /usr/bin/tvm_rpc | grep NEED
  [ 7] .gnu.version_r    VERNEED          0000000000403a88  00003a88
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_runtime.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_ffi.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
```

* After:
```
# readelf -a /usr/bin/tvm_rpc | grep NEED
  [ 7] .gnu.version_r    VERNEED          0000000000404ed0  00004ed0
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_runtime_extra.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_runtime_cuda.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_runtime_opencl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_runtime.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtvm_ffi.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
```

Thank you !
… / phase out AttrFieldInfo (apache#19615)

## Summary

Follow-up to apache#19607 that continues trimming `attrs.h` and adjacent
files. The six commits land independently and each builds clean.

- Phase out `OpNode::arguments` and `AttrFieldInfo` — the field stored
  metadata that no Python tooling, test, or C++ caller (beyond internal
  sanity checks) read; removing it deletes `AttrFieldInfo` plus ~335
chained `.add_argument(...)` calls. The remaining 12 internal consumers
  now read `op->num_inputs` and report indexed inputs (`input[i]`).
- Drop the (unused) virtual destructor on `BaseAttrsNode` (ffi::Object
  uses a captured-typed deleter, no virtual dispatch needed) and inline
  the trivial 3-line `DictAttrs(Map)` constructor into the header.
- Rename `BaseAttrsNode` → `AttrsNode`; the `Base` prefix existed only
  to distinguish from the `AttrsNodeReflAdapter` shim that apache#19607
  removed. The `"ir.Attrs"` FFI registry key is unchanged.
- Promote `DictAttrs` to NOTNULLABLE
  (`TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE` + COW macro). The
  no-arg `DictAttrs()` constructor already created an empty backing,
  so every existing call site already produced a defined object;
  ~15 defensive `attrs.defined()` checks (and a defensive Python `None`
  fallback in `Function`) are now redundant.
- Inline the `WithAttr(DictAttrs, ...)` / `WithAttrs(DictAttrs, ...)`
  free-function overloads into the TFunc-template wrappers — those
  overloads had no external callers (no TVM_DLL, no Python binding).
- Rename `AttrsWithDefaultValues<T>` → `PassConfigWithDefaults<T>` and
  move from `attrs.h` to `transform.h`; all 9 consumers are pass-config
  classes registered via `TVM_REGISTER_PASS_CONFIG_OPTION`.

`attrs.h` shrinks from 363 → 262 lines.
…KernelLaunch together (apache#19605)

## Summary

These three passes are logically a single host/device split step;
having intermediaries between them obscures the model and blocks
folding them into one pass. This PR moves each intermediary to the
position its actual ordering constraint allows, so that
`AnnotateDeviceRegions`, `SplitHostDevice`, and
`LowerDeviceKernelLaunch` run consecutively in every pipeline.

## Rationale

- `MergeSharedMemoryAllocations` moves **before**
`AnnotateDeviceRegions`
  (the only legal position: `LowerDeviceKernelLaunch` requires at most
  one dyn-shmem allocation per kernel, so Merge cannot move past Lower).
- `MakePackedAPI` moves **after** `LowerDeviceKernelLaunch` (Lower's
  `kCallingConv = kDeviceKernelLaunch` flag causes `MakePackedAPI` to
  correctly skip device kernels; the host body's lowered
  `tvm_call_packed` is transparent to `MakePackedAPI`'s subroutine
  rewriter).
- `FP8StorageLegalize` / `BF16StorageLegalize` move **after**
  `MakePackedAPI` (their `buffer_map.size()==0` ICHECK requires
  `MakePackedAPI` to have cleared the map).

Prereq for Phase 2: collapsing the three consecutive passes into a
single `tirx.transform.SplitHostDevice` with three commented regions.

## Test plan

- [x] tests/python/tirx-transform/ target-pass unit tests (25 pass)
- [x]
tests/python/s_tir/transform/test_merge_dynamic_shared_memory_allocations.py
(5 pass)
- [x] tests/python/tirx-transform/test_tir_transform_fp8_legalize.py /
      test_tir_transform_bf16_legalize.py (13 pass)
- [x] tests/python/codegen/test_target_codegen_c_host.py /
      test_target_codegen_device.py (6 pass including
      test_subroutine_call — verifies Risk apache#2)
- [x] pre-commit run --all-files clean
- [ ] CI: lint / Windows / MacOS
…rs (apache#19616)

## Summary

This PR adds Relax TFLite frontend support for the TFLite builtin
control-flow / multi-subgraph operator family from apache#19519 item F:
`CALL`, `IF`, `WHILE`, and `CALL_ONCE`.

It builds on the multi-subgraph import infrastructure merged in PR
apache#19587.
The frontend already accepts TFLite models with extra subgraphs while
converting
only `Subgraphs(0)` into the Relax `main` function. This PR uses those
extra
subgraphs as callable or control-flow regions for the TFLite
control-flow
operators.

The supported subset is intentionally pure tensor and guard-first:

- `CALL` lowers a referenced TFLite subgraph to a private Relax function
and
  emits a direct call.
- `IF` lowers the then/else subgraphs to private Relax functions and
emits a
  private wrapper function containing Relax `If`.
- `WHILE` lowers the cond/body subgraphs to private Relax functions and
emits a
  recursive private Relax function for the loop.
- `CALL_ONCE` supports the empty-init no-op subset and explicitly
rejects
  non-empty or resource-like init patterns.

This PR does not model resource variable side effects. Those cases
remain
explicitly guarded instead of being imported with incorrect pure
functional
semantics.

## Design

### Shared Subgraph Lowering

The frontend now keeps shared conversion state across the main graph and
referenced subgraphs:

- `lowered_subgraphs`
- `lowered_if_functions`
- `lowered_while_functions`
- `lowering_stack`
- `module_builder`

Referenced pure tensor subgraphs are lowered through a recursive
`OperatorConverter` using an isolated `ExprTable`, so subgraph tensor
bindings
cannot overwrite bindings from the main graph. Lowered subgraphs are
cached by
subgraph index and reused when the same region is referenced more than
once.
Generated private functions are registered through the shared parent
`module_builder`, so nested cases such as `main CALL -> subgraph A ->
CALL
subgraph B` keep all private functions in the final IRModule.

Recursive ordinary `CALL` subgraphs are guarded with `OpNotImplemented`.
`WHILE` uses a dedicated recursive wrapper function instead, because
recursion
is part of the intended Relax representation for the loop itself.

### Boundary Validation

The control-flow converters validate subgraph boundaries before
lowering:

- referenced subgraph indices must be valid
- op input/output arity must match the referenced subgraph interface
- branch and loop tensor shape/dtype metadata must match the surrounding
op
- `IF` and `WHILE` conditions must be scalar bool tensors
- `WHILE` loop-carried input/output tensors must have matching metadata

The shared `_check_subgraph_interface` helper is used by `CALL`, `IF`,
and
`WHILE` to keep arity and metadata checks consistent across the
control-flow
operators. `_require_scalar_bool_tensor` accepts both frontend
`TensorWrapper`
objects and raw TFLite tensors so caller and referenced-subgraph
condition
checks use the same path.

These checks keep the first implementation conservative and make
unsupported
cases fail with targeted `OpNotImplemented` diagnostics.

### Tuple Outputs

TFLite `CALL`, `IF`, and `WHILE` may produce multiple output tensors.
The
frontend maps those cases to Relax tuple returns:

```text
single output  -> tensor expression
multi output   -> Tuple(...)
op outputs     -> TupleGetItem(...)
```

This keeps the single-output IR simple while covering multi-output
calls,
multi-output branches, and multi-variable loop state.

## Operator Support

| Operator | TFLite options | Relax lowering | Supported subset |
|---|---|---|---|
| `CALL` | `CallOptions.Subgraph()` | private Relax function call | pure
tensor subgraphs, single or multiple outputs |
| `IF` | `IfOptions.ThenSubgraphIndex()`, `ElseSubgraphIndex()` |
private wrapper function containing Relax `If` | scalar bool condition,
matching branch I/O metadata |
| `WHILE` | `WhileOptions.CondSubgraphIndex()`, `BodySubgraphIndex()` |
recursive private Relax function | scalar bool cond output, tensor
loop-carried state |
| `CALL_ONCE` | `CallOnceOptions.InitSubgraphIndex()` | no-op for empty
init subgraph | empty init subgraph only |

## Not Included

- Full `CALL_ONCE` resource/variable initialization semantics.
- Resource, variant, hashtable, or variable tensor support.
- TensorFlow-generated `tf.cond` / `tf.while_loop` smoke tests.
- Dynamic-shape loop-state refinements beyond the current static
metadata
  checks.

## Tests

The tests manually build minimal TFLite flatbuffers and compare the
imported
Relax IR with `tvm.ir.assert_structural_equal`. Unsupported-boundary
tests use
`pytest.raises`.

| Test | Coverage |
|---|---|
| `test_call_subgraph` | basic `CALL` to a pure tensor subgraph |
| `test_call_subgraph_multi_output` | `CALL` tuple return and output
binding |
| `test_call_subgraph_nested_call` | nested `CALL` private function
registration |
| `test_call_subgraph_invalid_index_unsupported` | invalid `CALL`
subgraph index |
| `test_call_subgraph_io_mismatch_unsupported` | `CALL` arity mismatch |
| `test_call_subgraph_output_metadata_mismatch_unsupported` | `CALL`
output metadata guard |
| `test_if_subgraphs` | basic `IF` branch selection |
| `test_if_subgraphs_multi_output` | `IF` tuple branch returns |
| `test_if_subgraphs_non_bool_condition_unsupported` | `IF` condition
dtype guard |
| `test_if_subgraphs_invalid_index_unsupported` | invalid then/else
subgraph index |
| `test_if_subgraphs_output_count_mismatch_unsupported` | branch output
count guard |
| `test_if_subgraphs_input_metadata_mismatch_unsupported` | branch input
metadata guard |
| `test_if_subgraphs_output_metadata_mismatch_unsupported` | branch
output metadata guard |
| `test_while_subgraphs` | basic recursive `WHILE` lowering |
| `test_while_subgraphs_repeated_cond_body_pair` | shared cond/body loop
function cache |
| `test_while_subgraphs_two_loop_vars` | multi-variable loop state tuple
path |
| `test_while_subgraphs_non_bool_condition_unsupported` | `WHILE` cond
output dtype guard |
| `test_while_subgraphs_invalid_index_unsupported` | invalid cond/body
subgraph index |
| `test_while_subgraphs_zero_loop_vars_unsupported` | zero-loop-var
guard |
| `test_while_subgraphs_loop_state_metadata_mismatch_unsupported` | loop
state metadata guard |
| `test_while_subgraphs_output_count_mismatch_unsupported` | body output
count guard |
| `test_while_subgraphs_input_metadata_mismatch_unsupported` | cond/body
input metadata guard |
| `test_while_subgraphs_output_metadata_mismatch_unsupported` |
cond/body output metadata guard |
| `test_call_once_empty_init_subgraph` | empty `CALL_ONCE` no-op subset
|
| `test_call_once_non_empty_init_subgraph_unsupported` | non-empty init
subgraph guard |
| `test_call_once_inputs_outputs_unsupported` | `CALL_ONCE` op I/O guard
|
| `test_call_once_init_subgraph_io_unsupported` | init subgraph I/O
guard |
| `test_call_once_invalid_index_unsupported` | invalid init subgraph
index |

Local validation:

```bash
python -m ruff format --check \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m ruff check \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m pytest \
  tests/python/relax/test_frontend_tflite.py \
  -k "call_subgraph or if_subgraphs or while_subgraphs or call_once" -q

python -m pytest \
  tests/python/relax/test_frontend_tflite.py -q
```

Result:

```text
ruff format --check: 2 files already formatted
ruff check: All checks passed
28 passed, 434 deselected
462 passed
```

## References

- Issue apache#19519 item F: TFLite control-flow / multi-subgraph operators
- PR apache#19587: StableHLO region-based ops and multi-subgraph model support
…pache#19601)

## Summary

This PR adds Relax TFLite frontend support for
`UNIDIRECTIONAL_SEQUENCE_RNN` (BuiltinOperator 35), claimed in
[apache#19519](apache#19519) Group A.

The op executes a simple RNN cell over a time sequence. The converter
unrolls the time steps at graph-construction time using Relax
primitives.

Cell equation:
```
h_t = fused_activation(x_t @ W.T + h_{t-1} @ Wr.T + b)
```

## Changes

- **Handler**: `convert_unidirectional_sequence_rnn` registered in
`convert_map` (alphabetical, U-region after `UNPACK`)
- **Inputs** (5): `input [batch, time, input_size]`, `input_weights
[num_units, input_size]`, `recurrent_weights [num_units, num_units]`,
`bias [num_units]`, `hidden_state [batch, num_units]` (variable,
zero-initialised)
- **Output**: `[batch, time, num_units]` (always batch-major)
- **time_major=True**: input is transposed to batch-major before
unrolling
- **Activations**: NONE, RELU, RELU6, TANH, SIGMOID (via
`convert_fused_activation_function`)
- **Quantized**: raises `OpNotImplemented` (not yet supported)

## Testing

Modern TF/Keras (2.x, Keras 3) no longer emits
`UNIDIRECTIONAL_SEQUENCE_RNN`; `SimpleRNN` with `unroll=False` lowers to
`WHILE`+TensorList ops, and `unroll=True` expands to elementwise ops.
Tests therefore follow the same flatbuffer-construction pattern used by
the StableHLO op PRs (apache#19536, apache#19587).

Three tests added to `tests/python/relax/test_frontend_tflite.py`:

- `test_unidirectional_sequence_rnn_none_activation` —
`tvm.ir.assert_structural_equal` with identity weights / zero bias, NONE
activation, time=1
- `test_unidirectional_sequence_rnn_relu_activation` — shape check,
random weights, RELU activation, time=3
- `test_unidirectional_sequence_rnn_time_major` — shape check,
`time_major=True` input layout

```bash
python -m pytest tests/python/relax/test_frontend_tflite.py -k unidirectional_sequence_rnn -v
```

All 3 tests pass. pre-commit (ASF header, ruff check, ruff format) all
pass.

## References

- Issue [apache#19519](apache#19519) Group A:
Sequence / recurrent model operators

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This PR renames `tirx::CallNode::annotations` to `attrs`, matching the
existing Relax `CallNode::attrs` convention.
Previously, TIRX Call metadata was stored in a `Map<String, Any>` field
named `annotations`. This PR makes it a first-class `Attrs` field
instead, so call-level metadata follows the same representation and
naming style as Relax calls.
## Summary

`tvm::runtime::regex_match` was a thin C++ wrapper that bounced through
a
global `ffi::Function` back into Python's `re.match`. It was introduced
solely to avoid pulling `<regex>` into TVM (libstdc++ dual-ABI conflict
with
pre-cxx11 pytorch wheels). The only C++ caller is the DNNL JSON runtime,
where
every pattern reduces to substring containment — `re.match` anchors at
the
start only, so `.*X.*` is equivalent to `s.find(X) != npos`.

- Remove `src/runtime/regex.{h,cc}` and the Python
`tvm.runtime.regex_match`
  global registration.
- Add file-local `contains` / `contains_any` helpers in
`dnnl_json_runtime.cc`
  and inline `std::string::find` at the 15 call sites.
- Drop the dead `regex.h` include from
`src/relax/transform/update_param_struct_info.cc`.

No CMakeLists.txt change needed — `src/runtime/*.cc` is picked up by
glob.

`USE_DNNL` is OFF in the ci_gpu container, so DNNL-specific runtime
tests
are not exercised locally. The DNNL translation unit compiles cleanly
with
the inlined helpers, and the full TVM build (636 targets) passes.
## Summary

The [Refactor] Phase out microTVM commit (apache#17554) removed the bulk of
microTVM, but a few crumbs were left behind. This PR removes all of
them:

- `src/runtime/meta_data.h`: old snake_case header with a dmlc-based
  `FunctionInfo` struct. Replaced long ago by `src/runtime/metadata.h`
  (camelCase, `ffi::ObjectRef`-based). No file in the tree includes
  `meta_data.h`.

- `src/runtime/crt/common/crt_runtime_api.c`: the sole remaining file
  in the `src/runtime/crt/` subtree. Includes `<tvm/runtime/crt/*>`
  headers that no longer exist; not picked up by any `RUNTIME_SRCS`
  glob; uncompilable in the current tree.

- `cmake/utils/CRTConfig.cmake`: defines `generate_crt_config()`, which
  has no callers and references a missing `crt_config.h.template`.

- `docs/conf.py`: sphinx-gallery exclusion for a tutorial file
  (`micro_mlperftiny.py`) that no longer exists; simplified the regex.

No code changes elsewhere — these are all isolated leaves with zero
callers or includers across `*.cc *.h *.c *.py *.cmake CMakeLists.txt`.
…eader-only (apache#19621)

## Summary

The NVTXScopedRange utility is a thin RAII wrapper over
nvtxRangePush/Pop
with a no-op fallback when NVTX is not enabled. The two function bodies
and the conditional include of `<nvtx3/nvToolsExt.h>` fit naturally
inline
in the header, eliminating the separate translation unit and its
`TVM_RUNTIME_DLL` export annotations.

- Move `include/tvm/runtime/nvtx.h` to `include/tvm/support/cuda/nvtx.h`
  under namespace `tvm::support`; delete `src/runtime/nvtx.cc`.
- Inline the constructor/destructor; gate the real-vs-stub split with
  `TVM_NVTX_ENABLED` in the header.
- Switch the CMake gate from a per-file `COMPILE_DEFINITIONS` on
  `nvtx.cc` to a global `add_compile_definitions(TVM_NVTX_ENABLED=1)`
  when `USE_CUDA AND USE_NVTX`, so every TU that includes the header
  agrees on the definition.
- Update the three call-site files (`vm.cc`, `paged_kv_cache.cc`,
  `attn_utils.h`) to the new include path and qualify `NVTXScopedRange`
  as `support::NVTXScopedRange`.
… to tvm.support (apache#19624)

## Summary

Lifts 10 host-toolchain / CLI / process / utility modules from
`python/tvm/contrib/` to a new `python/tvm/support/` package, and
deletes two dead contrib shims.

`tvm.support` is the home for Python helpers that integrate TVM with
external CLIs and host-side tools — compilers, archivers, subprocess
pools, and build-info queries. These are load-bearing internal pieces
that TVM's compile/link/run paths depend on. `tvm.contrib` is reserved
for optional vendor SDK integrations and experimental features. The
distinction is documented in the `tvm.support` package docstring.

Moved (one commit each):

- `tvm.contrib.cc` → `tvm.support.cc`
- `tvm.contrib.nvcc` → `tvm.support.nvcc`
- `tvm.contrib.rocm` → `tvm.support.rocm`
- `tvm.contrib.ndk` → `tvm.support.ndk`
- `tvm.contrib.xcode` → `tvm.support.xcode`
- `tvm.contrib.clang` → `tvm.support.clang`
- `tvm.contrib.emcc` → `tvm.support.emcc`
- `tvm.contrib.popen_pool` → `tvm.support.popen_pool`
- `tvm.contrib.utils` → `tvm.support.utils`
- `tvm.contrib.tar` → `tvm.support.tar`

Deleted:
- `tvm.contrib.spirv` — single `optimize()` wrapping `spirv-opt`; zero
importers.
- `tvm.contrib.rpc` — self-deprecation shim with "removed in 0.5"
banner; honoring it.

Package conversion:
- `python/tvm/support.py` → `python/tvm/support/__init__.py` with
inclusion-rule docstring.
- `libinfo()` extracted into `python/tvm/support/libinfo.py`.
- `FrontendTestModule` dropped (audit confirmed zero callers outside its
own definition).

## Compatibility

Hard break — no `tvm.contrib.<mod>` re-export shims. All callers updated
in this PR.

C++-side FFI registry keys (`tvm.contrib.nvcc.*`, etc.) are unchanged —
only the Python module path moves. Renaming the FFI keys is a separate
follow-up.
…ut tvm/ir/repr.h (apache#19627)

## Summary

Two-commit PR:

1. Bump `3rdparty/tvm-ffi` from `3c35034` to `98d0029` and migrate all
21 in-tree `SEqHashDef()` call sites to `SEqHashDefRecursive()` (the
conservative variant matching the prior default behavior). Six let-style
sites carry `TODO(tqchen)` comments indicating they should flip to
`SEqHashDefNonRecursive` after the new tvm-ffi ships on pypi.

2. Phase out `include/tvm/ir/repr.h`. The bumped tvm-ffi now provides
ostream `operator<<` for `Any`/`ObjectRef`/`Variant`/`Optional` directly
in `tvm/ffi/extra/dataclass.h`, making the in-tree thin wrapper
redundant. Rewrite 8 includers, rename `src/ir/repr.cc` →
`src/ir/access_path_repr.cc` (preserves `node.AsRepr` +
AccessPath/AccessStep `__ffi_repr__` registrations; drops zero-caller
`tvm::Dump()`), delete the header. Also fixes a Python-level import
regression in `python/tvm/ir/attrs.py` caused by the bump: tvm_ffi
0.1.12.dev changes the field-registration guard from `not hasattr(cls,
name)` to `name not in cls.__dict__`, which breaks `DictAttrs` because
`DictAttrsNode` registers a reflection field named `"__dict__"` — Python
forbids installing a class descriptor with that name via `setattr`. Fix:
define `__dict__` as an explicit Python property on `DictAttrs` so the
auto-installation is skipped.

## TODO follow-ups

After the new tvm-ffi releases on pypi, flip the 6
`SEqHashDefRecursive()` sites that carry `TODO(tqchen)` comments to
`SEqHashDefNonRecursive()`. Locations are enumerated in the commit body
of commit 1.

## Test plan

- [x] Full ninja build clean (638/638).
- [x] 118/118 cpptest pass.
- [x] `import tvm; tvm.cuda(0).exist` returns True.
- [x] `tests/python/all-platform-minimal-test`: 37 passed, 105 skipped.
- [x] `tests/python/relax/test_struct_info.py`: 9 passed.
- [x] `git grep -nE 'SEqHashDef\(|"tvm/ir/repr\.h"'` is empty.
- [x] `pre-commit run --all-files` clean.
…he#19625)

## Summary

`ReplaceGlobalVars` was a public IR-layer API with only one in-tree C++
caller (`relax::AttachGlobalSymbol`). The mechanism used a NodeFunctor
vtable populated at static-init time by per-dialect `.cc` files in
relax and tirx, which made the IR layer logically depend on its
dialects even though the include graph did not show it.

Move the dispatch logic into the consumer as file-local mutators and
a private helper. Delete the public header, the IR-layer driver, both
per-dialect dispatch registrations, the `IRModule.replace_global_vars`
python method, and its dedicated test file. The behavior is still
covered by `tests/python/relax/test_transform_attach_global_symbol.py`
and by the pipelines that include the `AttachGlobalSymbol` pass.
…pache#19619)

Fixes apache#18915 

Vulkan codegen previously generated sequentially constistant
OpControlBarrier SPIR-V instructions, which is invalid for Vulkan, where
we would expect AcquireRelease.
…ead_map, texture, minrpc, disco, contrib (apache#19628)

## Background

The TVM runtime has been growing organically. Several headers and
directories
live at the top level of `src/runtime/` despite only being consumed by a
single backend subsystem. This PR applies the **locality principle**:
code that
has exactly one consumer moves to live next to that consumer.

## Changes

### Move 1: `thread_map.h` → `src/runtime/vulkan/`
`ThreadMap` is only used by Vulkan device API headers. Moving it under
`src/runtime/vulkan/` reflects this exclusive ownership.

### Move 2: `texture.h` → `src/runtime/opencl/`
Texture storage utilities are OpenCL/Adreno-specific. Moving the header
under `src/runtime/opencl/` makes ownership clear.

### Move 3: `minrpc/` → `src/runtime/rpc/minrpc/`
The minrpc mini-RPC implementation belongs logically under the existing
`src/runtime/rpc/` subtree. All consumers already live under rpc/ or
reference it as a child of rpc/.

### Move 4: Introduce `src/runtime/extra/` boundary
`disco/` and `contrib/` are the sole source directories for
`libtvm_runtime_extra`. Grouping them under `src/runtime/extra/` makes
the
`libtvm_runtime_extra` build boundary visible in the filesystem,
matching
the modular runtime split introduced in apache#19444.
- `src/runtime/disco/` → `src/runtime/extra/disco/`
- `src/runtime/contrib/` → `src/runtime/extra/contrib/`
- Public `include/tvm/runtime/disco/` is unchanged.

### Drive-by fixes
- `apps/android_rpc/…/tvm_runtime.h`: Drop stale `minrpc_logger.cc`
include
(file no longer exists) and fix stale `tvm-ffi/src/ffi/extra/testing.cc`
  path to `tvm-ffi/src/ffi/testing/testing.cc`.

## Test Plan

- [x] Full build (`ninja -j$(nproc)`) — succeeds
- [x] `./cpptest` — 118 tests passed
- [x] Python smoke: `tvm.__version__` + `tvm.cuda(0).exist` — pass
- [x] `tests/python/all-platform-minimal-test` — 37 passed, 105 skipped
- [x] `tests/python/runtime/test_runtime_rpc.py` — 2 passed, 21 skipped
- [x] `tests/python/runtime/test_rpc_base.py` — 2 passed
- [x] `pre-commit run --all-files` — all hooks pass
…he#19630)

## Summary

`derived_object` was duplicated byte-for-byte across
`python/tvm/runtime/support.py` and
`python/tvm/s_tir/meta_schedule/utils.py`. The function is not a runtime
feature and is used outside meta_schedule (tvm.relax, tvm.tirx), so
neither location was the right home.

Move the single canonical definition into a new
`python/tvm/ir/utils.py`. `tvm.ir` loads before both `tvm.tirx` and
`tvm.s_tir`, so eager top-level imports work from every consumer without
load-order workarounds.

Rewrite all 25 caller imports. Keep the better-typed `cls: type[T] ->
type[T]` signature from the runtime-side copy. After this change
`runtime/support.py` is empty and is removed;
`meta_schedule/__init__.py` drops its now-dead re-export. No alias shims
are left behind — callers update imports directly.
…way dep, migrate dialect config to extra_config (apache#19631)

## Background

The `tvm::ir` layer previously had a reverse dependency on
`tvm::script`, injected via the `TVM_OBJECT_ENABLE_SCRIPT_PRINTER()`
macro that added a `Script()` member method to IR node types (IRModule,
PrimExpr, Buffer, PrimFunc, Stmt). This violated the intended one-way
dependency: `script` should depend on `ir`, never the other way around.

Additionally, `PrinterConfigNode` accumulated dialect-specific fields
(`tir_prefix`, `tir_import_module`, `tirx_prefix`, `relax_prefix`) that
created leakage between the generic printer infrastructure and dialect
internals.

## Changes

This PR restores the clean dependency direction and encapsulates dialect
config properly, in 5 commits:

1. **Lift TVMScript entry point into `script/printer/printer.h`**: New
header `include/tvm/script/printer/printer.h` introduces:
- `tvm::Script()` free function replacing `TVMScriptPrinter::Script()`
static method
- `TVMScriptPrinter` class with vtable (`NodeFunctor<std::string(...)>`)
- `TVM_REGISTER_SCRIPT_AS_REPR` macro for registering per-type repr
callbacks

2. **Drop `TVM_OBJECT_ENABLE_SCRIPT_PRINTER` macro**: Remove the macro
from all IR headers (`ir/expr.h`, `ir/module.h`, `tirx/buffer.h`,
`tirx/function.h`, `tirx/stmt.h`), eliminating the reverse `ir` →
`script` dependency. All call sites of `.Script()` member methods
updated to use `tvm::Script()`.

3. **Move dialect-specific `PrinterConfig` fields to `extra_config`**:
Remove `tir_prefix`, `tir_import_module`, `tirx_prefix`, `relax_prefix`
from `PrinterConfigNode`. Dialect internals now read their config via
`GetExtraConfig<T>(key, fallback)` with dotted keys (e.g.,
`"tirx.prefix"`). `buffer_dtype` is kept as a top-level field alongside
`int_dtype`/`float_dtype` since it is a shared scalar-literal default,
not a dialect-specific knob.

4. **Python: drop dialect kwargs, expose `extra_config`**: Update
`PrinterConfig`, `Scriptable.script()`, `Scriptable.show()`,
`Scriptable._relax_script()`, and `BasePyModule.script()` to use
`extra_config: dict | None = None` instead of individual dialect kwargs.
The tirx auto-switch logic is preserved.

5. **Fix transitive include breakage**: Explicitly add direct includes
for `config.h` and `node_functor.h` where headers previously relied on
transitive paths through `expr.h`/`module.h`.

## Testing

- C++ unit tests: 118/118 pass
- TVMScript printer tests: 771 passed, 1 skipped, 1 xfailed
- TIR namespace tests
(`tests/python/tirx/test_printer_tir_namespaces.py`): 13/13 pass
- Relax AST printer tests: 24/24 pass
- Minimal platform tests: 37/37 pass
- Pre-commit (ASF headers, ruff, clang-format): all clean
…r proves over scalable vectors (apache#19638)

## Summary

Phase out `src/arith/scalable_expression.{h,cc}`. The arith layer no
longer attempts to prove anything about scalable vectors — proofs that
depended on `Target::Current()` are removed. Scalable vectors remain a
first-class concept; arith just doesn't reason about their lengths.

## Use-site summary

Only 16 call sites total across 7 symbols (9 live, 7 proof-related).

| Symbol | Live callers (kept) | Proof callers (deleted) | New home |
|---|---|---|---|
| `ExtractVscaleFactor` | 4 × `arith/rewrite_simplify.cc` + 2 ×
`tirx/ir/expr.cc` | — | file-local in each |
| `IsVScaleCall` | 1 × `tirx/op/op.cc` + 1 ×
`tirx/transform/vectorize_loop.cc` | — | inline at use sites |
| `ContainsVscaleCall` | 4 × `arith/rewrite_simplify.cc` + 1 ×
`s_tir/schedule/ir_comparator.cc` | — | inline at use sites |
| `TargetHasVLA` | 2 × `tirx/transform/vectorize_loop.cc` | analyzer.cc
+ const_int_bound.cc | local in vectorize_loop.cc |
| `GetVScaleValues` | 1 × `target/llvm/codegen_aarch64.cc` | analyzer.cc
+ const_int_bound.cc | inlined at codegen_aarch64 |
| `CanProveVscaleExpressionFromKnownValues` | — | analyzer.cc | DELETE |
| `SubstituteVScaleWithKnownValue` | — | internal only | DELETE |

## Changes (6 commits)

1. Move `ExtractVscaleFactor` to file-local anonymous-namespace helpers
in `rewrite_simplify.cc` and `tirx/ir/expr.cc`. Function is small;
per-file duplication is cleaner than a shared header.
2. Inline `IsVScaleCall` / `ContainsVscaleCall` / `TargetHasVLA` at call
sites (1-3 line predicates, anonymous-namespace per consumer `.cc`).
3. Drop the scalable-vector proof scaffolding from `arith/analyzer.cc`
(substitution-proof loop) and `arith/const_int_bound.cc` (vscale
branch). `vscale()` calls fall back to `Everything()` — no special bound
narrowing.
4. Delete `scalable_expression.{h,cc}`. Inline the `GetVScaleValues`
body at `codegen_aarch64.cc` (computes `max_val = vector_width / 8`
floor-rounded to a power of two for the LLVM `vscale_range` attribute).
5. Mark `pytest.mark.xfail` on 19 tests that relied on the deleted
substitution-proof loop.
6. `pre-commit` line-length cleanup.

## Compatibility / intentional regression

This is a hard break for any consumer of the deleted symbols. They were
already in a private header (`src/arith/scalable_expression.h`, not
under `include/`).

19 tests that proved vscale-bearing inequalities on SVE / RVV are
xfailed. The proofs were target-dependent and the new policy is that
arith does not attempt them.
## Summary
Add Relax TFLite frontend support for the builtin `REDUCE_WINDOW`
operator.
This covers the ordinary TFLite op only, not `STABLEHLO_REDUCE_WINDOW`.

The converter parses `ReduceWindowOptions` from `BuiltinOptions2`,
validates
the static window attributes, and lowers supported reduce functions
through
`topi.sliding_window` plus Relax reductions.

Supported modes:
- `ADD`
- `MUL`
- `MINIMUM`
- `MAXIMUM`
- `ALL`
- `ANY`

Empty output shapes are handled directly with `relax.op.zeros`.
Quantized
`REDUCE_WINDOW`, dynamic window attributes, and unsupported reduce
functions
remain rejected with explicit errors.

## Testing
- `python -m py_compile
python/tvm/relax/frontend/tflite/tflite_frontend.py
tests/python/relax/test_frontend_tflite.py`
- `python -m pytest tests/python/relax/test_frontend_tflite.py -k
reduce_window -q -p no:tvm.testing.plugin`
- `python -m pytest tests/python/relax/test_frontend_tflite.py -k
"reduce_window or reduction_ops" -q -p no:tvm.testing.plugin`
- `conda run -n test python -m ruff check
python/tvm/relax/frontend/tflite/tflite_frontend.py
tests/python/relax/test_frontend_tflite.py`

## Related
Related to apache#19519.
## Summary

Add Relax TFLite frontend support for `RNN` (BuiltinOperator 23),
claimed in [apache#19519](apache#19519) Group A.

Single-step RNN cell:
```
h = fused_activation(x @ W.T + h @ Wr.T + b)
```

## Changes

- **Handler**: `convert_rnn` registered in `convert_map` (alphabetical,
after `RANGE`)
- **Inputs** (5): `input [batch, input_size]`, `input_weights
[num_units, input_size]`, `recurrent_weights [num_units, num_units]`,
`bias [num_units]`, `hidden_state [batch, num_units]` (variable,
zero-initialised)
- **Output**: `[batch, num_units]`
- **Activations**: all fused activations via
`convert_fused_activation_function`
- **Quantized**: raises `OpNotImplemented`

## Testing

Two tests added to `tests/python/relax/test_frontend_tflite.py`:

- `test_rnn_none_activation` — `tvm.ir.assert_structural_equal` with
identity weights, NONE activation
- `test_rnn_relu_activation` — shape check, random weights, RELU
activation

```bash
python -m pytest tests/python/relax/test_frontend_tflite.py -k rnn -v
```

## References

- Issue [apache#19519](apache#19519) Group A:
Sequence / recurrent model operators
apache#19636)

## Background

`class Integer : public IntImm` and `class Bool : public IntImm` were
thin
wrappers sharing `IntImmNode` with no separate node class and no FFI
registration. They existed to provide implicit int→Integer constructors
and
a `.IntValue()` / `operator bool()` accessor, but the same functionality
is
available directly through `IntImm`.

## What this PR does

Migrates all call sites away from `Integer` / `Bool` and then deletes
the
class definitions.  The changes are split into four commits, each
independently buildable:

**Commit 1 – [REFACTOR][TIR]** Replace IR-position `Integer(N)` /
`Bool(b)`
constructors with `IntImm(DataType::Int(32), N)` /
`IntImm(DataType::Bool(), b)`
across ~62 source files (arith, relax analysis, s_tir schedule state,
transform
passes, codegen).

**Commit 2 – [REFACTOR][SCHEDULE]** Migrate `Schedule` and
`MetaSchedule`
trace-boxing code: `Integer(N)` attrs in `TracedSchedule` →
`IntImm(DataType::Int(32), N)`;
`ffi::Array<Integer>` schedule-rule parameters → `int64_t`; `Bool(b)`
attrs →
`IntImm(DataType::Bool(), b)`.

**Commit 3 – [REFACTOR][TOPI]** Migrate topi container signatures
(`ffi::Array<Integer>` → `ffi::Array<int64_t>`) and update all internal
usages (`.IntValue()` → plain int64_t, `.defined()` → removed,
`->value` → direct indexing).  Also handles stray `Integer` / `Bool`
variables in clml codegen, make_packed_api, infer_layout_utils, and
relax distributed code.

**Commit 4 – [REFACTOR][IR]** Delete `class Bool`, `class Integer`,
`TypeTraits<Bool>`, and `TypeTraits<Integer>` from
`include/tvm/ir/expr.h`.

## Canonical replacements

| Old | New |
|-----|-----|
| `Integer(N)` | `IntImm(DataType::Int(32), N)` |
| `Bool(b)` | `IntImm(DataType::Bool(), b)` |
| `x.IntValue()` | `x->value` |
| `x` as bool | `x->value != 0` |
| `ffi::Array<Integer>` | `ffi::Array<int64_t>` |

## Testing

- All 118 C++ unit tests pass (`./cpptest`)
- `tests/python/s_tir/` — 1251 passed (14 pre-existing failures
unrelated to this change, all in TIR transform tests with
annotation-mismatch errors)
- `tests/python/relax/` — passes (excluding pre-existing
torch/torchvision import failures in frontend tests)
## Summary

Add LSTM (coupled input-forget) and SVDF single-step converters to the
TFLite frontend. Both are float32-only; quantized variants are not
supported yet.

From apache#19519.

## Changes

- **LSTM**: FULL kernel type, coupled input-forget gate only. Peephole,
projection, and layer norm are not supported
- **SVDF**: Standard SVDF with feature projection + time filtering +
bias + fused activation
- Both converters validate unsupported modes (quantized, non-coupled
LSTM) with clear error messages

## Testing

- `test_lstm_none_activation` — verifies LSTM converter produces correct
IR shapes (batch, input_size) → (batch, num_units) with 3 params (input,
h_state, c_state)
- `test_svdf_none_activation` — verifies SVDF converter produces correct
IR shapes (batch, input_size) → (batch, num_filters) with 2 params
(input, state)

```bash
python -m pytest tests/python/relax/test_frontend_tflite.py -k "lstm or svdf" -v
```

## References

- TFLite LSTM spec:
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/kernels/lstm.cc
- TFLite SVDF spec:
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/kernels/svdf.cc
…htable Import Support (apache#19639)

## Summary

This PR adds incremental Relax TFLite frontend support for the resource
variable initialization subset:

- `VAR_HANDLE`
- `ASSIGN_VARIABLE`
- `READ_VARIABLE`

It builds on the TFLite control-flow / multi-subgraph support from
apache#19616,
especially `CALL_ONCE`. TFLite commonly represents initialization
through a
`CALL_ONCE` init subgraph, then uses resource handles from the main
subgraph to
read initialized variables. This PR supports that constrained
initialization
pattern without introducing general mutable runtime state into Relax.

The PR also adds explicit frontend guards for the TFLite builtin
hashtable
operators:

- `HASHTABLE`
- `HASHTABLE_IMPORT`
- `HASHTABLE_FIND`
- `HASHTABLE_SIZE`

These operators are intentionally left unsupported for now. TFLite
builtin
hashtable kernels are not generic tensor maps: their runtime
implementations
cover the `int64 -> string` and `string -> int64` table variants, and
correct
import requires proper `TensorType.STRING` support. Rejecting the
operators is
safer than lowering a synthetic numeric table semantics that TFLite does
not
actually implement.

## Design

### Shared Initialization State

The frontend now keeps resource initialization data in shared conversion
state:

- `conversion_state["resource_values"]`
- `conversion_state["in_call_once_init"]`

This state is shared by the main graph converter and the `CALL_ONCE`
init
subgraph converter. Each converter instance still keeps its own local
`self.resource_handles` map, keyed by TFLite tensor name.

Resource variables use `container + shared_name` from `VarHandleOptions`
when
present, falling back to the handle tensor name. This keeps tensor-name
bindings
scoped to each subgraph while allowing init subgraphs and the main graph
to
agree on the same logical resource.

### CALL_ONCE Init Subgraphs

`CALL_ONCE` now accepts a non-empty init subgraph when all operators are
in the
supported initialization subset:

- `VAR_HANDLE`
- `ASSIGN_VARIABLE`

The init subgraph still must have no inputs and no outputs. The
converter first
checks every operator against the allowlist, then converts the init
subgraph
with a fresh `ExprTable` and shared conversion state.

The init subconverter deliberately shares the parent `BlockBuilder`.
This is
safe for the current subset because all supported init operators update
importer
state and return `None`; they do not emit Relax bindings. A comment
documents
that this should be revisited if future `CALL_ONCE` init operators emit
Relax
expressions.

### Resource Variables

`VAR_HANDLE` is declarative. It registers the output resource tensor in
the
current converter's local `resource_handles` map and returns `None`.

`ASSIGN_VARIABLE` is accepted only while converting a supported
`CALL_ONCE` init
subgraph. It resolves the resource handle through the init converter's
local
handle map and stores the assigned tensor expression in shared
`conversion_state["resource_values"]`.

`READ_VARIABLE` resolves the main graph resource handle and returns the
initialized expression from shared state. If the resource has not been
initialized by a supported `CALL_ONCE` path, the frontend raises
`OpNotImplemented`.

This supports the common static-initialization inference pattern while
avoiding
incorrect lowering for runtime mutation.

### Hashtable Operators

`HASHTABLE` registers the table handle and validates the dtype pair
against
TFLite kernel constraints (`int64/string` or `string/int64`).

`HASHTABLE_IMPORT` in a supported `CALL_ONCE` init subgraph captures
static
metadata (table size, key/value dtypes) but does not store actual string
data,
because Relax does not yet support `TensorType.STRING`.

`HASHTABLE_SIZE` returns a scalar Relax constant for statically imported
tables.

`HASHTABLE_FIND` is rejected with `OpNotImplemented` because Relax
cannot
represent TFLite string tensors or the runtime lookup semantics.

## Operator Support

| Operator | TFLite options | Relax lowering | Supported subset |
|---|---|---|---|
| `VAR_HANDLE` | `VarHandleOptions` | handle registration only | main
graph and supported `CALL_ONCE` init subgraphs |
| `ASSIGN_VARIABLE` | `AssignVariableOptions` | store initialized Relax
expression in shared importer state | supported `CALL_ONCE` init
subgraphs only |
| `READ_VARIABLE` | `ReadVariableOptions` | return initialized Relax
expression | resource must have supported static initialization |
| `HASHTABLE` | `HashtableOptions` | handle registration + dtype
validation | validates `int64/string` or `string/int64` pair, rejects
other combinations |
| `HASHTABLE_IMPORT` | `HashtableImportOptions` | store static metadata
(size, key/value dtype) | `CALL_ONCE` init subgraphs only, constant
key/value shape validation |
| `HASHTABLE_FIND` | `HashtableFindOptions` | unsupported guard |
requires future `TensorType.STRING` support in Relax |
| `HASHTABLE_SIZE` | `HashtableSizeOptions` | scalar Relax constant |
returns `[size]` int64 for statically imported tables |

## Safety Checks

- `ASSIGN_VARIABLE` outside `CALL_ONCE` initialization raises
  `OpNotImplemented`.
- `READ_VARIABLE` without supported initialization raises
`OpNotImplemented`.
- `CALL_ONCE` init subgraphs with inputs or outputs remain unsupported.
- `CALL_ONCE` init subgraphs containing operators outside the
resource-variable
  initialization allowlist remain unsupported.
- TFLite builtin hashtable operators raise `OpNotImplemented` until the
  frontend can model their real int64/string table semantics.

## Not Included

- Runtime `ASSIGN_VARIABLE` mutation in the main graph.
- Runtime resource-state threading through Relax function parameters and
  returns.
- Cross-subgraph resource handle aliasing beyond the static
  `container/shared_name` matching pattern.
- Multiple runtime writes with ordering semantics.
- TFLite builtin hashtable lowering.
- `TensorType.STRING` import support.

## Tests

The tests manually build minimal TFLite flatbuffers and compare imported
Relax
IR with `tvm.ir.assert_structural_equal`. Unsupported patterns use
`pytest.raises`.

| Test | Coverage |
|---|---|
| `test_resource_variable_call_once_init_read` | `CALL_ONCE` init
subgraph with `VAR_HANDLE + ASSIGN_VARIABLE`, then main graph
`READ_VARIABLE` |
| `test_assign_variable_main_subgraph_unsupported` | runtime/main graph
`ASSIGN_VARIABLE` guard |
| `test_read_variable_uninitialized_unsupported` | `READ_VARIABLE`
without supported initialization guard |
| `test_hashtable_call_once_import_find_unsupported` | hashtable
init/find path remains unsupported |
| `test_hashtable_call_once_import_size_unsupported` | hashtable
init/size path remains unsupported |
| `test_hashtable_import_main_subgraph_unsupported` | main graph
`HASHTABLE_IMPORT` remains unsupported |
| `test_hashtable_size_uninitialized_unsupported` | uninitialized
`HASHTABLE_SIZE` remains unsupported |

Local validation:

```bash
python -m py_compile \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m ruff format --check \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m ruff check \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m pytest \
  tests/python/relax/test_frontend_tflite.py \
  -k "resource_variable or read_variable_uninitialized or hashtable" -q

python -m pytest \
  tests/python/relax/test_frontend_tflite.py -q
```

Result:

```text
py_compile: passed
ruff format --check: files already formatted
ruff check: All checks passed
targeted resource/hashtable tests: 6 passed
full test_frontend_tflite.py: 472 passed
```
test_transform_lower_tirx.py imports and calls Simplify, but the pass is
named StmtSimplify (the only simplify pass exported from
tvm.tirx.transform). The stale name makes the module fail to import at
collection time. Use StmtSimplify so the test collects and runs.
…ache#19634)

## Summary

Add three TFLite sequence recurrent operators to the Relax frontend, all
with
coupled input-forget gate (FULL kernel) and float32-only support.

- UNIDIRECTIONAL_SEQUENCE_LSTM
- BIDIRECTIONAL_SEQUENCE_RNN
- BIDIRECTIONAL_SEQUENCE_LSTM

From apache#19519.

## Changes

- **UNIDIRECTIONAL_SEQUENCE_LSTM**: same layout as single-step LSTM,
unrolls over
time and stacks per-step hidden states. Supports time_major, cell_clip,
proj_clip,
  and fused activation.
- **BIDIRECTIONAL_SEQUENCE_RNN**: separate fw/bw RNN cells, backward
scans in
reverse. Supports merge_outputs (concat fw + bw) and split outputs via
Tuple.
- **BIDIRECTIONAL_SEQUENCE_LSTM**: 48-input operator with fw/bw LSTM
cells sharing
  the same input tensor. States at indices 35-38.
- All converters propagate final states to exp_tab for multi-step
correctness.
- Peephole, projection, layer norm, and aux input are not supported
(raise
  OpNotImplemented).

## Testing

- `test_unidirectional_sequence_lstm_none_activation` — output shape
[batch, time, num_units]
- `test_bidirectional_sequence_rnn_none_activation` —
merge_outputs=True, shape [batch, time, 2*num_units]
- `test_bidirectional_sequence_lstm_none_activation` —
merge_outputs=True, shape [batch, time, 2*num_units]

```bash
python -m pytest tests/python/relax/test_frontend_tflite.py -k "sequence_lstm or sequence_rnn" -v
```
## Summary

This PR adds Relax TFLite frontend support for the TFLite builtin
`STABLEHLO_WHILE` operator.

`STABLEHLO_WHILE` uses StableHLO `BuiltinOptions2` to reference its
condition
and body region subgraphs. Its loop semantics otherwise match the
existing
TFLite `WHILE` importer path: loop-carried tensors are passed to the
cond/body
subgraphs, the cond subgraph returns a scalar bool, and the body
subgraph
returns the updated loop state.

## Design

### Shared While Lowering

The native TFLite `WHILE` converter is refactored through a shared
`_convert_while_like` helper. Native `WHILE` and `STABLEHLO_WHILE` now
share the
same validation and lowering path after their options are parsed:

- native `WHILE` reads `WhileOptions` from `BuiltinOptions`
- `STABLEHLO_WHILE` reads `StablehloWhileOptions` from `BuiltinOptions2`

Both paths lower the referenced cond/body subgraphs to private Relax
functions
and emit a recursive private Relax function for the loop.

### Boundary Validation

`STABLEHLO_WHILE` reuses the same guard-first checks as native `WHILE`:

- loop input count must match op output count
- cond subgraph input metadata must match loop-carried tensors
- cond subgraph must have exactly one output
- cond output must be a scalar bool tensor
- body subgraph input and output metadata must match loop-carried
tensors
- referenced cond/body subgraph indices must be valid non-main subgraphs

The recursive loop-function cache key now includes the generated
function
prefix. This prevents native `WHILE` and `STABLEHLO_WHILE` from
accidentally
sharing a cached loop wrapper if they reference the same cond/body
subgraph
indices.

## Operator Support

| Operator | TFLite options | Relax lowering | Supported subset |
|---|---|---|---|
| `STABLEHLO_WHILE` | `StablehloWhileOptions.CondSubgraphIndex()`,
`BodySubgraphIndex()` from `BuiltinOptions2` | recursive private Relax
function | tensor loop-carried state, scalar bool cond output, matching
cond/body interfaces |

## Tests

The tests manually build a minimal StableHLO while TFLite flatbuffer and
compare
the imported Relax IR with `tvm.ir.assert_structural_equal`. Unsupported
patterns use `pytest.raises`.

| Test | Coverage |
|---|---|
| `test_stablehlo_while` | basic `STABLEHLO_WHILE` recursive private
function lowering |
| `test_stablehlo_while_non_bool_condition_unsupported` | cond output
scalar bool guard |
| `test_stablehlo_while_invalid_index_unsupported` | invalid cond/body
subgraph index guard |
| `test_stablehlo_while_output_count_mismatch_unsupported` | body output
arity guard |
| `test_stablehlo_while_input_metadata_mismatch_unsupported` | cond
subgraph input metadata guard |
| `test_stablehlo_while_output_metadata_mismatch_unsupported` | body
subgraph output metadata guard |

Local validation:

```bash
python -m py_compile \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m ruff check \
  python/tvm/relax/frontend/tflite/tflite_frontend.py \
  tests/python/relax/test_frontend_tflite.py

python -m pytest \
  tests/python/relax/test_frontend_tflite.py \
  -k stablehlo_while -q

python -m pytest \
  tests/python/relax/test_frontend_tflite.py \
  -k stablehlo -q
```

Result:

```text
py_compile: passed
ruff check: All checks passed
stablehlo_while tests: 6 passed
stablehlo tests: 84 passed
```

## References

- Issue apache#19519 item I: remaining StableHLO operators in TFLite
- PR apache#19587: StableHLO region-based ops and multi-subgraph model support
- PR apache#19616: TFLite control-flow / multi-subgraph support
…on (apache#19643)

This PR will fix apache#19592.

LayerNorm could produce NaN on large-value, small-variance inputs due to
catastrophic cancellation in var = E[x^2] - E[x]^2.

Switch to a numerically stable two-pass formulation:

  - pass1 computes mean via sum(x) / N
  - pass2 computes variance via sum((x - mean)^2) / N
tqchen and others added 25 commits June 30, 2026 14:37
…19916)

Structural diagnostics can identify a field below an object that
TVMScript renders without exposing that field. An underline alone then
points at the nearest visible parent and hides the full internal
location. This change keeps Script string-returning while making the
diagnostic context self-contained.

When the requested path is <root>.dtype, Script now returns this string
by default:

```text
Access path: <root>.dtype
Note: The underlined object is the nearest visible parent of this path.

T.int32
^^^^^^^
```

render_invisible_path_info defaults to true. Calls without target paths
are unchanged, and callers can set it to false to retain the legacy
underline-only string.

The implementation reuses the printer span-selection logic to capture
the deepest visible path and assembles the minimal
access-path/note/script block in C++. Pass-error enrichment uses the
same Script path. Production Python remains unchanged; focused Python
tests assert the complete strings for default-on, explicit-false,
hidden, exact-visible, unavailable-visible, pass-error, and
structural-equality cases.
…e#19904)

FlashInfer 0.6.3 changes the paged-attention plan/run ABI: the
prefill/decode plans take new arguments (e.g. window_left,
fixed_split_size, disable_split_kv; the decode plan now dispatches dtype
through empty q/kv tensors), the runs add enable_pdl and drop the
explicit stream, and the kernels consume separate key/value paged caches
read through tensor strides rather than one combined tensor. This
updates
the runtime attention backend (paged MHA, ragged, decode and MLA) to the
new signatures and to the Array<int64_t> plan-info representation.

FlashInfer 0.6.3 reads tensors from `data` directly and does not honor
the DLPack `byte_offset` field. mlc's auxiliary index tensors
(qo_indptr,
kv_indptr, page_indptr, page_indices, length_info) are views packed into
a shared workspace and so carry a non-zero byte_offset; passed as-is the
kernels read the wrong addresses (e.g. a ragged prefill processed only
the first query row). Three zero-copy DLPack view helpers address this:
`ZeroByteOffsetView` folds byte_offset into the data pointer,
`PagedKVCacheView` exposes the combined (num_pages, 2, ...) page tensor
as separate strided key/value caches, and `SliceLastDimView` slices the
last dimension for MLA.

This also completes the MLA FlashInfer path, which previously shipped
only the test and module generator. The MLA run splits the query into
nope/pe parts and the paged cache into ckv/kpe parts, and the ragged
self-attention is given its own uncompressed head dims and per-query kv
head count via a 5-element backend spec, since they differ from the
compressed MLA cache.

The MHA and MLA FlashInfer KV-cache tests are re-enabled as regression
coverage, guarded on FlashInfer availability (inline-RoPE is skipped as
unsupported by FlashInfer).
## Related Issue

closes apache#19689

## Why

The Relax AffineGrid op only handled 2D (4D theta/grid); 5D 3D inputs
from ONNX failed.

## How

- Generalize struct-info inference to 2D/3D via spatial =
size_sinfo->ndim.
- Branch TOPI affine_grid compute on 2D vs 3D.
- Add the 3D permute path in the frontend and a test_affine_grid_3d
case.

---------

Signed-off-by: Guan-Ming (Wesley) Chiu <105915352+guan404ming@users.noreply.github.com>
## Why

The bool→int8 backing-array conversion was duplicated inline across
`FlattenBuffer` and `LowerTIRxCleanup`.

## How

- Add `LowerBoolBuffer` pass that rewrites `bool` buffers to `int8` and
inserts load/store casts.
- Remove the duplicated bool handling from `FlattenBuffer` and
`LowerTIRxCleanup`.
- Run it after FlattenBuffer (before VectorizeLoop) in every pipeline,
with structural and build-and-run tests.

---------

Signed-off-by: Guan-Ming (Wesley) Chiu <105915352+guan404ming@users.noreply.github.com>
This pr adds a onnx helper that cleaned by apache#19880 and fixes ci error
## 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.
## Rationale

`SizeVar` encodes nonnegativity in runtime subtype identity, which is
fragile under cloning and remapping. Symbolic integer values should use
one `Var` representation, with nonnegative facts recorded in the
analyzer at the use sites that establish them.

## Changes

- Remove `SizeVar` from the C++, Python, TE, TVMScript, FFI, visitor,
and serialization surfaces, and migrate callers to `Var`.
- Preserve the existing Relax constraint ownership model and use
`MarkGlobalNonNegValue` as the canonical path for global nonnegative
facts.
- Preserve `T.handle()` as the normal opaque-handle form. An optional
dtype constructs a typed pointer, with `T.handle("void")` reserved for
an explicit pointer-to-void.
Expression unification gives TIRX a shared `Expr` surface, but its
visitor and mutator APIs still expose primitive-only signatures. That
mismatch prevents general expressions from flowing through the existing
traversal structure and leaves statement traversal with overlapping
customization hooks.

This refactor generalizes the existing `ExprFunctor`, `ExprVisitor`, and
`ExprMutator` signatures in place to accept and return `Expr`. Statement
visitors and mutators expose a single virtual `VisitExpr(const Expr&)`
hook, while primitive statement reconstruction uses a non-virtual
checked `VisitPrimExpr` helper so invalid narrowing fails at the
boundary. Public pre-order and post-order traversal entry points accept
general `Expr` roots.

The existing specialization, vtable, dispatch registration, and class
structure remain intact; the change adds no parallel functor, fallback
dispatcher, or alternate implementation path.
Replace MakeConst with direct IntImm construction at call sites whose
static contracts guarantee scalar integer constants.

The repository-wide audit converts 80 call sites across 32 files.
Generic construction remains where runtime dtype, vector behavior,
unsigned range, overload resolution, or invalid-input diagnostics
require it. Eleven initially proposed conversions were reverted after
compilation and focused tests exposed false positives.

Validation:
- LLVM-enabled compiler and runtime library build
- Focused arithmetic, TIR, S-TIR, TOPI, TE, LLVM-codegen, reflection,
and printing suites
- Changed-file pre-commit and git diff checks
…9933)

## Rationale

After `PrimExpr` and `Expr` share one typed expression hierarchy,
expression types are part of semantic identity. Structurally identical
syntax with different types compare and hash differently, while source
spans remain diagnostic metadata.

## Invariant

`ExprNode::ty` participates in structural equality and hashing by
default. `GlobalVar` and Relax variables retain their symbol identity
rules. `tirx.PrimFunc` compares and hashes authoritative source fields
while excluding its derived type cache until all transformation paths
maintain that cache eagerly. Nested symbolic-shape rendering is isolated
from outer diagnostic configuration so diagnostic context cannot become
script-token content.

## Changes

- include expression types in generic structural equality and hashing
- preserve GlobalVar and Relax variable identity plus definition-safe
SeqExpr traversal
- compare and hash PrimFunc from authoritative fields while excluding
its stale derived type cache
- normalize narrow Relax construction and expected-fixture types exposed
by stricter identity
- isolate nested symbolic-shape token rendering from outer printer
configuration
Generated LLVM modules currently cache imported packed functions through
an unsynchronized null check and plain store. Concurrent first calls can
therefore race the lookup and cache update.

This change:

- routes generated C and LLVM lookups directly through
TVMFFIEnvModLookupFromImports and removes the superseded
TVMBackendGetFuncFromEnv wrapper;
- gives each LLVM cached function a readable internal hidden initializer
and publishes its module-owned result through TVMFFIHandleInitOnce;
- removes the unused TVMBackendRunOnce export and dead LLVM static-init
producer while preserving the live static-handle path.

Validated with the existing LLVM, C-host, common codegen, static-init,
and C++ test suites.
…pache#19941)

The Python unittest CI step previously looped over each collected test
directory and invoked `run_pytest` once per directory. Splitting related
tests across many pytest invocations fragments Jenkins failure reports.

This change collects the ordered test directory list into a
`PYTEST_TARGETS` array first, then passes the full target set to a
single `run_pytest` invocation. Target ordering, pytest flags
(`--reruns=3`, `-n=1`), `PYTEST_ADDOPTS` environment setup, and per-test
failure behavior are unchanged; the platform-minimal run remains a
separate invocation with its own JUnit XML.

This keeps related failures within one pytest report for clearer CI
output.
Add tvm.testing.run_with_gpu_lock backed by the existing
tvm_ffi.utils.FileLock. Migrate live local GPU tests to acquire the
machine-local lock around device execution, synchronization, host
transfer, and checks while leaving target construction and compilation
outside the critical section.

Replace the custom xdist scheduler with standard xdist_group placement
for the order-dependent test family. RPC tests retain dynamic port
allocation and per-test process isolation rather than gaining a broad
category lock.
…e#19940)

Replace the nested `DocToPythonScript` invocation in Relax
dependent-shape printing with an expression-string Doc rendered during
the active `PythonDocPrinter` traversal.

This keeps recursive IR-to-doc conversion inside the active docsifier,
preserves naming, precedence, escaping, source paths, and printer
configuration, and avoids a nested top-level renderer or a new public
rendering entry point.

Expression-string escaping is streamed directly into the final output so
wrapper and nested source spans retain exact escaped byte offsets.
)

## Summary

- Move whole-Tensor arithmetic and cast dispatch onto `te.Tensor` while
scalar TIRx smart constructors decline whole-Tensor operands.
- Remove the legacy `tirx.generic` module, TOPI import-time mutation
bridge, and obsolete aliases.
- Migrate scan and cast callers while preserving identity-gated Thrust
sum selection.

Whole-Tensor behavior now lives with TE, leaving scalar TIRx
construction independent of TOPI initialization.
## 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.
Retire GitHub automation that is disabled, non-functional, unowned, or
explicitly no longer wanted, together with its orphaned support code and
tests.

This removes the optional Dependabot version-update config; automatic
team mentions and cc-review requests; last-successful and nightly branch
advancement; reviewer pings; the disabled PR-comment bot; and the unused
CI-resource upload path. Active CI, release, tvm-bot, and manual
Docker-update workflows remain, with narrower permissions and event
guards, plus refreshed issue-template and network-resource guidance.

The behavior change is intentional: reviewer requests and team routing
become manual, and the nightly and last-successful branches are no
longer advanced by this repository. Dependabot security updates remain
controlled by repository settings.
This PR simplifies Jenkins pytest execution around standard pytest-xdist
behavior.

- Runs each already-filtered CPU/GPU suite once with `-n auto`; the
broad suite keeps load-group scheduling because its order-sensitive
cases require it.
- Removes external sharding, wrapper/profile code, JUnit XML generation
and publication, the skipped-test XML consumer, obsolete suite naming,
and orphaned helpers.
- Retains one inert `task_clear_pytest.sh` entry point only because PR
jobs evaluate their Jenkinsfile from the trusted base branch before
checking out the PR; it performs no cleanup or reporting and can be
removed after this pipeline lands.
- Corrects stale broad-suite paths and explicit target guards, and
migrates a scalar stride test to the current `T.handle` pointer
semantics while preserving its negative lowering check.
- Prevents nested MetaSchedule/XGBoost unit tests from multiplying CPU
fanout without serializing the full suite.
- Builds only the `tvm_runtime` target for the secondary GPU
configuration and removes its unconsumed `gpu2` artifact upload.

The result reduces parallelism to one layer managed by pytest-xdist
while preserving GPU filtering and native failure visibility.
## Summary

- remove redundant parentheses from four VM dtype comparisons
- clean up pessimizing moves, missing overrides, unused state, and
hidden virtual overloads reported by macOS Clang
- preserve `PrimType` across source-codegen type-bearing paths and
remove transitional raw dtype adapters
- retain raw `DLDataType` only for explicit runtime launch metadata and
runtime-helper boundaries
- leave the deferred LLVM and CMake compatibility paths unchanged

`PrimType::operator==` already compares the represented dtype by code,
bits, and lanes, so no backend-specific non-identity equality regression
is needed.

## Validation

- compiled all original warning-producing translation units with Clang
22 and the relevant warning families promoted to errors
- built `tvm_runtime` and `tvm_compiler` with LLVM 15 after the codegen
migration
- passed 14 focused C-host, bool, OpenCL, Metal, device, and Vulkan
codegen tests, with 70 hardware-dependent skips
- generated OpenCL C, Metal, WGSL, and CUDA source from the same typed
kernel
- compiled the changed Hexagon and Vulkan translation units
independently
- passed pre-commit, Git whitespace/log checks, and a static audit
leaving raw codegen `DLDataType` declarations only at the WebGPU runtime
ABI boundary
…#19927)

This PR updates `IRMutatorWithAnalyzer` and `IRVisitorWithAnalyzer` to
add the constraint `loop_extent > 0` while visiting a `ForNode` body.

If execution reaches the loop body, the loop must have at least one
iteration, so the body context can safely assume the extent is positive.
The constraint is scoped only to the loop body, leaving the loop header
expressions (`min`, `extent`, `step`) outside of this assumption.

While validating this change, it exposed an issue in `IntSetAnalyzer`:
one-sided constraints such as `m > 0` could cause existing parametric
bounds like `m - 1` to be recursively relaxed to `+inf`. This caused
`DomainTouched` to lose finite symbolic bounds. The PR fixes this by
preserving existing parametric bounds when recursive interval relaxation
would otherwise replace them with infinity.
## Summary

- Keep the Python test launcher close to plain `pytest -n auto`, move
nightly tests under `tests/nightly/python`, remove obsolete launchers
and collection bookkeeping, and partition CPU/GPU jobs with explicit
`gpu` marker expressions.
- Repair exact-pointer regressions at their owning boundaries: packed
raw-string ABI values, CUDA/Metal matrix intrinsic pointers, internal TE
extern offsets, MetaSchedule scalar annotations, localized
auto-tensorization scope matching, and typed DLTensor fixture fields.
- Preserve typed workspace calls in TIR and cast pointer-returning
external calls in CodeGenC, covered by a plain-TIRx 1024-byte global
workspace that is compiled as C++.
- Finish phasing out value-bearing Relax `R.Prim` annotations by
requiring an explicit dtype, removing obsolete value-based contracts,
and expressing the DISCO rank-dependent slices as explicit scalar
`call_tir` inputs.
- Gate the distributed callback on the optional DISCO runtime, NCCL, and
at least two GPUs so capability-limited jobs skip instead of failing.
- Remove the non-demonstrating pointer probe, use direct TVMScript
comparison for packed strings, and remove the four designated legacy
testing modules.

The seven repaired CPU categories cover packed raw strings (7 failures),
CUDA/Metal matrix access-pointer types (7), internal TE extern offsets
(1), a typed DLTensor fixture (1), MetaSchedule scalar annotations (1),
CodeGenC workspace return casts (12), and localized auto-tensorization
storage-scope matching (19).

## Validation

- Base: `ded6ad8dd212869c881efb5590f8a33fc972728e`
- Head: `a7277e86dbcfe0638c8c252d36760859c4ab4297`
- All 35 locally available original failing node IDs pass across the
focused runs.
- The full focused TE, TIR builtin-lowering, and CodeGenC files pass: 61
tests.
- The complete touched Relax/TVMScript set plus
PlanAndUpdateBufferAllocationLocation passes with 784 passed, 20
skipped, and 1 expected failure.
- The DISCO callback collects and skips when its runtime or two-GPU
environment is unavailable.
- Six direct mapping tests, twelve tensor-core sketches, and the dp4a
sketch pass unchanged.
- The compiler rebuild, branch-wide pre-commit hooks, and full-range
whitespace checks pass.
- The 13 broad CBLAS/TFLite nodes remain dependency-gated; their owning
TE and generated-C regressions compile.

No merge is included in this change.
## Summary

Update TVM to tvm-ffi's stable `TVMFFIAny`-backed Optional and Variant
layout.

- bump `3rdparty/tvm-ffi` from `84ee1a07` to `5411a642`
- migrate Optional presence checks from the removed inherited
`defined()` API
- adapt pointer, cast, JSON, and FFI return sites while preserving
missing-value semantics
- require `apache-tvm-ffi>=0.1.13` and preserve the source-matched FFI
build in the macOS wheel smoke test

## Validation

Validated with linked LLVM builds, default and conditional backend
compilation, an Emscripten 4.0.23 WebAssembly compile/link, C++
Optional/FFI and TVM suites, focused runtime/IR/Relax Python tests,
broad regression coverage, repository format/static checks, production
wheel metadata inspection, and an isolated source-FFI wheel
install/import smoke test.

## Release compatibility blocker

Do not merge or publish this bump until the tvm-ffi 0.1.13 release
preserves compatibility for TVM 0.25's by-value JSON `Stringify`
consumer, or an equivalent non-matching release/version strategy is in
place. The release also needs coordinated handling for the published
ORCJIT extension: `apache-tvm-ffi-orcjit==0.1.0` returns
`Optional<Function>` by value while the new layout grows from 8 to 16
bytes, which can corrupt return storage when mixed with the new runtime.
TVM's wheel now requires `apache-tvm-ffi>=0.1.13`; resolver-driven
publish tests remain enabled so production publication fails closed
until a compatible release exists.
## Rationale

Analyzer constraint scopes continue to provide loop-positive facts to
constant-bound and rewrite proofs. During IntSet relaxation, however, a
scoped domain constraint is a refinement only for a variable explicitly
present in the relaxation map. Applying it to an unmapped variable
reinterprets a free parameter as a relaxation domain and can let a
loop-local symbol survive recursive interval evaluation.

## Changes

- Apply scoped IntSet constraints only to variables already present in
the relaxation map; unmapped variables remain free parameters.
- Remove the finite-bound restoration fallback and its stronger
parametric-bound contract.
- Add a direct compact-buffer regression that prevents a loop-local
variable from escaping into a function-scope allocation extent.
Remove the Relax-specific Id indirection and use Var/DataflowVar object
identity directly.

Type-changing rewrites now remap definitions, uses, and binding lookups
coherently while preserving reflection, serialization, and the
DataflowVar subtype. Existing tests are adjusted for the API change; no
new test files or test cases are added.

Validation: the compiler and C++ tests build successfully; focused C++
coverage passes 4/4; the affected existing Python matrices pass 549
tests with 2 expected xfails; source censuses, diff checks, and
applicable hooks pass.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for dynamic indices when gathering from a relax.ShapeExpr in the ONNX frontend by materializing the shape as an int64 tensor and performing a dynamic gather. A new test is also added to verify this behavior. Feedback points out a correctness issue in the constant-index fast path where multi-element constant indices are incorrectly handled, and suggests restricting this fast path to constants of size 1.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread python/tvm/relax/frontend/onnx/onnx_frontend.py Outdated
The ONNX importer's Gather converter asserted that indices must be a
constant whenever the data operand is a ShapeExpr, raising
"Only constant indices supported for shape gather." for any
runtime-computed index. Detection post-processing graphs such as
FasterRCNN feed a dynamic index into a Gather whose data comes from a
Shape node, so import failed before compilation could start.

Keep the fast path for a single constant index, which resolves one
dimension to a PrimValue and preserves shape-specialized handling
downstream. Any other index (dynamic, or a constant selecting multiple
dimensions) materializes the shape as an int64 tensor via
shape_to_tensor and gathers from it at runtime, reusing the existing
negative-index normalization.

Adds a regression test that gathers a dimension out of a Shape result
using a non-constant index, covering positive and negative indices, and
checks it against onnxruntime.

Fixes part of apache#19965.
@hamzaqureshi5 hamzaqureshi5 force-pushed the fix/onnx-gather-dynamic-shape-index branch from e0aa965 to 44b2dff Compare July 8, 2026 12:48
@hamzaqureshi5 hamzaqureshi5 deleted the fix/onnx-gather-dynamic-shape-index branch July 8, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.