WebAssembly / WebAssembly/binaryen
wasm2asm miscompiles nested i64 ops
Nobody has claimed this yet.
- Dominant language
- WebAssembly
- Stars
- 8.6k
- Forks
- 885
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 69
Description
Compiling a function like:
(func $shl_i64 (param $0 i64) (param $1 i64) (result i64)
(i64.or (i64.shl (get_local $0) (get_local $1))
(i64.shl (get_local $0) (get_local $1))))
results in:
function shl_i64($0, $0$hi, $1, $1$hi) {
$0 = $0 | 0;
$0$hi = $0$hi | 0;
$1 = $1 | 0;
$1$hi = $1$hi | 0;
var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$5 = 0, $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $20 = 0, $21 = 0, $22 = 0, $23 = 0, $24 = 0, $25 = 0, $26 = 0, $27 = 0, $28 = 0, $29 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, $49 = 0, $50 = 0, $51 = 0, $52 = 0, $53 = 0, $54 = 0, $55 = 0, $56 = 0, $57 = 0, $58 = 0, $59 = 0, $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0, $65 = 0, $66 = 0, $67 = 0, $68 = 0, $69 = 0, $70 = 0, $71 = 0, $72 = 0, $73 = 0, $74 = 0, $75 = 0, $76 = 0, $77 = 0, $78 = 0, $79 = 0, $80 = 0, $81 = 0, $82 = 0, $83 = 0, $84 = 0, $85 = 0, $86 = 0, $87 = 0, $88 = 0, $89 = 0, $90 = 0, $91 = 0, $92 = 0, $93 = 0, $94 = 0, $95 = 0, $96 = 0, $97 = 0, $98 = 0, $99 = 0;
i64toi32_i32$0 = $0$hi;
i64toi32_i32$2 = $0;
i64toi32_i32$1 = $1$hi;
i64toi32_i32$3 = $1;
i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
$45 = 0;
} else {
i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
$45 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
}
// XXX
i64toi32_i32$3 = $45;
i64toi32_i32$2 = $0$hi;
i64toi32_i32$3 = $0;
i64toi32_i32$0 = $1$hi;
i64toi32_i32$4 = $1;
i64toi32_i32$5 = i64toi32_i32$4 & 31 | 0;
if (32 >>> 0 <= (i64toi32_i32$4 & 63 | 0) >>> 0) {
i64toi32_i32$0 = i64toi32_i32$3 << i64toi32_i32$5 | 0;
$84 = 0;
} else {
i64toi32_i32$0 = ((1 << i64toi32_i32$5 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$5 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$5 | 0) | 0;
$84 = i64toi32_i32$3 << i64toi32_i32$5 | 0;
}
i64toi32_i32$2 = $84;
i64toi32_i32$0 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$2 | 0;
i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
return i64toi32_i32$3 | 0;
}
Notice that at XXX, we're assigning the low part of one shift to i64toi32_i32$3 and then, two lines down, overwriting i64toi32_i32$3 with the high bits of one of the input arguments.
Not sure whether this is specific to bitwise operations or a more general issue.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling the provided nested i64 WAST function with wasm2asm and inspect the generated JavaScript around the marked XXX. Compare the intermediate values for both shifts and verify that the generated result no longer overwrites a needed value; reproduce the case with a regression test if the existing test location can be identified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- wasm
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100