WebAssembly / WebAssembly/binaryen

wasm2asm miscompiles nested i64 ops

Open
#1,480 4 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.