New user self-registration is disabled due to spam. For an account please email bugs-admin@lists.llvm.org with your e-mail address and full name.

Bug 40805 - [WebAssembly] codegen bug during instruction selection
Summary: [WebAssembly] codegen bug during instruction selection
Status: RESOLVED FIXED
Alias: None
Product: libraries
Classification: Unclassified
Component: Backend: WebAssembly (show other bugs)
Version: 8.0
Hardware: PC All
: P enhancement
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-02-21 08:43 PST by Alex Crichton
Modified: 2019-02-24 11:06 PST (History)
4 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Crichton 2019-02-21 08:43:46 PST
First reported upstream to rust-lang/rust - https://github.com/rust-lang/rust/issues/58548 - I've managed to reduce this a little more from the Rust issue report. It looks like during "WebAssembly Instruction Selection" on the `run_test` function a bug is generated. 

All the relevant files for this should be in https://gist.github.com/alexcrichton/f0098f0505ce1476a2bef944b03ff06e, notably:

* lib.rs - https://gist.github.com/alexcrichton/f0098f0505ce1476a2bef944b03ff06e#file-lib-rs - the original Rust source used to generate this buggy program
* foo.ll - https://gist.github.com/alexcrichton/f0098f0505ce1476a2bef944b03ff06e#file-foo-ll - the LLVM IR generated by rustc with LTO (to avoid references to the Rust standard library). 
* foo.js - https://gist.github.com/alexcrichton/f0098f0505ce1476a2bef944b03ff06e#file-foo-js - auxiliary JS for node.js to run the output wasm binary
* build.sh - https://gist.github.com/alexcrichton/f0098f0505ce1476a2bef944b03ff06e#file-build-sh - the invocations of `llc` and `wasm-ld` used to produce a WebAssembly binary.

Using `-opt-bisect-limit` I've found that the pass "WebAssembly Instruction Selection on function (run_test)" looks to be causing the issue here (different behavior in optimized vs non-optimized mode). This pass changes the final output wasm with this diff:

https://gist.github.com/alexcrichton/5603d6a0e59d638e9ac74751d51f4cad

but I unfortunately can't really make heads or tails of where the bug is. 

If any more info is needed from our end please just let me know!
Comment 1 Nikita Popov 2019-02-23 02:17:08 PST
Reduced reproduce case:

define i32 @test(i32 %a) nounwind {
  %b = and i32 %a, 1
  %c = icmp ne i32 %b, 0
  %d = select i1 %c, i32 23, i32 0
  ret i32 %d
}

Pre-selection SDAG:

    t0: ch = EntryToken
        t2: i32 = WebAssemblyISD::ARGUMENT TargetConstant:i32<0>
      t4: i32 = and t2, Constant:i32<1>
    t9: i32 = select t4, Constant:i32<23>, Constant:i32<0>
  t10: ch = WebAssemblyISD::RETURN t0, t9

Post-selection SDAG:

      t8: i32 = CONST_I32 TargetConstant:i32<23>
      t5: i32 = CONST_I32 TargetConstant:i32<0>
      t2: i32 = ARGUMENT_i32 TargetConstant:i32<0>
    t9: i32 = SELECT_I32 t8, t5, t2
    t0: ch = EntryToken
  t10: ch = RETURN_I32 t9, t0

We can see that the "and" node has been lost. This is due to these two patterns in WebAssemblyInstrInteger.td:

// The legalizer inserts an unnecessary `and 1` to make input conform
// to getBooleanContents, which we can lower away.
def : Pat<(select (i32 (and I32:$cond, 1)), I32:$lhs, I32:$rhs),
          (SELECT_I32 I32:$lhs, I32:$rhs, I32:$cond)>;
def : Pat<(select (i32 (and I32:$cond, 1)), I64:$lhs, I64:$rhs),
          (SELECT_I64 I64:$lhs, I64:$rhs, I32:$cond)>;

That comment isn't right :)
Comment 2 Nikita Popov 2019-02-23 02:47:38 PST
https://reviews.llvm.org/D58575
Comment 3 Alex Crichton 2019-02-23 12:23:32 PST
Thanks for the quick fix Nikita!
Comment 4 Dan Gohman 2019-02-24 11:06:51 PST
FYI, I filed https://bugs.llvm.org/show_bug.cgi?id=40847 to request merging this fix to the 8.0 branch.