Skip to content

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

Open
@alexcrichton

Description

@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?

Activity

sbc100

sbc100 commented on Sep 20, 2024

@sbc100
Collaborator

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

alexcrichton

alexcrichton commented on Sep 20, 2024

@alexcrichton
ContributorAuthor

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)

added
LTOLink time optimization (regular/full LTO or ThinLTO)
and removed on Sep 20, 2024
llvmbot

llvmbot commented on Sep 20, 2024

@llvmbot
Member

@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

StackOverflowExcept1on commented on Mar 5, 2025

@StackOverflowExcept1on

@sbc100 Any updates on this bug?

sbc100

sbc100 commented on Mar 5, 2025

@sbc100
Collaborator

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

StackOverflowExcept1on commented on Mar 5, 2025

@StackOverflowExcept1on

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

sbc100

sbc100 commented on Mar 5, 2025

@sbc100
Collaborator

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

StackOverflowExcept1on

StackOverflowExcept1on commented on Mar 5, 2025

@StackOverflowExcept1on

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

alexcrichton

alexcrichton commented on Mar 5, 2025

@alexcrichton
ContributorAuthor

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

StackOverflowExcept1on

StackOverflowExcept1on commented on Mar 5, 2025

@StackOverflowExcept1on

@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

alexcrichton commented on Mar 5, 2025

@alexcrichton
ContributorAuthor

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

StackOverflowExcept1on commented on Apr 23, 2025

@StackOverflowExcept1on

@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)

reopened this on Apr 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    LTOLink time optimization (regular/full LTO or ThinLTO)lld:wasm

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @alexcrichton@sbc100@EugeneZelenko@llvmbot@StackOverflowExcept1on

        Issue actions

          wasm-ld: Disabling on-by-default features doesn't work when LTO is used · Issue #109443 · llvm/llvm-project