[Relax][Frontend][TFLite] Support StableHLO region-based ops and multi-subgraph models#19587
Merged
Merged
Conversation
… layout np.indices returns (rank, *update_shape) but scatter_nd expects (*update_shape, rank). Add np.moveaxis to transpose the coordinate axis from first to last position.
Contributor
There was a problem hiding this comment.
Code Review
This pull request significantly expands the TFLite frontend's support for StableHLO operators in TVM Relax. It introduces conversions for several complex operations, including REDUCE, SCATTER, SORT, CONVOLUTION, and DOT_GENERAL. Additionally, it adds support for handling multiple subgraphs, which are used as region bodies for these operators. Feedback suggests simplifying the STABLEHLO_CBRT implementation using relax.op.sign and relax.op.abs for better conciseness and potential backend efficiency. Another suggestion points out an opportunity to optimize constant handling during the decomposition of STABLEHLO_COMPOSITE operators by reusing existing expressions instead of re-creating them.
Contributor
Author
|
cc @tlopex |
tlopex
approved these changes
May 21, 2026
This was referenced May 25, 2026
Aharrypotter
added a commit
to Aharrypotter/tvm
that referenced
this pull request
May 26, 2026
Add Relax TFLite frontend support for the TFLite control-flow and multi-subgraph operators from apache#19519 item F: CALL, IF, WHILE, and the no-op subset of CALL_ONCE. The implementation builds on the multi-subgraph import infrastructure from apache#19587. Referenced subgraphs are lowered to private Relax functions with isolated expression tables and shared lowering state, while the main TFLite subgraph remains the Relax main function. - Lower CALL targets to private Relax functions and emit ordinary Relax function calls. - Lower IF branches to private Relax functions and emit a private wrapper function containing Relax If. - Lower WHILE cond/body subgraphs to private Relax functions and emit a recursive private Relax loop function. - Support CALL_ONCE only when the init subgraph is empty; non-empty init subgraphs remain guarded because they may model resource initialization side effects. - Validate referenced subgraph input/output counts and static tensor metadata at CALL, IF, and WHILE boundaries. Added hand-built TFLite flatbuffer tests with structural equality coverage for CALL, IF, WHILE, empty CALL_ONCE, multi-output CALL, multi-output IF, and two-loop-var WHILE. Added unsupported-path tests for non-empty CALL_ONCE, invalid subgraph indices, arity mismatches, non-bool IF/WHILE conditions, and static metadata mismatches.
Aharrypotter
added a commit
to Aharrypotter/tvm
that referenced
this pull request
May 26, 2026
Add Relax TFLite frontend support for the TFLite control-flow and multi-subgraph operators from apache#19519 item F: CALL, IF, WHILE, and the no-op subset of CALL_ONCE. The implementation builds on the multi-subgraph import infrastructure from apache#19587. Referenced subgraphs are lowered to private Relax functions with isolated expression tables and shared lowering state, while the main TFLite subgraph remains the Relax main function. - Lower CALL targets to private Relax functions and emit ordinary Relax function calls. - Lower IF branches to private Relax functions and emit a private wrapper function containing Relax If. - Lower WHILE cond/body subgraphs to private Relax functions and emit a recursive private Relax loop function. - Support CALL_ONCE only when the init subgraph is empty; non-empty init subgraphs remain guarded because they may model resource initialization side effects. - Validate referenced subgraph input/output counts and static tensor metadata at CALL, IF, and WHILE boundaries. Added hand-built TFLite flatbuffer tests with structural equality coverage for CALL, IF, WHILE, empty CALL_ONCE, multi-output CALL, multi-output IF, and two-loop-var WHILE. Added unsupported-path tests for non-empty CALL_ONCE, invalid subgraph indices, arity mismatches, non-bool IF/WHILE conditions, and static metadata mismatches.
tlopex
pushed a commit
that referenced
this pull request
May 27, 2026
…rs (#19616) ## Summary This PR adds Relax TFLite frontend support for the TFLite builtin control-flow / multi-subgraph operator family from #19519 item F: `CALL`, `IF`, `WHILE`, and `CALL_ONCE`. It builds on the multi-subgraph import infrastructure merged in PR #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 #19519 item F: TFLite control-flow / multi-subgraph operators - PR #19587: StableHLO region-based ops and multi-subgraph model support
tlopex
pushed a commit
that referenced
this pull request
May 27, 2026
…19601) ## Summary This PR adds Relax TFLite frontend support for `UNIDIRECTIONAL_SEQUENCE_RNN` (BuiltinOperator 35), claimed in [#19519](#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 (#19536, #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 [#19519](#19519) Group A: Sequence / recurrent model operators Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tlopex
pushed a commit
that referenced
this pull request
May 31, 2026
## 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 #19519 item I: remaining StableHLO operators in TFLite - PR #19587: StableHLO region-based ops and multi-subgraph model support - PR #19616: TFLite control-flow / multi-subgraph support
This was referenced Jun 24, 2026
tlopex
pushed a commit
that referenced
this pull request
Jun 25, 2026
…#19881) ## Summary This PR adds Relax TFLite frontend support for runtime (dynamic) start indices in `STABLEHLO_DYNAMIC_UPDATE_SLICE`, addressing the `DYNAMIC_UPDATE_SLICE` item from #19412 section B. `_convert_stablehlo_dynamic_update_slice` (added in #19587) previously raised `OpNotImplemented` when the start-index scalars were runtime (non-constant) values, handling only compile-time-constant starts. Models that compute the update offset at runtime could therefore not be imported. This PR makes the dynamic-start path work, with StableHLO clamping semantics, without adding a new Relax op. The change is limited to this converter and its test. ## Design ### Dynamic start indices via scatter_nd The existing static path already lowers `STABLEHLO_DYNAMIC_UPDATE_SLICE` to `relax.op.scatter_nd`, building the scatter index grid at compile time with `numpy.indices`. `scatter_nd` accepts a general **runtime** `indices` tensor and returns the `data` (operand) shape unchanged, so the dynamic case needs no new op and introduces no symbolic dimensions — only the index grid is built in-graph instead of in NumPy. For runtime starts, the converter builds the index grid per axis `a` (rank is statically known from the operand/update shapes): - clamp the start to `[0, operand_dim - update_dim]` with `relax.op.maximum` / `relax.op.minimum` — StableHLO clamps out-of-range starts rather than erroring; - `idx = arange(update_dim) + clamped_start`; - reshape `idx` to broadcast on axis `a` and `broadcast_to` the update shape; - `expand_dims` a trailing index axis. `concat` over the axes produces an int64 index tensor of shape `(*update_shape, rank)`, which is fed to the same `relax.op.scatter_nd(operand, indices, update, "update")` call the static path uses. The static (constant-start) path is unchanged, including its compile-time out-of-bounds rejection. ## Operator Support | Operator | TFLite inputs | Relax lowering | Supported subset | |---|---|---|---| | `STABLEHLO_DYNAMIC_UPDATE_SLICE` | `operand`, `update`, N scalar `start` indices | `relax.op.scatter_nd` with a NumPy index grid (constant starts) or an in-graph `arange` + clamp index grid (runtime starts) | static operand/update shapes; constant or runtime start indices | ## Not Included - Dynamic (non-static) operand or update shapes — the index grid is built from the statically known update shape, so operand/update shapes must be static. Runtime *start indices* are supported; runtime *tensor shapes* are not. ## Tests The dynamic-start test compiles the imported module and runs it on the Relax VM, comparing the output against a NumPy reference; it includes an out-of-range start to exercise clamping. The static structural-equal and out-of-bounds tests are unchanged. | Test | Coverage | |---|---| | `test_stablehlo_dynamic_update_slice` | constant start indices, structural-equal (existing) | | `test_stablehlo_dynamic_update_slice_dynamic_starts` | runtime start indices, compile + run, including an out-of-range start that is clamped | | `test_stablehlo_dynamic_update_slice_out_of_bounds_unsupported` | constant-start path rejects out-of-bounds updates (existing) | 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 dynamic_update_slice -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 dynamic_update_slice tests: 3 passed, 555 deselected full TFLite pytest: 558 passed ``` ## References - Issue #19412 section B: `DYNAMIC_UPDATE_SLICE` - PR #19587: introduced `STABLEHLO_DYNAMIC_UPDATE_SLICE` (constant starts) and multi-subgraph / StableHLO region support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds Relax TFLite frontend support for 10 additional StableHLO builtin
operators from #19519 item I, building on the 29 ops merged in PR #19536.
The first 5 ops are direct single-subgraph converters:
CBRT,REMAINDER,DYNAMIC_UPDATE_SLICE,DOT_GENERAL, andCONVOLUTION. The remaining 5 opsare region/subgraph-based:
REDUCE,REDUCE_WINDOW,SORT,SCATTER, andCOMPOSITE. To support these, the TFLite frontend is extended to acceptmulti-subgraph models while still converting only
Subgraphs(0)into theRelax main function. Region subgraphs are consumed by their parent op
converters as needed.
Relates to #19519.
Changes
Single-subgraph ops
CBRT— sign-preserving composite expression:where(x < 0, -power(-x, 1/3), power(x, 1/3)). Float dtype only.REMAINDER— truncating remainder viax - y * trunc(x / y), matchingStableHLO semantics (sign follows dividend). Float dtype only.
DYNAMIC_UPDATE_SLICE— static start indices + static shapes only, loweredto
R.scatter_ndwith a coordinate grid generated vianp.indices.Runtime starts and out-of-bounds ranges raise
OpNotImplemented.DOT_GENERAL— canonical 2D matmul subset: no batching dims,lhs_contracting=[1],rhs_contracting=[0], lowered toR.matmul.CONVOLUTION— canonical 2D NHWC/HWIO subset withBatchGroupCount=1,FeatureGroupCount=1, lowered toR.nn.conv2d. Non-canonical dimensionnumbers and grouped/depthwise conv raise
OpNotImplemented.Multi-subgraph infrastructure
from_tflite()assertion frommodel.SubgraphsLength() == 1tomodel.SubgraphsLength() >= 1. OnlySubgraphs(0)is converted into theRelax main function.
_input_type()toSubgraphs(0)inputs, preventing regionparameters from leaking as Relax main function parameters.
_get_stablehlo_simple_body_ophelper for validating and extractingthe single operator from a region body subgraph.
_finish_tflite_modelwithextra_subgraphsparameterfor constructing multi-subgraph TFLite flatbuffers.
Region/subgraph ops
REDUCE— single-op reducer body subgraph. SupportsADD→R.sum,MAXIMUM→R.max,MINIMUM→R.min,MULTIPLY→R.prod.Init value must match the reducer identity element.
SORT— single-op comparator body subgraph.LT→ ascending sort,GT→ descending sort viaR.sort.IsStableis not mapped.REDUCE_WINDOW— NHWC 4D 2D-pooling subset withMAXIMUMreducer andidentity init, lowered to
R.nn.max_pool2d. BaseDilations must be all 1.SCATTER— single-op update computation body subgraph. SupportsADD/MAXIMUM/MINIMUM/MULTIPLY→R.scatter_ndwith thecorresponding reduction mode. Only canonical point-update semantics
(no window dims).
COMPOSITE— inlines a decomposition subgraph through a recursiveOperatorConverterwith an isolatedExprTable, so decomposition tensorbindings cannot overwrite main graph bindings. Only supports composites
without
CompositeAttributes.Not included
STABLEHLO_RESHAPE,STABLEHLO_TRANSPOSE, andSTABLEHLO_SLICEWHILE,CUSTOM_CALL, andRNG_BIT_GENERATORBug fix
DYNAMIC_UPDATE_SLICEscatter_nd indices layout:np.indicesreturns
(rank, *update_shape)butscatter_ndexpects(*update_shape, rank). Addednp.moveaxisto transpose the coordinateaxis from first to last position.
Testing
All tests use manually-built minimal TFLite flatbuffers with
tvm.ir.assert_structural_equal. Region/subgraph tests construct the smallestvalid body/comparator/update subgraphs. BuiltinOptions2 ops construct their
options via the FlatBuffers schema API.
Result
39 StableHLO operators registered in the Relax TFLite frontend (29 from
PR [Relax][Frontend][TFLite] Add initial StableHLO builtin operator support #19536 + 10 from this PR).
77 StableHLO test cases covering all registered ops, including
structural-equal tests and unsupported/error-path checks:
REMAINDERtruncating semanticsDYNAMIC_UPDATE_SLICEwith dynamic starts and out-of-bounds startsDOT_GENERALwith non-canonical contracting dimensionsCONVOLUTIONwith non-canonical dimension numbers andFeatureGroupCount > 1REDUCEwith unsupported reducer and non-identity init valueSORTwith unsupported comparator and stable sortREDUCE_WINDOWwith unsupported reducer and base dilationSCATTERwith unsupported reducer and update window dimsCOMPOSITEwith composite attributes and scope isolationAll 77 StableHLO tests pass.
References