koute / cargo-web

A Cargo subcommand for the client-side Web
Apache License 2.0
1.11k stars 80 forks source link

modules that rotate a u128 fail at load time #193

Open kazcw opened 5 years ago

kazcw commented 5 years ago

src/main.rs:

#[test] fn test() { 1u128.rotate_right(1) }

cargo web test --target=wasm32-unknown-unknown:

   Compiling test-rotate v0.1.0 (/home/kaz/repo/test-rotate)
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
    Processing "test_rotate-11d8ed67e1303d79.wasm"...
    Finished processing of "test_rotate-11d8ed67e1303d79.wasm"!
Error loading Rust wasm module 'test_rotate_11d8ed67e1303d79': <CompileError>
error: unhandled exception thrown
error:     CompileError: AsyncCompilation: (null): Compiling wasm function "_ZN4core3num22_$LT$impl$u20$u128$GT$11rotate_left17h80813d4a39024717E" failed: call[3] expected type i32, found get_local of type i64 @+2112
error: source: http://localhost:33257/:0:0

Other u128 ops besides rotate_left/right are fine.

If I justcargo build --target=wasm32-unknown-unknown (without cargo-web), I get a WASM module that I can import without error.

kazcw commented 5 years ago

I don't see how this could be anything but a rustc codegen / wasm intrinsics bug, but I haven't been able to reproduce it without building with cargo-web.

koute commented 5 years ago

Definitely looks like a codegen bug. A simpler repro:

#![no_std]
#![feature(start)]

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    loop {}
}

#[start]
fn main(_: isize, _: *const *const u8) -> isize {
    1u128.rotate_right(1);
    0
}

This produces the following (in debug mode):

(module
  (type (;0;) (func))
  (type (;1;) (func (param i32 i64 i64 i32)))
  (type (;2;) (func (param i32 i32) (result i32)))
  (import "env" "__web_on_grow" (func $__web_on_grow (type 0)))
  (func $__wasm_call_ctors (type 0))
  (func $_ZN4core3num22_$LT$impl$u20$u128$GT$12rotate_right17h9dd638bf1db6bc5aE (type 1) (param i32 i64 i64 i32)
    (local i32 i32 i32 i64 i64 i64 i64 i64 i64 i32 i32 i64 i64 i32 i32 i64 i64 i64 i32 i32 i32 i32 i64 i32 i32 i32 i64 i64 i64 i64 i32 i32)
    get_global 0
    set_local 4
    i32.const 80
    set_local 5
    get_local 4
    get_local 5
    i32.sub
    set_local 6
    get_local 6
    set_global 0
    get_local 6
    get_local 1
    i64.store offset=40
    get_local 6
    get_local 2
    i64.store offset=48
    get_local 6
    get_local 3
    i32.store offset=60
    get_local 6
    i64.load offset=48
    set_local 7
    get_local 6
    i64.load offset=40
    set_local 8
    get_local 6
    i64.load32_u offset=60
    set_local 9
    i64.const 127
    set_local 10
    get_local 9
    get_local 10
    i64.and
    set_local 11
    i64.const 0
    set_local 12
    i32.const 24
    set_local 13
    get_local 6
    get_local 13
    i32.add
    set_local 14
    get_local 14
    get_local 8
    get_local 7
    get_local 11
    get_local 12
    call $_ZN17compiler_builtins3int5shift13rust_u128_shr17h13bc89a30fced34aE
    get_local 12
    get_local 9
    i64.sub
    set_local 15
    get_local 15
    get_local 10
    i64.and
    set_local 16
    i32.const 8
    set_local 17
    get_local 6
    get_local 17
    i32.add
    set_local 18
    get_local 18
    get_local 8
    get_local 7
    get_local 16
    get_local 12
    call $_ZN17compiler_builtins3int5shift13rust_i128_shl17h15ab07cc5d615a82E
    get_local 6
    i64.load offset=24 align=1
    set_local 19
    get_local 6
    i64.load offset=8 align=1
    set_local 20
    get_local 20
    get_local 19
    i64.or
    set_local 21
    i32.const 8
    set_local 22
    i32.const 24
    set_local 23
    get_local 6
    get_local 23
    i32.add
    set_local 24
    get_local 24
    get_local 22
    i32.add
    set_local 25
    get_local 25
    i64.load align=1
    set_local 26
    i32.const 8
    set_local 27
    get_local 6
    get_local 27
    i32.add
    set_local 28
    get_local 28
    get_local 22
    i32.add
    set_local 29
    get_local 29
    i64.load align=1
    set_local 30
    get_local 30
    get_local 26
    i64.or
    set_local 31
    get_local 6
    get_local 31
    i64.store offset=72
    get_local 6
    get_local 21
    i64.store offset=64
    get_local 6
    i64.load offset=72
    set_local 32
    get_local 6
    i64.load offset=64
    set_local 33
    get_local 0
    get_local 33
    i64.store
    get_local 0
    get_local 32
    i64.store offset=8
    i32.const 80
    set_local 34
    get_local 6
    get_local 34
    i32.add
    set_local 35
    get_local 35
    set_global 0
    return)
  (func $_ZN6foobar4main17h153e5080d7c41a58E (type 2) (param i32 i32) (result i32)
    (local i32 i32 i32 i32 i64 i64 i32 i32 i32 i32 i32)
    get_global 0
    set_local 2
    i32.const 32
    set_local 3
    get_local 2
    get_local 3
    i32.sub
    set_local 4
    get_local 4
    set_global 0
    get_local 4
    get_local 0
    i32.store offset=24
    get_local 4
    get_local 1
    i32.store offset=28
    i32.const 1
    set_local 5
    i64.const 0
    set_local 6
    i64.const 1
    set_local 7
    i32.const 8
    set_local 8
    get_local 4
    get_local 8
    i32.add
    set_local 9
    get_local 9
    get_local 7
    get_local 6
    get_local 5
    call $_ZN4core3num22_$LT$impl$u20$u128$GT$12rotate_right17h9dd638bf1db6bc5aE
    i32.const 0
    set_local 10
    i32.const 32
    set_local 11
    get_local 4
    get_local 11
    i32.add
    set_local 12
    get_local 12
    set_global 0
    get_local 10
    return)
  (func $main (type 2) (param i32 i32) (result i32)
    (local i32 i32)
    i32.const 0
    set_local 2
    get_local 2
    i32.load8_u offset=1048576
    drop
    get_local 0
    get_local 1
    call $_ZN6foobar4main17h153e5080d7c41a58E
    set_local 3
    get_local 3
    return)
  (func $_ZN17compiler_builtins3int5shift13rust_i128_shl17h15ab07cc5d615a82E (type 1) (param i32 i64 i64 i32)
    (local i64)
    block  ;; label = @1
      block  ;; label = @2
        get_local 3
        i32.const 64
        i32.and
        br_if 0 (;@2;)
        get_local 3
        i32.eqz
        br_if 1 (;@1;)
        get_local 1
        i32.const 0
        get_local 3
        i32.sub
        i32.const 63
        i32.and
        i64.extend_u/i32
        i64.shr_u
        get_local 2
        get_local 3
        i32.const 63
        i32.and
        i64.extend_u/i32
        tee_local 4
        i64.shl
        i64.or
        set_local 2
        get_local 1
        get_local 4
        i64.shl
        set_local 1
        br 1 (;@1;)
      end
      get_local 1
      get_local 3
      i32.const 63
      i32.and
      i64.extend_u/i32
      i64.shl
      set_local 2
      i64.const 0
      set_local 1
    end
    get_local 0
    get_local 1
    i64.store
    get_local 0
    get_local 2
    i64.store offset=8)
  (func $_ZN17compiler_builtins3int5shift13rust_u128_shr17h13bc89a30fced34aE (type 1) (param i32 i64 i64 i32)
    (local i64)
    block  ;; label = @1
      block  ;; label = @2
        get_local 3
        i32.const 64
        i32.and
        br_if 0 (;@2;)
        get_local 3
        i32.eqz
        br_if 1 (;@1;)
        get_local 1
        get_local 3
        i32.const 63
        i32.and
        i64.extend_u/i32
        tee_local 4
        i64.shr_u
        get_local 2
        i32.const 0
        get_local 3
        i32.sub
        i32.const 63
        i32.and
        i64.extend_u/i32
        i64.shl
        i64.or
        set_local 1
        get_local 2
        get_local 4
        i64.shr_u
        set_local 2
        br 1 (;@1;)
      end
      get_local 2
      get_local 3
      i32.const 63
      i32.and
      i64.extend_u/i32
      i64.shr_u
      set_local 1
      i64.const 0
      set_local 2
    end
    get_local 0
    get_local 1
    i64.store
    get_local 0
    get_local 2
    i64.store offset=8)
  (table (;0;) 1 1 anyfunc)
  (memory (;0;) 17)
  (global (;0;) (mut i32) (i32.const 1048576))
  (global (;1;) i32 (i32.const 1048610))
  (global (;2;) i32 (i32.const 1048610))
  (global (;3;) i32 (i32.const 1048576))
  (export "main" (func $main))
  (export "__indirect_function_table" (table 0))
  (export "memory" (memory 0))
  (export "__heap_base" (global 1))
  (export "__data_end" (global 2))
  (export "__rustc_debug_gdb_scripts_section__" (global 3))
  (data (i32.const 1048576) "\01gdb_load_rust_pretty_printers.py\00"))

and fails validation:

target/wasm32-unknown-unknown/debug/foobar.wasm:000015f: error: type mismatch in call, expected [i32, i64, i64, i32] but got [... i64, i64, i64, i64]
target/wasm32-unknown-unknown/debug/foobar.wasm:0000184: error: type mismatch in call, expected [i32, i64, i64, i32] but got [... i64, i64, i64, i64]

It reproduces easily without cargo-web. Just compile it once to have cargo-web generate the .js file for you, then grab it, delete target, recompile with cargo build --target=wasm32-unknown-unknown and launch it throgh Node.js using the .js file you've saved.

kazcw commented 5 years ago

Great. Kicking this further up the toolchain: rust-lang/rust#61521

kazcw commented 5 years ago

FYI, upstream issue has been rejected as @alexcrichton doesn't think it looks like a Rust or LLVM bug. All I know is it's not my bug; I no longer rotate u128s in portable crates.