Description
Found by adversarial review while verifying the WebAssembly backend (feature/webasm-backend), which matches plain JS on all three where cpu does not. All three are pre-existing on develop and unrelated to that branch.
1. Early return inside a loop returns the post-loop value for every cell.
gpu.createKernel(function () {
for (let i = 0; i < 20; i++) {
if (i * i > this.thread.x) { return i * 100 + this.thread.x; }
}
return -1;
}, { output: [6] });
// cpu: [-1, -1, -1, -1, -1, -1]
// plain JS: [100, 201, 202, 203, 304, 305] (webasm agrees)The translated loop keeps running after the return.
2. Do-while with continue does not jump to the test correctly — a do/while accumulating with if (i % 3 === 0) continue; returns 56 on cpu where plain JS gives 45.
3. Assignment to a scalar argument leaks across cells — base = base + this.thread.x; return base; with base = 10 returns [10, 11, 13, 16, ...] on cpu (the mutation accumulates across the cell loop) where per-cell JS, the GL backends and webasm give [10, 11, 12, 13].
The webasm suite pins these shapes against per-cell plain-JS references (test/features/webasm/control-flow.js) precisely because the cpu backend cannot serve as ground truth for them. Fixing cpu should add the same three shapes to a cpu regression file.
Activity
fuzzie360 commentedon Aug 2, 2026
Fixed on
feature/webasm-backend(PR #866) in 11b4c0e — the PR that discovered these now also fixes them, since its webasm suite supplied ready-made plain-JS-referenced fixtures.All three mechanisms as diagnosed: the early-return
continuetargeting the user's loop (now akernelBody:labeled block withbreak kernelBody;from any depth), the for-wrapped do-while skipping its trailing test oncontinue(now a native do-while with the loopMaxIterations cap riding in the condition), and run-wide argument bindings (now per-celluser_X$cellshadows routed through both the identifier and member-expression emitters, so reassigned array arguments read correctly too).test/issues/865-cpu-control-flow.jspins the shapes against plain-JS references across backends; 5 of 10 runnable assertions fail with the fix reverted. Suites: Node 2697/0, browser 4071/0, SwiftShader baseline identical.One discovery from the cross-backend rows: the GL backends fail the do-while and assigned-argument shapes by their own mechanisms (skipped trailing test in the do-while emulation;
can't modify a uniform) — filed as #867, with the scoped test rows as its acceptance test.fix(cpu): three control-flow shapes now match plain JavaScript (#865)
fix: the twelve findings of the webasm adversarial review