[llvm] [WebAssembly] Fix crash when storing externref to globals (PR #178474)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 28 09:54:43 PST 2026


https://github.com/ParkHanbum created https://github.com/llvm/llvm-project/pull/178474

Storing `externref` values to global variables previously caused a selection error because the backend attempted a linear memory store.

This patch implements custom lowering for `ISD::STORE` to convert stores of `externref` values into `WebAssemblyISD::GLOBAL_SET`, ensuring they are correctly updated in the Wasm global space.

Fixes: #141011

>From 51603e5282d892bf8fdff3dd4316709073bffb86 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Thu, 29 Jan 2026 02:51:58 +0900
Subject: [PATCH] [WebAssembly] Fix crash when storing externref to globals

Storing `externref` values to global variables previously caused
a selection error because the backend attempted a linear memory store.

This patch implements custom lowering for `ISD::STORE` to convert
stores of `externref` values into `WebAssemblyISD::GLOBAL_SET`,
ensuring they are correctly updated in the Wasm global space.

Fixes: #141011
---
 .../WebAssembly/WebAssemblyISelLowering.cpp     | 17 +++++++++++++++++
 .../Target/WebAssembly/WebAssemblyInstrInfo.td  |  5 +++++
 llvm/test/CodeGen/WebAssembly/global-set.ll     | 13 +++++++++++++
 3 files changed, 35 insertions(+)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 5abf0e8f59d2a..69357c908397b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1824,6 +1824,23 @@ SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
         "Encountered an unlowerable store to the wasm_var address space",
         false);
 
+  if (Value.getValueType() == MVT::externref) {
+    SDValue Ptr =
+        Base.getOpcode() != WebAssemblyISD::Wrapper ? Base : Base.getOperand(0);
+    auto *GNode = dyn_cast<GlobalAddressSDNode>(Ptr);
+    if (!GNode)
+      report_fatal_error("Cannot store externref to non-global address");
+
+    const GlobalValue *GV = GNode->getGlobal();
+    SDValue TargetGlobal =
+        DAG.getTargetGlobalAddress(GV, DL, Ptr.getValueType());
+    SDValue WrappedPtr =
+        DAG.getNode(WebAssemblyISD::Wrapper, DL, MVT::i32, TargetGlobal);
+
+    return DAG.getNode(WebAssemblyISD::GLOBAL_SET, DL, MVT::Other,
+                       SN->getChain(), Value, WrappedPtr);
+  }
+
   return Op;
 }
 
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 76e94c2ec3d61..839f5e11fe6d2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -458,6 +458,11 @@ def : Pat<(i32 (WebAssemblyWrapperREL texternalsym:$addr)),
 def : Pat<(i64 (WebAssemblyWrapperREL texternalsym:$addr)),
           (CONST_I64 texternalsym:$addr)>, Requires<[IsPIC, HasAddr64]>;
 
+// Manually define the pattern because 'externref' is not included in the
+// standard RegTypes iteration of the generic loop above.
+def : Pat<(WebAssemblyglobal_set externref:$src, (WebAssemblyWrapper tglobaladdr:$addr)),
+          (GLOBAL_SET_EXTERNREF tglobaladdr:$addr, externref:$src)>,
+          Requires<[HasReferenceTypes]>;
 //===----------------------------------------------------------------------===//
 // Additional sets of instructions.
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/WebAssembly/global-set.ll b/llvm/test/CodeGen/WebAssembly/global-set.ll
index 4553957ae7588..6c37ba8e7ac1c 100644
--- a/llvm/test/CodeGen/WebAssembly/global-set.ll
+++ b/llvm/test/CodeGen/WebAssembly/global-set.ll
@@ -4,6 +4,19 @@
 @i64_global = local_unnamed_addr addrspace(1) global i64 undef
 @f32_global = local_unnamed_addr addrspace(1) global float undef
 @f64_global = local_unnamed_addr addrspace(1) global double undef
+ at a = global ptr addrspace(10) null
+
+declare ptr addrspace(10) @function_that_gives_me_a_js_object()
+define void @object_store_to_global_ptr() {
+; CHECK-LABEL: object_store_to_global_ptr:
+; CHECK:         .functype object_store_to_global_ptr () -> ()
+; CHECK-NEXT:    call function_that_gives_me_a_js_object
+; CHECK-NEXT:    global.set a
+; CHECK-NEXT:    end_function
+  %object = call ptr addrspace(10) @function_that_gives_me_a_js_object()
+  store ptr addrspace(10) %object, ptr @a
+  ret void
+}
 
 define void @set_i32_global(i32 %v) {
 ; CHECK-LABEL: set_i32_global:



More information about the llvm-commits mailing list