[llvm] [WebAssembly] Implement lowering calls through funcref to call_ref when available (PR #162227)

Demetrius Kanios via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 13:10:02 PDT 2026


QuantumSegfault wrote:

> I mean, other than it needing rebasing, I guess there's no real reason to block this at all.
> 
> If the existing thing I was trying to compare against doesn't work, than this is a solid improvement. I'll rebase and do a simple test to make sure it still works as intended.

Without #166820 I don't think it's possible to do this from C yet (func ptr => funcref for testing). But with IR:
```ll
target triple = "wasm32-unknown-unknown"

@__indirect_function_table = external addrspace(1) global [0 x ptr addrspace(20)]

declare ptr addrspace(20) @llvm.wasm.table.get.funcref(ptr addrspace(1), i32) nounwind

define hidden i32 @call_callback(ptr addrspace(20) %callback) {
entry:
  %call = call addrspace(20) i32 %callback(i32 32)
  ret i32 %call
}

define hidden i32 @times_two(i32 %x) {
entry:
  %mul = mul nsw i32 %x, 2
  ret i32 %mul
}

define i32 @test() {
entry:
  %funcref = call ptr addrspace(20) @llvm.wasm.table.get.funcref(ptr addrspace(1) @__indirect_function_table, i32 ptrtoint (ptr @times_two to i32))
  %call = call i32 @call_callback(ptr addrspace(20) %funcref)
  ret i32 %call
}
```

```
$ wasm-ld --export=test --no-entry -o test.wasm <(bin/llc -filetype=obj -mattr=+reference-types,+gc -o - test.ll)
$ wasm-tools print test.wasm
(module $test.wasm
  (type (;0;) (func (param i32) (result i32)))
  (type (;1;) (func (param funcref) (result i32)))
  (type (;2;) (func (result i32)))
  (table (;0;) 2 2 funcref)
  (memory (;0;) 1)
  (export "memory" (memory 0))
  (export "test" (func $test))
  (elem (;0;) (i32.const 1) func $times_two)
  (func $call_callback (;0;) (type 1) (param funcref) (result i32)
    i32.const 32
    local.get 0
    ref.cast (ref 0)
    call_ref 0
  )
  (func $times_two (;1;) (type 0) (param i32) (result i32)
    local.get 0
    i32.const 1
    i32.shl
  )
  (func $test (;2;) (type 2) (result i32)
    i32.const 1
    table.get 0
    call $call_callback
  )
  (@custom "target_features" (after code) "\09+\0bbulk-memory+\0fbulk-memory-opt+\16call-indirect-overlong+\02gc+\0amultivalue+\0fmutable-globals+\13nontrapping-fptoint+\0freference-types+\08sign-ext")
)
$ wasmtime run -W gc,function-references --invoke test test.wasm 32
64
```

It works, performance considerations aside.

https://github.com/llvm/llvm-project/pull/162227


More information about the llvm-commits mailing list