fix: eliminate non-constant Slice ends in sliding-window CB subfunction - #1179
Open
quic-amitraj wants to merge 3 commits into
Open
fix: eliminate non-constant Slice ends in sliding-window CB subfunction#1179quic-amitraj wants to merge 3 commits into
quic-amitraj wants to merge 3 commits into
Conversation
quic-amitraj
force-pushed
the
fix/gemma4-sliding-window-subfunction-slice-main
branch
2 times, most recently
from
July 16, 2026 10:11
828d727 to
f4d0bc9
Compare
quic-hemagnih
approved these changes
Jul 17, 2026
quic-amitraj
force-pushed
the
fix/gemma4-sliding-window-subfunction-slice-main
branch
from
July 21, 2026 17:58
b95f6ff to
0493804
Compare
quic-rishinr
requested changes
Jul 22, 2026
| ctx_indices = torch.where(invalid_mask, invalid_idx_value, ctx_indices) | ||
|
|
||
| all_indices = torch.arange(layer_ctx_len) + kv_position_ids.max() + 1 | ||
| all_indices = torch.arange(ctx_len) + kv_position_ids.max() + 1 |
Contributor
There was a problem hiding this comment.
How is this working for the other models if we're using the same logic in the cache utilities?
all_indices = torch.arange(layer_ctx_len) + kv_position_ids.max() + 1.
The same change is already present in both HybridChunkedCache and HybridCache.
…on (QRANIUMSW-62851)
In QEffHybridCache, QEffHybridChunkedCache, and QEffGemma4DynamicLayer,
the rolling-index computation for sliding-window CB caches was:
all_indices = torch.arange(layer_ctx_len) + kv_position_ids.max() + 1
rolling_indices = torch.where(...)
rolling_indices = rolling_indices[:ctx_len] # <- Slice node
When compiled with -sub-functions, QAIC subfunction lowering rejects
Slice operators whose `ends` input is a non-constant function argument.
ctx_len (= Shape(past_key)[2] = sliding_window) is pre-computed in the
outer ONNX graph and injected into the subfunction as an opaque INT32
parameter. The compiler raises:
[Operator-'Slice_N']: Slice: Non-constant ends tensor not supported.
Fix: replace torch.arange(layer_ctx_len)[:ctx_len] with torch.arange(ctx_len)
directly. arange(n)[:n] == arange(n) identically; no behavioural change.
The Range op with a dynamic upper bound is already supported in QAIC
subfunction lowering. The Slice node is eliminated entirely.
Same class of bug as the CtxGatherCB comp_ctx_len fix in commit c89c4f7.
Affects: Gemma4-E2B, Gemma4-E4B with use_onnx_subfunctions=True in
qaic-vllm disaggregated serving (decode QPC compilation).
Signed-off-by: Amit Raj <amitraj@qti.qualcomm.com>
Signed-off-by: Amit Raj <amitraj@qti.qualcomm.com>
quic-amitraj
force-pushed
the
fix/gemma4-sliding-window-subfunction-slice-main
branch
from
July 28, 2026 10:10
ccc7829 to
a0f8083
Compare
Signed-off-by: Amit Raj <amitraj@qti.qualcomm.com>
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.
Problem
When compiling Gemma4-E2B or Gemma4-E4B with
use_onnx_subfunctions=Truein qaic-vllm disaggregated serving, the decode QPC compilation consistently fails:The encoder QPC compiles successfully; only the decoder (with
-sub-functions) fails.JIRA:
Root Cause
In
QEffHybridCache,QEffHybridChunkedCache, andQEffGemma4DynamicLayer(cache_utils.py), the sliding-window rolling-index computation was:The
rolling_indices[:ctx_len]slice becomes an ONNXSlicenode inside theQEffGemma4TextDecoderLayersubfunction. Itsendstensor isctx_len = Shape(past_key)[2](=sliding_window), which is pre-computed in the outer ONNX graph asGather(Shape(past_key), 2)and injected into the subfunction as an opaqueINT32argument. Inside the subfunction body, the QAIC compiler cannot resolve this as a compile-time constant and rejects the graph.This is the same class of bug as the
CtxGatherCBcomp_ctx_lenfix in commitc89c4f71.Fix
Replace
torch.arange(layer_ctx_len)[:ctx_len]withtorch.arange(ctx_len)directly:arange(n)[:n] == arange(n)identically — no behavioural change. The resultingRangeop with a dynamic upper bound is already permitted in QAIC subfunction lowering (the existingctx_indices = torch.arange(ctx_len)in the same function demonstrates this). The Slice node is eliminated entirely.The fix is also correct for the CCL case:
arange(min(sliding_window, CCL))naturally producesCCLelements without slicing.Changes
QEfficient/transformers/cache_utils.pyarange(layer_ctx_len)[:ctx_len]witharange(ctx_len)inQEffHybridCache.update(),QEffHybridChunkedCache.update(), andQEffGemma4DynamicLayer.update()Test Plan
gemma4_cb.pywithuse_onnx_subfunctions=True,continuous_batching=True,full_batch_size=4, 2-layer reduced config — compiles and runs end-to-end on AI100gemma4_cb.pywithuse_onnx_subfunctions=False— no regressionSlice_520absent from re-exported subfunction ONNX bodyrelease/v1.22.0as PR fix: eliminate non-constant Slice ends in Gemma4 sliding-window CB subfunction #1170Sdk: 1.22.1.18