[WebAssembly] Fix crash when storing externref to globals#178474
[WebAssembly] Fix crash when storing externref to globals#178474ParkHanbum wants to merge 1 commit intollvm:mainfrom
Conversation
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: llvm#141011
|
@llvm/pr-subscribers-backend-webassembly Author: hanbeom (ParkHanbum) ChangesStoring This patch implements custom lowering for Fixes: #141011 Full diff: https://github.com/llvm/llvm-project/pull/178474.diff 3 Files Affected:
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
+@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:
|
|
None of these changes are necessary. The problem is that in the test, the global The test should be this instead: @a = addrspace(1) 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 addrspace(1) @a
ret void
}Address space 1 is how LLVM represents WASM globals (and tables). |
Storing
externrefvalues to global variables previously caused a selection error because the backend attempted a linear memory store.This patch implements custom lowering for
ISD::STOREto convert stores ofexternrefvalues intoWebAssemblyISD::GLOBAL_SET, ensuring they are correctly updated in the Wasm global space.Fixes: #141011