[llvm] [WebAssembly] Fix SELECT_CC lowering for reference types (PR #181622)
Hood Chatham via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 19 01:50:46 PST 2026
https://github.com/hoodmane updated https://github.com/llvm/llvm-project/pull/181622
>From e8bcf7e98082a9e74a22c30fe77b747bae525e16 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 | 15 ++++--
.../CodeGen/WebAssembly/select-reftype.ll | 50 +++++++++++++++++++
3 files changed, 66 insertions(+), 5 deletions(-)
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..faea931aeccdc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -271,11 +271,6 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
// There is no i8x16.mul instruction
setOperationAction(ISD::MUL, MVT::v16i8, Expand);
- // There is no vector conditional select instruction
- for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
- MVT::v2f64})
- setOperationAction(ISD::SELECT_CC, T, Expand);
-
// Expand integer operations supported for scalars but not SIMD
for (auto Op :
{ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR})
@@ -370,6 +365,16 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
setOperationAction(Op, T, Expand);
+ if (Subtarget->hasReferenceTypes())
+ for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
+ for (auto T : {MVT::externref, MVT::funcref})
+ setOperationAction(Op, T, Expand);
+
+ // There is no vector conditional select instruction
+ for (auto T :
+ {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64, MVT::v2f64})
+ 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..baca3ca6258a3
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/select-reftype.ll
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; 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-NEXT: # %bb.0:
+; CHECK-NEXT: 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-NEXT: # %bb.0:
+; CHECK-NEXT: 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-NEXT: # %bb.0:
+; CHECK-NEXT: 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-NEXT: # %bb.0:
+; CHECK-NEXT: 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