[llvm] [WebAssembly] Fix SELECT_CC lowering for reference types (PR #181622)
Hood Chatham via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 17 03:22:30 PST 2026
https://github.com/hoodmane updated https://github.com/llvm/llvm-project/pull/181622
>From e48da7b6da5e5b2007e8717b9988b0ffaf7da562 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchatham at gmail.com>
Date: Mon, 16 Feb 2026 10:47:03 +0100
Subject: [PATCH] [WebAssembly] Fix SELECT_CC lowering for reference types
SELECT_CC nodes with externref or funcref return types were not being
expanded, causing "Cannot select" errors during instruction selection.
This adds SELECT_CC to the list of operations that should be expanded
for reference types, similar to how it's already handled for scalar
types (i32, i64, f32, f64). This allows the SELECT_CC to be lowered to
a SELECT node, which already has instruction patterns defined in
WebAssemblyInstrRef.td.
---
.../WebAssembly/WebAssemblyAsmPrinter.cpp | 6 +++
.../WebAssembly/WebAssemblyISelLowering.cpp | 6 +++
.../CodeGen/WebAssembly/select-reftype.ll | 45 +++++++++++++++++++
3 files changed, 57 insertions(+)
create mode 100644 llvm/test/CodeGen/WebAssembly/select-reftype.ll
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 1cacdb04fa74d..fdf98902b68bd 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -666,6 +666,12 @@ void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) {
case WebAssembly::ARGUMENT_v2f64_S:
case WebAssembly::ARGUMENT_v8f16:
case WebAssembly::ARGUMENT_v8f16_S:
+ case WebAssembly::ARGUMENT_externref:
+ case WebAssembly::ARGUMENT_externref_S:
+ case WebAssembly::ARGUMENT_funcref:
+ case WebAssembly::ARGUMENT_funcref_S:
+ case WebAssembly::ARGUMENT_exnref:
+ case WebAssembly::ARGUMENT_exnref_S:
// These represent values which are live into the function entry, so there's
// no instruction to emit.
break;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 2799b0ee0c804..a26db5ef5cf92 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -370,6 +370,12 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
setOperationAction(Op, T, Expand);
+ // Reference types need SELECT_CC to be expanded to SELECT as well.
+ if (Subtarget->hasReferenceTypes()) {
+ for (auto T : {MVT::externref, MVT::funcref})
+ setOperationAction(ISD::SELECT_CC, T, Expand);
+ }
+
// We have custom switch handling.
setOperationAction(ISD::BR_JT, MVT::Other, Custom);
diff --git a/llvm/test/CodeGen/WebAssembly/select-reftype.ll b/llvm/test/CodeGen/WebAssembly/select-reftype.ll
new file mode 100644
index 0000000000000..220be8e3cd577
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/select-reftype.ll
@@ -0,0 +1,45 @@
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown -mattr=+reference-types -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
+
+; Test that wasm select instruction works with reference types.
+
+target triple = "wasm32-unknown-unknown"
+
+define ptr addrspace(10) @select_externref_eq(i32 %a, ptr addrspace(10) %b, ptr addrspace(10) %c) {
+; CHECK-LABEL: select_externref_eq:
+; CHECK: .functype select_externref_eq (i32, externref, externref) -> (externref)
+; CHECK: externref.select $push0=, $2, $1, $0
+; CHECK-NEXT: return $pop0
+ %cmp = icmp eq i32 %a, 0
+ %cond = select i1 %cmp, ptr addrspace(10) %b, ptr addrspace(10) %c
+ ret ptr addrspace(10) %cond
+}
+
+define ptr addrspace(10) @select_externref_ne(i32 %a, ptr addrspace(10) %b, ptr addrspace(10) %c) {
+; CHECK-LABEL: select_externref_ne:
+; CHECK: .functype select_externref_ne (i32, externref, externref) -> (externref)
+; CHECK: externref.select $push0=, $1, $2, $0
+; CHECK-NEXT: return $pop0
+ %cmp = icmp ne i32 %a, 0
+ %cond = select i1 %cmp, ptr addrspace(10) %b, ptr addrspace(10) %c
+ ret ptr addrspace(10) %cond
+}
+
+define ptr addrspace(20) @select_funcref_eq(i32 %a, ptr addrspace(20) %b, ptr addrspace(20) %c) {
+; CHECK-LABEL: select_funcref_eq:
+; CHECK: .functype select_funcref_eq (i32, funcref, funcref) -> (funcref)
+; CHECK: funcref.select $push0=, $2, $1, $0
+; CHECK-NEXT: return $pop0
+ %cmp = icmp eq i32 %a, 0
+ %cond = select i1 %cmp, ptr addrspace(20) %b, ptr addrspace(20) %c
+ ret ptr addrspace(20) %cond
+}
+
+define ptr addrspace(20) @select_funcref_ne(i32 %a, ptr addrspace(20) %b, ptr addrspace(20) %c) {
+; CHECK-LABEL: select_funcref_ne:
+; CHECK: .functype select_funcref_ne (i32, funcref, funcref) -> (funcref)
+; CHECK: funcref.select $push0=, $1, $2, $0
+; CHECK-NEXT: return $pop0
+ %cmp = icmp ne i32 %a, 0
+ %cond = select i1 %cmp, ptr addrspace(20) %b, ptr addrspace(20) %c
+ ret ptr addrspace(20) %cond
+}
More information about the llvm-commits
mailing list