Repository navigation
Conversation
77ff0d4 to
77ed9ed
Compare
…r) — 87 counter `while` loops with an unroll marker in linear/{delta,conv,norm_gate}, flash_gqa, flash_gqa_prefill, flash and rope_neox become `for i in 0..N` with the same marker (ledger #31 closed by NVIDIA/cuda-rust#1346 in the pin); the prefill-256 body adds the warp-half offset into its K/V bases once before the loop, so the per-step ldmatrix offsets stay immediates (ptxas 250 regs, predicted 190–200), and its exchange add is one add (IEEE add commutes); gpu-deepseek41 takes `expf_ik` from bloomery_gpu::linear
`needless_range_loop` is allowed per fn with its reason: an iterator loop is not unrolled and keeps its array in a local depot. sihyung: check rc 0, clippy 48, fmt ok, gpu-gates lib 43 passed. Box-ready: ptx-scan of generate_ds41, gate_e2e, gate_linear and gate_qwen35moe_attn predicted identical instructions everywhere except gqa_prefill_flash_256; gate-gpu-linear, gate-gpu-qwen35moe-attn and gate-ptx-spill predicted green (not yet run).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9xdyin8HGq4ZLiEreJzey
`#[unroll]` on `for i in a..b` did not unroll: the loop exits through a match on the `Option` from the inlined `Range::next`, so the counter is not an induction variable. Rewrite that match into a header test before the unroll analysis. No block is copied, and loops whose header already exits are unchanged. Signed-off-by: midagedev <midagedev@gmail.com>
77ed9ed to
5a59773
Compare
|
I tested this PR on the real-use question from #559 and found one gap: range loops with signed counters, including the default Setup: PR head Real use: a Q4_K prefill MMA tileThe kernel is a 128×128 int8
Timing covers the tile plus its activation-quantization kernel: 40 launches per CUDA graph after warmup, 8 samples per shape, with builds interleaved. Medians:
*In those runs the paired native CUDA kernel was also about 10% slower. Against it, the ratio is 0.79 versus 0.76, so the difference is about +3.5%. On Gap: signed counters (
|
|
Thank you for testing this on a real kernel, and for finding the cause. I can reproduce the shape from your dump: signed |
core steps a signed counter through checked_add (checked_sub for .rev()), with the tuple in a stack slot and a branch on the overflow flag before the arm's goto. When the header tests lo < hi and the step is one, the step cannot overflow and the overflow edge leaves the loop, so fold the step to a plain add or sub and the branch to a goto. The next round sees the unsigned shape. An inferred-i32 counter (used only through `as`) now unrolls: the tester's range_i32 kernel goes from 2 warnings, 18 ld/st.local and 3 branches to 0, 0 and 0, and its PTX equals the usize form. unroll_smoke's existing kernels keep their PTX. Signed-off-by: midagedev <midagedev@gmail.com>
|
Pushed 20e30b6. Thank you for the clear report and the reproducer. The cause was as you described: core's signed step goes through Your The missing source span in the warning is a separate change; I left it out of this PR. |
|
Thanks, confirmed. Setup: both PR commits cherry-picked cleanly onto
Both range kernels now have the same instruction counts as the counted- Prepared with help from an AI assistant (Claude Code). |
Summary
#[unroll]onfor i in a..bdoes not unroll ("no recognized induction variable"), so arrays indexed byistay in local memory. The loop exits through a match on theOptionfrom the inlinedRange::next. This adds the dialect-mir canonicalization mentioned in #559. No block is copied.#559 asked for a real use. Our GDN kernel had a 192 B local depot from range
forloops over lane arrays. We had to rewrite them as countedwhileloops.Changes
canonicalize.rs:thread_iterator_exit_test. Only for a hinted loop whose header does not exit, so loops that unroll today are unchanged.a..=b,.step_by) still warn and stay loops.evaluate_integer; oneunroll_smokekernel; docs.Testing
ld.local-> none.just checkpasses (5,506 tests)cargo oxide run <example>passes (unroll_smokeon RTX 3090, LLVM and NVVM paths, memcheck and synccheck 0 errors)unroll_smokeChecklist
git commit -s)Written with help from an AI assistant. I ran every test above.