Skip to content

wasm-ld: Disabling on-by-default features doesn't work when LTO is used #109443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
alexcrichton opened this issue Sep 20, 2024 · 12 comments
Open
Labels
lld:wasm LTO Link time optimization (regular/full LTO or ThinLTO)

Comments

@alexcrichton
Copy link
Contributor

Given this input:

target triple = "wasm32-unknown-unknown"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"

define void @foo(ptr %a) #0 {
  call void %a()
  ret void
}

attributes #0 = { "target-cpu"="mvp" }

Locally I see:

$ llvm-as wat.ll
$ wasm-ld wat.bc -o foo.wasm --no-entry --export foo 
$ wasm-tools validate -f=-reference-types foo.wasm
error: func 0 failed to validate

Caused by:
    0: zero byte expected (at offset 0x4b)

This issue is a reduction of rust-lang/rust#130604 and is where a user is trying to disable reference types for their entire compilation and use LTO as well, but it looks like the "target-cpu" isn't taking effect with wasm-ld.

cc @sbc100 do you know what might be causing this?

@sbc100
Copy link
Collaborator

sbc100 commented Sep 20, 2024

That does seem wrong. Just to confirm, if you compile to and object file (not a .bc file) this doesn't fail?

@alexcrichton
Copy link
Contributor Author

Right yeah, this works ok:

$ llc wat.ll -filetype=obj -o foo.o -mcpu=mvp
$ wasm-ld foo.o -o foo.wasm --no-entry --export foo
$ wasm-tools validate -f=-reference-types foo.wasm

Interestingly the -mcpu=mvp is required though. If I remove that flag then it additionally doesn't work. I forget all the ways that the CPU and such can be configured in LLVM, but I believe that passing -mcpu=mvp mirrors what the Rust compiler does at least. (I'm mostly not sure how the CLI flag -mcpu=mvp interacts with the "target-cpu"="mvp" attribute on functions)

@EugeneZelenko EugeneZelenko added lld:wasm LTO Link time optimization (regular/full LTO or ThinLTO) and removed new issue labels Sep 20, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 20, 2024

@llvm/issue-subscribers-lld-wasm

Author: Alex Crichton (alexcrichton)

Given this input:
target triple = "wasm32-unknown-unknown"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"

define void @<!-- -->foo(ptr %a) #<!-- -->0 {
  call void %a()
  ret void
}

attributes #<!-- -->0 = { "target-cpu"="mvp" }

Locally I see:

$ llvm-as wat.ll
$ wasm-ld wat.bc -o foo.wasm --no-entry --export foo 
$ wasm-tools validate -f=-reference-types foo.wasm
error: func 0 failed to validate

Caused by:
    0: zero byte expected (at offset 0x4b)

This issue is a reduction of rust-lang/rust#130604 and is where a user is trying to disable reference types for their entire compilation and use LTO as well, but it looks like the "target-cpu" isn't taking effect with wasm-ld.

cc @sbc100 do you know what might be causing this?

@StackOverflowExcept1on
Copy link

@sbc100 Any updates on this bug?

@sbc100
Copy link
Collaborator

sbc100 commented Mar 5, 2025

I cannot reproduce this anymore:

$ wasm-tools validate -f=-reference-types foo.wasm
$ wasm-tools validate -f=-reference-types foo_lto.wasm

Also, the two binaries produced via LTO and non-LTO are identical for me:

$ wasm-ld --strip-all foo.o -o foo.wasm --no-entry --export foo
$ wasm-ld --strip-all wat.bc -o foo_lto.wasm --no-entry --export foo
$ diff foo.wasm foo_lto.wasm

Can either of you still reproduce this?

@StackOverflowExcept1on
Copy link

StackOverflowExcept1on commented Mar 5, 2025

@sbc100 With LLVM 20? As far as I know Rust has recently updated to LLVM 20.

@sbc100
Copy link
Collaborator

sbc100 commented Mar 5, 2025

I only tested on tip-of-tree. I don't have LLVM 20 handy to test I'm afraid.

@StackOverflowExcept1on
Copy link

I can confirm that this problem is solved at least in nightly Rust

@alexcrichton
Copy link
Contributor Author

Nice! Seems like this may have been fixed in the 19->20 interim, so closing.

@StackOverflowExcept1on
Copy link

@alexcrichton @sbc100 I tried building more complex wasm and now it has memory.fill (bulk memory operations), although my target is wasm32v1-none:

  error: File path: "/gear/target/wasm32-gear/release/demo_ping.wasm"
  |      Unsupported instruction: MemoryFill { mem: 0 }

@alexcrichton
Copy link
Contributor Author

There's a lot of possible reasons for where that might be coming from, so perhaps it's best to continue the discussion elsewhere given that this specific issue seems to have been fixed? Maybe on your project's issue tracker or similar?

@StackOverflowExcept1on
Copy link

StackOverflowExcept1on commented Apr 23, 2025

@sbc100 Can we reopen this? I'm seeing similar problem again, but so far I have not been able to minimize it. I wrote the steps to reproduce here: rust-lang/rust#140174 (comment).

wasm_program.ll

wget https://gist.githubusercontent.com/StackOverflowExcept1on/a522b4f410da3ed5cd4217aa10715802/raw/0b7aacd8ea92dad23a37cc2035447f55b8c73d28/wasm_program.ll

llvm-as wasm_program.ll
wasm-ld wasm_program.bc -o wasm_program.wasm --no-entry --import-undefined --export init
wasm-tools print wasm_program.wasm
(module $wasm_program.wasm
  (type (;0;) (func (param i32)))
  (type (;1;) (func))
  (import "env" "gr_size" (func $gr_size (;0;) (type 0)))
  (memory (;0;) 2)
  (global $__stack_pointer (;0;) (mut i32) i32.const 66576)
  (export "memory" (memory 0))
  (export "init" (func $init))
  (func $init (;1;) (type 1)
    (local i32 i32)
    global.get $__stack_pointer
    i32.const 16
    i32.sub
    local.tee 0
    global.set $__stack_pointer
    local.get 0
    i32.const 0
    i32.store offset=12
    local.get 0
    i32.const 12
    i32.add
    call $gr_size
    block ;; label = @1
      block ;; label = @2
        local.get 0
        i32.load offset=12
        local.tee 1
        i32.const -1
        i32.le_s
        br_if 0 (;@2;)
        local.get 1
        br_if 1 (;@1;)
        local.get 0
        i32.const 16
        i32.add
        global.set $__stack_pointer
        return
      end
      call $alloc::raw_vec::capacity_overflow::hbcdda363c397d873
      unreachable
    end
    i32.const 0
    i32.load8_u offset=1024
    drop
    call $alloc::alloc::handle_alloc_error::h375d584c5a428f70
    unreachable
  )
  (func $alloc::raw_vec::capacity_overflow::hbcdda363c397d873 (;2;) (type 1)
    call $core::panicking::panic_nounwind_fmt::h965b19ef84cb4c59
    unreachable
  )
  (func $alloc::alloc::handle_alloc_error::h375d584c5a428f70 (;3;) (type 1)
    call $__rustc::__rust_alloc_error_handler
    unreachable
  )
  (func $core::panicking::panic_nounwind_fmt::h965b19ef84cb4c59 (;4;) (type 1)
    loop ;; label = @1
      br 0 (;@1;)
    end
  )
  (func $__rustc::__rust_alloc_error_handler (;5;) (type 1)
    call $__rustc::__rdl_oom
    unreachable
  )
  (func $__rustc::__rdl_oom (;6;) (type 1)
    call $core::panicking::panic_nounwind_fmt::h965b19ef84cb4c59
    unreachable
  )
  (@custom ".debug_abbrev" (after code) "\01\11\01%\0e\13\05\03\0e\10\17\1b\0e\11\01U\17\00\00\029\01\03\0e\00\00\03.\00\11\01\12\06@\18n\0e\03\0e:\0b;\0b6\0b\87\01\19\00\00\04.\00n\0e\03\0e:\0b;\05\87\01\19 \0b\00\00\05.\01\11\01\12\06@\18n\0e\03\0e:\0b;\056\0b?\19\87\01\19\00\00\06\1d\001\13\11\01\12\06X\0bY\05W\0b\00\00\07.\00\11\01\12\06@\18n\0e\03\0e:\0b;\056\0b?\19\87\01\19\00\00\08\11\01%\0e\13\05\03\0e\10\17\1b\0e\11\01\12\06\00\00\09.\01\11\01\12\06@\18n\0e\03\0e:\0b;\0b6\0b?\19\87\01\19\00\00\00")
  (@custom ".debug_info" (after code) "\b6\00\00\00\04\00\00\00\00\00\04\01q\02\00\00\1c\009\02\00\00\00\00\00\00\d3\01\00\00\00\00\00\00\00\00\00\00\02\95\00\00\00\02\9b\00\00\00\03d\00\00\00\09\00\00\00\07\ed\03\00\00\00\00\9fb\01\00\00\00\00\00\00\01\1c\03\00\02\95\00\00\00\02.\00\00\00\04\a3\00\00\00%\00\00\00\02\93\01\01\00\05n\00\00\00\09\00\00\00\07\ed\03\00\00\00\00\9f\9b\01\00\00.\00\00\00\02\8d\01\03\06W\00\00\00n\00\00\00\09\00\00\00\02\9b\01\09\00\02A\00\00\00\07\8a\00\00\00\09\00\00\00\07\ed\03\00\00\00\00\9fW\00\00\00t\00\00\00\02\aa\01\03\00\00\00\00p\00\00\00\04\00\00\00\00\00\04\08q\02\00\00\1c\00\03\02\00\00\9c\00\00\00\d3\01\00\00x\00\00\00\07\00\00\00\02\88\00\00\00\02~\00\00\00\02\12\00\00\00\04\e4\00\00\00\8d\00\00\00\02o\0c\01\00\09x\00\00\00\07\00\00\00\07\ed\03\00\00\00\00\9f'\01\00\00\12\00\00\00\01Z\03\065\00\00\00x\00\00\00\05\00\00\00\02{\0c\09\00\00\00\00")
  (@custom ".debug_ranges" (after code) "d\00\00\00m\00\00\00n\00\00\00w\00\00\00\8a\00\00\00\93\00\00\00\00\00\00\00\00\00\00\00")
  (@custom ".debug_str" (after code) "capacity_overflow\00panic_nounwind_fmt\00rt_error\00handle_alloc_error\00__alloc_error_handler\00_RNvCskUo7FPs0YsV_7___rustc9___rdl_oom\00panicking\00core\00runtime\00alloc\00raw_vec\00_ZN5alloc5alloc18handle_alloc_error8rt_error17h19ce4111641a582fE\00_ZN4core9panicking18panic_nounwind_fmt7runtime17h97a29e16993dee0cE\00_ZN4core9panicking18panic_nounwind_fmt17h965b19ef84cb4c59E\00_ZN5alloc7raw_vec17capacity_overflow17hbcdda363c397d873E\00_ZN5alloc5alloc18handle_alloc_error17h375d584c5a428f70E\00/rustc/d6c1e454aa8af5e7e59fbf5c4e7d3128d2f99582\00library/core/src/lib.rs/@/core.9343ef24dc9046c6-cgu.0\00library/alloc/src/lib.rs/@/alloc.44ef90a7bbe2c7b4-cgu.0\00clang LLVM (rustc version 1.88.0-nightly (d6c1e454a 2025-04-21))\00")
  (@custom ".debug_line" (after code) "\98\00\00\00\04\00V\00\00\00\01\01\01\fb\0e\0d\00\01\01\01\01\00\00\00\01\00\00\01library/alloc/src/raw_vec\00library/alloc/src\00\00mod.rs\00\01\00\00alloc.rs\00\02\00\00\00\05\05\0a\00\05\02e\00\00\00\03\1c\01\02\08\00\01\01\04\02\05\0d\0a\00\05\02o\00\00\00\03\94\03\01\02\08\00\01\01\04\02\05\0d\0a\00\05\02\8b\00\00\00\03\b4\03\01\02\08\00\01\01y\00\00\00\04\00[\00\00\00\01\01\01\fb\0e\0d\00\01\01\01\01\00\00\00\01\00\00\01library/core/src\00library/core/src/intrinsics\00\00panicking.rs\00\01\00\00mod.rs\00\02\00\00\00\05\16\0a\00\05\02y\00\00\00\03\f4\00\01\06\03\8b\7fJ\02\02\00\01\01")
  (@producers
    (language "Rust" "")
    (processed-by "rustc" "1.88.0-nightly (d6c1e454a 2025-04-21)")
  )
  (@custom "target_features" (after code) "\08+\0bbulk-memory+\0fbulk-memory-opt+\16call-indirect-overlong+\0amultivalue+\0fmutable-globals+\13nontrapping-fptoint+\0freference-types+\08sign-ext")
)

target_features contains many features that should not appear in wasm32v1-none (mvp + mutable-globals)

@sbc100 sbc100 reopened this Apr 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lld:wasm LTO Link time optimization (regular/full LTO or ThinLTO)
Projects
None yet
Development

No branches or pull requests

5 participants