[Relax][Frontend][TFLite] Support dynamic DYNAMIC_UPDATE_SLICE starts#19881
[Relax][Frontend][TFLite] Support dynamic DYNAMIC_UPDATE_SLICE starts#19881Aharrypotter wants to merge 2 commits into
Conversation
_convert_stablehlo_dynamic_update_slice previously raised OpNotImplemented when the start-index scalars were runtime (non-constant) values, only handling compile-time-constant starts. This was the DYNAMIC_UPDATE_SLICE "partial implementation" item tracked in apache#19412. scatter_nd already accepts a general runtime indices tensor, so no new op is needed. Add a dynamic branch that builds the index grid in-graph: per axis, arange(update_dim) + clamp(start, 0, operand_dim - update_dim), broadcast to the update shape and concatenated on a trailing axis. Clamping matches StableHLO, which clamps out-of-range starts rather than erroring. The static path (compile-time index grid, out-of-bounds rejection) is unchanged. Replace the "not supported" test with a compile-and-run test that exercises both an in-range start and an out-of-range start (verifying clamping).
There was a problem hiding this comment.
Code Review
This pull request adds support for converting STABLEHLO_DYNAMIC_UPDATE_SLICE with dynamic start indices in the TVM Relax TFLite frontend by lowering it to relax.op.scatter_nd and building the index grid dynamically at runtime. It also adds a test case to verify correct execution and clamping behavior. Feedback suggests improving robustness by explicitly passing start, stop, and step constants to relax.op.arange to avoid type mismatches, and adding compile-time validation to ensure update slice dimensions do not exceed operand dimensions.
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.
Apply Gemini Code Assist review feedback to the dynamic-start DYNAMIC_UPDATE_SLICE converter: - Validate at import time that update dimensions do not exceed operand dimensions, matching StableHLO's precondition and avoiding negative clamp bounds. - Pass explicit start/stop/step to relax.op.arange for clarity and to avoid relying on default-argument dtype behavior.
Summary
This PR adds Relax TFLite frontend support for runtime (dynamic) start indices
in
STABLEHLO_DYNAMIC_UPDATE_SLICE, addressing theDYNAMIC_UPDATE_SLICEitemfrom #19412 section B.
_convert_stablehlo_dynamic_update_slice(added in #19587) previously raisedOpNotImplementedwhen 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_SLICEtorelax.op.scatter_nd, building the scatter index grid at compile time withnumpy.indices.scatter_ndaccepts a general runtimeindicestensor andreturns the
data(operand) shape unchanged, so the dynamic case needs no newop 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 isstatically known from the operand/update shapes):
[0, operand_dim - update_dim]withrelax.op.maximum/relax.op.minimum— StableHLO clamps out-of-range starts rather than erroring;idx = arange(update_dim) + clamped_start;idxto broadcast on axisaandbroadcast_tothe update shape;expand_dimsa trailing index axis.concatover the axes produces an int64 index tensor of shape(*update_shape, rank), which is fed to the samerelax.op.scatter_nd(operand, indices, update, "update")call the static pathuses.
The static (constant-start) path is unchanged, including its compile-time
out-of-bounds rejection.
Operator Support
STABLEHLO_DYNAMIC_UPDATE_SLICEoperand,update, N scalarstartindicesrelax.op.scatter_ndwith a NumPy index grid (constant starts) or an in-grapharange+ clamp index grid (runtime starts)Not Included
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_stablehlo_dynamic_update_slicetest_stablehlo_dynamic_update_slice_dynamic_startstest_stablehlo_dynamic_update_slice_out_of_bounds_unsupportedLocal validation:
Result:
References
DYNAMIC_UPDATE_SLICESTABLEHLO_DYNAMIC_UPDATE_SLICE(constant starts) andmulti-subgraph / StableHLO region support