wasm loop unroller: correctly handle dependences through memory
Categories
(Core :: JavaScript: WebAssembly, defect, P1)
Tracking
()
Tracking | Status | |
---|---|---|
firefox142 | --- | fixed |
People
(Reporter: yury, Assigned: jseward)
References
()
Details
Attachments
(6 files)
After fixing bug 1966549 I noticed that few seconds in the game, the program hangs but allows the script to stop. In the debugger, the following machine code can be observed, which is compiled wasm code:
...
0x115bab6ea728: fcmp s4, s0
0x115bab6ea72c: b.ge 0x115bab6ea75c
0x115bab6ea730: ldr s0, 0x115bab6ea9c0
0x115bab6ea734: fsub s0, s3, s0
0x115bab6ea738: str s0, [x0, #0x1c0]
0x115bab6ea73c: nop
0x115bab6ea740: str s0, [x0, #0x1c0]
0x115bab6ea744: str s0, [x0, #0x1c0]
0x115bab6ea748: ldr x1, [x28, #0xc0]
0x115bab6ea74c: ldr w16, [x1, #0x40]
0x115bab6ea750: cbnz w16, 0x115bab6f4c50
0x115bab6ea754: str s0, [x0, #0x1c0]
-> 0x115bab6ea758: b 0x115bab6ea740
0x115bab6ea75c: ldr s0, [x0, #0x1c0]
0x115bab6ea760: fsub s2, s2, s0
....
Notice that the code/loop at 0x115bab6ea740 - 0x115bab6ea758 is doing nothing useful. Disabling javascript.options.wasm_unroll_loops fixes the issue.
Reporter | ||
Comment 1•2 months ago
|
||
Assignee | ||
Updated•2 months ago
|
Assignee | ||
Comment 2•2 months ago
|
||
The loop in question looks OK immediately after unrolling. But after the
post-unroll cleanup (GVN + dead block removal), all the side exits have
disappeared, causing it to be an infinite loop. Also almost all of the other
contents of the original loop have been removed. See attached log.
Assignee | ||
Comment 3•2 months ago
•
|
||
Immediately after unrolling, each copy of the original loop body has its own
copy of the struct.get, and the associated f32.lt, f32.add and struct.set that
that feeds. After the post-unroll cleanup, everything except the struct.set
disappears in the unrolled iterations; the struct.get, f32.lt and f32.add
appear appear only in the peeled iteration.
This would be consistent with the struct.gets in the unrolled iterations having
been GVNd out on the basis that they are duplicates of the one in the peeled
iteration -- which they are not, because the struct.set invalidates the old
value each time round the loop.
Assignee | ||
Comment 4•2 months ago
|
||
This one is also runnable. On baseline it prints 4444200, which is correct;
for Ion it prints 360, which definitely isn't.
Assignee | ||
Updated•2 months ago
|
Assignee | ||
Comment 5•2 months ago
|
||
When combined with the test case in comment 4, this would probably
be a complete fix.
Assignee | ||
Comment 6•2 months ago
|
||
When duplicating MIR nodes in the original loop body, the load dependency field
was not being updated.
It is necessary for the load dependency field of a duplicated node to be
updated to point at the corresponding duplicated store node in the same
iteration-copy.
The result was that the load dependency fields ended up still pointing at the
store node in the original loop, which eventually becomes the peeled iteration,
outside the loop. Post-unrolling GVN could then common up all the loads and
replace them with the value loaded in the peeled iteration, so that the loaded
value was, incorrectly, the value stored by the first iteration of the
(original) loop.
This patch fixes it in a straightforward way, and adds a regression test.
Updated•1 months ago
|
Updated•1 months ago
|
Comment 8•1 month ago
|
||
bugherder |
Updated•15 days ago
|
Description
•