[Bug] [Miscompilation] [WebAssembly] `select` on `externref`s uses untyped opcode and cannot lower from wasm_var address space
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
**clang version:** 22.1.6
**OS**: `Linux archlinux 7.0.12-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 10 Jun 2026 08:58:02 +0000 x86_64 GNU/Linux`
# Case 1: Local `externref`s
```llvm
target triple = "wasm32-freestanding"
%externref = type ptr addrspace(10)
define %externref @select(i32 %a, %externref %t, %externref %f) #0 {
%cmp = icmp ne i32 %a, 0
%res = select i1 %cmp, %externref %t, %externref %f
ret %externref %res
}
attributes #0 = { "wasm-export-name"="select" }
```
## ``clang test.ll -mcpu=bleeding-edge --target=wasm32-freestanding -c``:
```wasm
000054 func[0] :
000055: 20 01 | local.get 1
000057: 20 02 | local.get 2
000059: 20 00 | local.get 0
00005b: 1b | select
00005c: 0f | return
00005d: 0b | end
```
Note that `select` here is untyped (opcode `0x1b`), which is incorrect. For `externref`, it **must** use **typed select** (opcode `0x1c`).
**[MDN](https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Control_flow/select)**: `The instruction may be followed by an immediate value type: select (result T). select (result T) uses a different binary opcode, and allows types besides those introduced by the WebAssembly MVP (i32, i64, f32, f64), for example, it allows selection between two externref values.`
## With `-O2` added:
```
fatal error: error in backend: Cannot select: 0x564cb7dfa220: externref = select_cc 0x564cb7df9dc0, Constant:i32<0>, 0x564cb7df9f80, 0x564cb7df9ea0, seteq:ch
0x564cb7df9dc0: i32 = WebAssemblyISD::ARGUMENT TargetConstant:i32<0>
0x564cb7df9f80: externref = WebAssemblyISD::ARGUMENT TargetConstant:i32<2>
0x564cb7df9ea0: externref = WebAssemblyISD::ARGUMENT TargetConstant:i32<1>
In function: select
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0. Program arguments: clang test.ll -mcpu=bleeding-edge --target=wasm32-freestanding -c -O2
1. Code generation
2. Running pass 'Function Pass Manager' on module 'test.ll'.
3. Running pass 'WebAssembly Instruction Selection' on function '@select'
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 libLLVM.so.22.1 0x00007fa0fbb98a97 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 71
1 libLLVM.so.22.1 0x00007fa0fbb96427 llvm::sys::CleanupOnSignal(unsigned long) + 263
2 libLLVM.so.22.1 0x00007fa0fba47704 llvm::CrashRecoveryContext::HandleExit(int) + 84
3 libLLVM.so.22.1 0x00007fa0fbb8ed86 llvm::sys::Process::Exit(int, bool) + 38
4 clang 0x0000564cb63ffb1b
5 libLLVM.so.22.1 0x00007fa0fba6bad0 llvm::report_fatal_error(llvm::Twine const&, bool) + 128
6 libLLVM.so.22.1 0x00007fa0fc99c0e8 llvm::SelectionDAGISel::CannotYetSelect(llvm::SDNode*) + 440
7 libLLVM.so.22.1 0x00007fa0fc99e4fb llvm::SelectionDAGISel::SelectCodeCommon(llvm::SDNode*, unsigned char const*, unsigned int) + 8891
8 libLLVM.so.22.1 0x00007fa100aa2a08
9 libLLVM.so.22.1 0x00007fa0fc996b29 llvm::SelectionDAGISel::DoInstructionSelection() + 489
10 libLLVM.so.22.1 0x00007fa0fc9a430c llvm::SelectionDAGISel::CodeGenAndEmitDAG() + 668
11 libLLVM.so.22.1 0x00007fa0fc9a6fa9 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) + 5097
12 libLLVM.so.22.1 0x00007fa0fc9a9179 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 249
13 libLLVM.so.22.1 0x00007fa0fc9966db llvm::SelectionDAGISelLegacy::runOnMachineFunction(llvm::MachineFunction&) + 459
14 libLLVM.so.22.1 0x00007fa0fc1ff049 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 473
15 libLLVM.so.22.1 0x00007fa0fbd8b98b llvm::FPPassManager::runOnFunction(llvm::Function&) + 1547
16 libLLVM.so.22.1 0x00007fa0fbd8d795 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 1429
17 libclang-cpp.so.22.1 0x00007fa1079f62fb
18 libclang-cpp.so.22.1 0x00007fa1079f6796 clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr, std::unique_ptr>, clang::BackendConsumer*) + 1014
19 libclang-cpp.so.22.1 0x00007fa107e13f21 clang::CodeGenAction::ExecuteAction() + 3297
20 libclang-cpp.so.22.1 0x00007fa1088f8aeb clang::FrontendAction::Execute() + 59
21 libclang-cpp.so.22.1 0x00007fa108869ef1 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 625
22 libclang-cpp.so.22.1 0x00007fa1089ca581 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 737
23 clang 0x0000564cb6402b64 cc1_main(llvm::ArrayRef, char const*, void*) + 8980
24 clang 0x0000564cb63f909a
25 clang 0x0000564cb63f9244
26 libclang-cpp.so.22.1 0x00007fa1083e9ea5
27 libLLVM.so.22.1 0x00007fa0fba475f8 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref) + 40
28 libclang-cpp.so.22.1 0x00007fa1083ea917
29 libclang-cpp.so.22.1 0x00007fa10839c4c1 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const + 193
30 libclang-cpp.so.22.1 0x00007fa10839d46c clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl>&, bool) const + 172
31 libclang-cpp.so.22.1 0x00007fa1083b5af6 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl>&) + 406
32 clang 0x0000564cb63fe434 clang_main(int, char**, llvm::ToolContext const&) + 10740
33 clang 0x0000564cb63f874f main + 127
34 libc.so.6 0x00007fa0faa27741
35 libc.so.6 0x00007fa0faa27879 __libc_start_main + 137
36 clang 0x0000564cb63f87a5 _start + 37
clang: error: clang frontend command failed with exit code 70 (use -v to see invocation)
clang version 22.1.6
Target: wasm32-freestanding
Thread model: posix
InstalledDir: /usr/bin
clang: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/test-485074.ll
clang: note: diagnostic msg: /tmp/test-485074.sh
clang: note: diagnostic msg:
********************
```
[test-485074.sh](https://github.com/user-attachments/files/29491848/test-485074.sh)
If i had to guess, it probably tries to treat `externref` ptr as a regular ptr (`i32`) completly ignoring its semantics.
# Case 2: Global `externref`s:
```llvm
target triple = "wasm32-freestanding"
%externref = type ptr addrspace(10)
@true = external addrspace(1) global %externref
@false = external addrspace(1) global %externref
define %externref @compare(i32 %a) #0 {
%cmp = icmp ne i32 %a, 0
%t = load %externref, ptr addrspace(1) @true
%f = load %externref, ptr addrspace(1) @false
%res = select i1 %cmp, %externref %t, %externref %f
ret %externref %res
}
attributes #0 = { "wasm-export-name"="select" }
```
Note that `addrspace(1)` is being used, which is signaling **LLVM** **not to use** linear memory.
## ``clang test.ll -mcpu=bleeding-edge --target=wasm32-freestanding -c``:
```wasm
00005b func[0] :
00005c: 23 80 80 80 80 00 | global.get 0
000062: 23 81 80 80 80 00 | global.get 1
000068: 20 00 | local.get 0
00006a: 1b | select
00006b: 0f | return
00006c: 0b | end
```
Once again, with optimizations disabled, it fails to use correct `opcode` for select like in **Case 1**.
## With `-O2` added:
```
fatal error: error in backend: Encountered an unlowerable load from the wasm_var address space
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0. Program arguments: clang test.ll -mcpu=bleeding-edge --target=wasm32-freestanding -c -O2
1. Code generation
2. Running pass 'Function Pass Manager' on module 'test.ll'.
3. Running pass 'WebAssembly Instruction Selection' on function '@compare'
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 libLLVM.so.22.1 0x00007f30f9d98a97 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 71
1 libLLVM.so.22.1 0x00007f30f9d96427 llvm::sys::CleanupOnSignal(unsigned long) + 263
2 libLLVM.so.22.1 0x00007f30f9c47704 llvm::CrashRecoveryContext::HandleExit(int) + 84
3 libLLVM.so.22.1 0x00007f30f9d8ed86 llvm::sys::Process::Exit(int, bool) + 38
4 clang 0x000055865e660b1b
5 libLLVM.so.22.1 0x00007f30f9c6bad0 llvm::report_fatal_error(llvm::Twine const&, bool) + 128
6 libLLVM.so.22.1 0x00007f30f9c6bcbe
7 libLLVM.so.22.1 0x00007f30fecac8fe
8 libLLVM.so.22.1 0x00007f30fecbc931
9 libLLVM.so.22.1 0x00007f30fa984e65
10 libLLVM.so.22.1 0x00007f30fa9a0986 llvm::SelectionDAG::Legalize() + 694
11 libLLVM.so.22.1 0x00007f30faba423e llvm::SelectionDAGISel::CodeGenAndEmitDAG() + 462
12 libLLVM.so.22.1 0x00007f30faba6fa9 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) + 5097
13 libLLVM.so.22.1 0x00007f30faba9179 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 249
14 libLLVM.so.22.1 0x00007f30fab966db llvm::SelectionDAGISelLegacy::runOnMachineFunction(llvm::MachineFunction&) + 459
15 libLLVM.so.22.1 0x00007f30fa3ff049 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 473
16 libLLVM.so.22.1 0x00007f30f9f8b98b llvm::FPPassManager::runOnFunction(llvm::Function&) + 1547
17 libLLVM.so.22.1 0x00007f30f9f8d795 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 1429
18 libclang-cpp.so.22.1 0x00007f3105bf62fb
19 libclang-cpp.so.22.1 0x00007f3105bf6796 clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr, std::unique_ptr>, clang::BackendConsumer*) + 1014
20 libclang-cpp.so.22.1 0x00007f3106013f21 clang::CodeGenAction::ExecuteAction() + 3297
21 libclang-cpp.so.22.1 0x00007f3106af8aeb clang::FrontendAction::Execute() + 59
22 libclang-cpp.so.22.1 0x00007f3106a69ef1 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 625
23 libclang-cpp.so.22.1 0x00007f3106bca581 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 737
24 clang 0x000055865e663b64 cc1_main(llvm::ArrayRef, char const*, void*) + 8980
25 clang 0x000055865e65a09a
26 clang 0x000055865e65a244
27 libclang-cpp.so.22.1 0x00007f31065e9ea5
28 libLLVM.so.22.1 0x00007f30f9c475f8 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref) + 40
29 libclang-cpp.so.22.1 0x00007f31065ea917
30 libclang-cpp.so.22.1 0x00007f310659c4c1 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const + 193
31 libclang-cpp.so.22.1 0x00007f310659d46c clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl>&, bool) const + 172
32 libclang-cpp.so.22.1 0x00007f31065b5af6 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl>&) + 406
33 clang 0x000055865e65f434 clang_main(int, char**, llvm::ToolContext const&) + 10740
34 clang 0x000055865e65974f main + 127
35 libc.so.6 0x00007f30f8c27741
36 libc.so.6 0x00007f30f8c27879 __libc_start_main + 137
37 clang 0x000055865e6597a5 _start + 37
```
# Case 3: Using `br` instead
```llvm
target triple = "wasm32-freestanding"
%externref = type ptr addrspace(10)
define %externref @select(i32 %a, %externref %t, %externref %f) #0 {
%cmp = icmp ne i32 %a, 0
br i1 %cmp, label %true, label %false
true:
ret %externref %t
false:
ret %externref %f
}
attributes #0 = { "wasm-export-name"="select" }
```
## ``clang test.ll -mcpu=bleeding-edge --target=wasm32-freestanding -c``:
```wasm
000054 func[0] :
000055: 02 40 | block
000057: 20 00 | local.get 0
000059: 45 | i32.eqz
00005a: 0d 00 | br_if 0
00005c: 20 01 | local.get 1
00005e: 0f | return
00005f: 0b | end
000060: 20 02 | local.get 2
000062: 0f | return
000063: 0b | end
```
This is the only case in this whole report where **LLVM** produced valid output. Running this correctly selects return value based on the condition.
## With `-O2` added:
```
fatal error: error in backend: Cannot select: 0x55c6b11461e0: externref = select_cc 0x55c6b1145d80, Constant:i32<0>, 0x55c6b1145f40, 0x55c6b1145e60, seteq:ch
0x55c6b1145d80: i32 = WebAssemblyISD::ARGUMENT TargetConstant:i32<0>
0x55c6b1145f40: externref = WebAssemblyISD::ARGUMENT TargetConstant:i32<2>
0x55c6b1145e60: externref = WebAssemblyISD::ARGUMENT TargetConstant:i32<1>
In function: select
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0. Program arguments: clang test.ll -mcpu=bleeding-edge --target=wasm32-freestanding -c -O2
1. Code generation
2. Running pass 'Function Pass Manager' on module 'test.ll'.
3. Running pass 'WebAssembly Instruction Selection' on function '@select'
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 libLLVM.so.22.1 0x00007f6d58398a97 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 71
1 libLLVM.so.22.1 0x00007f6d58396427 llvm::sys::CleanupOnSignal(unsigned long) + 263
2 libLLVM.so.22.1 0x00007f6d58247704 llvm::CrashRecoveryContext::HandleExit(int) + 84
3 libLLVM.so.22.1 0x00007f6d5838ed86 llvm::sys::Process::Exit(int, bool) + 38
4 clang 0x000055c69796db1b
5 libLLVM.so.22.1 0x00007f6d5826bad0 llvm::report_fatal_error(llvm::Twine const&, bool) + 128
6 libLLVM.so.22.1 0x00007f6d5919c0e8 llvm::SelectionDAGISel::CannotYetSelect(llvm::SDNode*) + 440
7 libLLVM.so.22.1 0x00007f6d5919e4fb llvm::SelectionDAGISel::SelectCodeCommon(llvm::SDNode*, unsigned char const*, unsigned int) + 8891
8 libLLVM.so.22.1 0x00007f6d5d2a2a08
9 libLLVM.so.22.1 0x00007f6d59196b29 llvm::SelectionDAGISel::DoInstructionSelection() + 489
10 libLLVM.so.22.1 0x00007f6d591a430c llvm::SelectionDAGISel::CodeGenAndEmitDAG() + 668
11 libLLVM.so.22.1 0x00007f6d591a6fa9 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) + 5097
12 libLLVM.so.22.1 0x00007f6d591a9179 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 249
13 libLLVM.so.22.1 0x00007f6d591966db llvm::SelectionDAGISelLegacy::runOnMachineFunction(llvm::MachineFunction&) + 459
14 libLLVM.so.22.1 0x00007f6d589ff049 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 473
15 libLLVM.so.22.1 0x00007f6d5858b98b llvm::FPPassManager::runOnFunction(llvm::Function&) + 1547
16 libLLVM.so.22.1 0x00007f6d5858d795 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 1429
17 libclang-cpp.so.22.1 0x00007f6d641f62fb
18 libclang-cpp.so.22.1 0x00007f6d641f6796 clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr, std::unique_ptr>, clang::BackendConsumer*) + 1014
19 libclang-cpp.so.22.1 0x00007f6d64613f21 clang::CodeGenAction::ExecuteAction() + 3297
20 libclang-cpp.so.22.1 0x00007f6d650f8aeb clang::FrontendAction::Execute() + 59
21 libclang-cpp.so.22.1 0x00007f6d65069ef1 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 625
22 libclang-cpp.so.22.1 0x00007f6d651ca581 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 737
23 clang 0x000055c697970b64 cc1_main(llvm::ArrayRef, char const*, void*) + 8980
24 clang 0x000055c69796709a
25 clang 0x000055c697967244
26 libclang-cpp.so.22.1 0x00007f6d64be9ea5
27 libLLVM.so.22.1 0x00007f6d582475f8 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref) + 40
28 libclang-cpp.so.22.1 0x00007f6d64bea917
29 libclang-cpp.so.22.1 0x00007f6d64b9c4c1 clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const + 193
30 libclang-cpp.so.22.1 0x00007f6d64b9d46c clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl>&, bool) const + 172
31 libclang-cpp.so.22.1 0x00007f6d64bb5af6 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl>&) + 406
32 clang 0x000055c69796c434 clang_main(int, char**, llvm::ToolContext const&) + 10740
33 clang 0x000055c69796674f main + 127
34 libc.so.6 0x00007f6d57227741
35 libc.so.6 0x00007f6d57227879 __libc_start_main + 137
36 clang 0x000055c6979667a5 _start + 37
clang: error: clang frontend command failed with exit code 70 (use -v to see invocation)
clang version 22.1.6
Target: wasm32-freestanding
Thread model: posix
InstalledDir: /usr/bin
clang: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/test-2392d2.ll
clang: note: diagnostic msg: /tmp/test-2392d2.sh
clang: note: diagnostic msg:
```
[test-2392d2.sh](https://github.com/user-attachments/files/29491784/test-2392d2.sh)
**LLVM** tried to use `select` and failed.
Contributor guide
Research direction
Reproduce the issue with test.ll using the clang commands shown, both without optimization and with -O2. Start in the WebAssembly Instruction Selection path and investigate typed select handling for externref and loads from the wasm_var address space. Done means both cases compile successfully and emit typed select with opcode 0x1c rather than the untyped opcode.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- wasm
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100