https://github.com/hmelder updated https://github.com/llvm/llvm-project/pull/175202
>From b37d5288c3c5f547b2043cf2a6ff0ccaa2a6f129 Mon Sep 17 00:00:00 2001 From: hmelder <[email protected]> Date: Fri, 9 Jan 2026 09:09:07 +0000 Subject: [PATCH 1/5] [WebAssembly] Call EH personality fn directly Move away from using _Unwind_CallPersonality and instead call the EH personality function directly. _Unwind_CallPersonality clears the selector field in the landing pad and then calls the hard-coded personality function '__gxx_personality_wasm0'. This is now done in codegen instead to allow the use of other personality functions --- llvm/include/llvm/IR/RuntimeLibcalls.td | 1 - llvm/lib/CodeGen/WasmEHPrepare.cpp | 97 ++++++++++++++----------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td index b9e68247de94d..8e032f20905f0 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -3500,7 +3500,6 @@ def WasmSystemLibrary (add DefaultRuntimeLibcallImpls, Int128RTLibcalls, CompilerRTOnlyInt64Libcalls, CompilerRTOnlyInt128Libcalls, exp10f, exp10, - _Unwind_CallPersonality, emscripten_return_address, LibcallImpls<(add __small_printf, __small_sprintf, diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp index 2f54578da5113..ab75372a50b06 100644 --- a/llvm/lib/CodeGen/WasmEHPrepare.cpp +++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp @@ -28,7 +28,9 @@ // wasm.landingpad.index(index); // __wasm_lpad_context.lpad_index = index; // __wasm_lpad_context.lsda = wasm.lsda(); -// _Unwind_CallPersonality(exn); +// __wasm_lpad_context.selector = 0; +// personality_fn(1, _UA_SEARCH_PHASE, exn->exception_class, exn, +// (struct _Unwind_Context *)&__wasm_lpad_context); // selector = __wasm_lpad_context.selector; // ... // @@ -38,18 +40,13 @@ // exception is thrown. After the stack is unwound, the control flow is // transfered to WebAssembly 'catch' instruction. // -// Unwinding the stack is not done by libunwind but the VM, so the personality -// function in libcxxabi cannot be called from libunwind during the unwinding -// process. So after a catch instruction, we insert a call to a wrapper function -// in libunwind that in turn calls the real personality function. -// // In Itanium EH, if the personality function decides there is no matching catch // clause in a call frame and no cleanup action to perform, the unwinder doesn't // stop there and continues unwinding. But in Wasm EH, the unwinder stops at // every call frame with a catch intruction, after which the personality // function is called from the compiler-generated user code here. // -// In libunwind, we have this struct that serves as a communincation channel +// In libunwind, we have this struct that serves as a communication channel // between the compiler-generated user code and the personality function in // libcxxabi. // @@ -60,20 +57,8 @@ // }; // struct _Unwind_LandingPadContext __wasm_lpad_context = ...; // -// And this wrapper in libunwind calls the personality function. -// -// _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) { -// struct _Unwind_Exception *exception_obj = -// (struct _Unwind_Exception *)exception_ptr; -// _Unwind_Reason_Code ret = __gxx_personality_v0( -// 1, _UA_CLEANUP_PHASE, exception_obj->exception_class, exception_obj, -// (struct _Unwind_Context *)__wasm_lpad_context); -// return ret; -// } -// // We pass a landing pad index, and the address of LSDA for the current function -// to the wrapper function _Unwind_CallPersonality in libunwind, and we retrieve -// the selector after it returns. +// to the personality function, and we retrieve the selector after it returns. // //===----------------------------------------------------------------------===// @@ -82,6 +67,7 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/IR/EHPersonalities.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicsWebAssembly.h" #include "llvm/IR/Module.h" @@ -98,6 +84,7 @@ class WasmEHPrepareImpl { friend class WasmEHPrepare; Type *LPadContextTy = nullptr; // type of 'struct _Unwind_LandingPadContext' + Type *UnwindExceptionTy = nullptr; // type of 'struct _Unwind_Exception' GlobalVariable *LPadContextGV = nullptr; // __wasm_lpad_context // Field addresses of struct _Unwind_LandingPadContext @@ -111,8 +98,7 @@ class WasmEHPrepareImpl { Function *GetExnF = nullptr; // wasm.get.exception() intrinsic Function *CatchF = nullptr; // wasm.catch() intrinsic Function *GetSelectorF = nullptr; // wasm.get.ehselector() intrinsic - FunctionCallee CallPersonalityF = - nullptr; // _Unwind_CallPersonality() wrapper + FunctionCallee PersonalityF = nullptr; bool prepareThrows(Function &F); bool prepareEHPads(Function &F); @@ -120,7 +106,8 @@ class WasmEHPrepareImpl { public: WasmEHPrepareImpl() = default; - WasmEHPrepareImpl(Type *LPadContextTy_) : LPadContextTy(LPadContextTy_) {} + WasmEHPrepareImpl(Type *LPadContextTy_, Type *UnwindExceptionTy_) + : LPadContextTy(LPadContextTy_), UnwindExceptionTy(UnwindExceptionTy_) {} bool runOnFunction(Function &F); }; @@ -145,10 +132,14 @@ PreservedAnalyses WasmEHPreparePass::run(Function &F, FunctionAnalysisManager &) { auto &Context = F.getContext(); auto *I32Ty = Type::getInt32Ty(Context); + auto *I64Ty = Type::getInt64Ty(Context); auto *PtrTy = PointerType::get(Context, 0); auto *LPadContextTy = StructType::get(I32Ty /*lpad_index*/, PtrTy /*lsda*/, I32Ty /*selector*/); - WasmEHPrepareImpl P(LPadContextTy); + auto *UnwindExceptionTy = + StructType::get(I64Ty /* exception_class*/, PtrTy /* exception_cleanup */, + I32Ty /* private_1 */, I32Ty /* private_2 */); + WasmEHPrepareImpl P(LPadContextTy, UnwindExceptionTy); bool Changed = P.runOnFunction(F); return Changed ? PreservedAnalyses::none() : PreservedAnalyses ::all(); } @@ -163,9 +154,15 @@ FunctionPass *llvm::createWasmEHPass() { return new WasmEHPrepare(); } bool WasmEHPrepare::doInitialization(Module &M) { IRBuilder<> IRB(M.getContext()); - P.LPadContextTy = StructType::get(IRB.getInt32Ty(), // lpad_index - IRB.getPtrTy(), // lsda - IRB.getInt32Ty() // selector + auto *I32Ty = IRB.getInt32Ty(); + auto *I64Ty = IRB.getInt64Ty(); + auto *PtrTy = IRB.getPtrTy(); + P.LPadContextTy = StructType::get(I32Ty, // lpad_index + PtrTy, // lsda + I32Ty // selector + ); + P.UnwindExceptionTy = StructType::get(I64Ty, /* exception_class*/ + PtrTy /* exception_cleanup */ ); return false; } @@ -235,11 +232,15 @@ bool WasmEHPrepareImpl::prepareEHPads(Function &F) { if (CatchPads.empty() && CleanupPads.empty()) return false; - if (!F.hasPersonalityFn() || - !isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) { + if (!F.hasPersonalityFn()) + return false; + + auto Personality = classifyEHPersonality(F.getPersonalityFn()); + + if (!isScopedEHPersonality(Personality)) { report_fatal_error("Function '" + F.getName() + "' does not have a correct Wasm personality function " - "'__gxx_wasm_personality_v0'"); + "'__gxx_personality_wasm0'"); } assert(F.hasPersonalityFn() && "Personality function not found"); @@ -274,16 +275,13 @@ bool WasmEHPrepareImpl::prepareEHPads(Function &F) { // instruction selection. CatchF = Intrinsic::getOrInsertDeclaration(&M, Intrinsic::wasm_catch); - // FIXME: Verify this is really supported for current module. - StringRef UnwindCallPersonalityName = - RTLIB::RuntimeLibcallsInfo::getLibcallImplName( - RTLIB::impl__Unwind_CallPersonality); - - // _Unwind_CallPersonality() wrapper function, which calls the personality - CallPersonalityF = M.getOrInsertFunction(UnwindCallPersonalityName, - IRB.getInt32Ty(), IRB.getPtrTy()); - if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee())) - F->setDoesNotThrow(); + auto *I32Ty = IRB.getInt32Ty(); + auto *I64Ty = IRB.getInt64Ty(); + auto *PtrTy = IRB.getPtrTy(); + auto *PersPrototype = + FunctionType::get(I32Ty, {I32Ty, I32Ty, I64Ty, PtrTy, PtrTy}, false); + PersonalityF = + M.getOrInsertFunction(getEHPersonalityName(Personality), PersPrototype); unsigned Index = 0; for (auto *BB : CatchPads) { @@ -367,9 +365,22 @@ void WasmEHPrepareImpl::prepareEHPad(BasicBlock *BB, bool NeedPersonality, // Pseudocode: __wasm_lpad_context.lsda = wasm.lsda(); IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField); - // Pseudocode: _Unwind_CallPersonality(exn); - CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI, - OperandBundleDef("funclet", CPI)); + // Pseudocode: __wasm_lpad_context.selector = 0; + IRB.CreateStore(IRB.getInt32(0), SelectorField); + + // Pseudocode: &exn->exception_class + auto *ExceptionClassPtr = IRB.CreateConstInBoundsGEP2_32( + UnwindExceptionTy, CatchCI, 0, 0, "exception_class_gep"); + auto *ExceptionClass = IRB.CreateLoad(IRB.getInt64Ty(), ExceptionClassPtr); + auto *UASearchPhase = IRB.getInt32(1); + + // Pseudocode: + // personality_fn(1, _UA_SEARCH_PHASE, exn->exception_class, exn, + // (struct _Unwind_Context *)&__wasm_lpad_context); + CallInst *PersCI = IRB.CreateCall( + PersonalityF, + {IRB.getInt32(1), UASearchPhase, ExceptionClass, CatchCI, LPadContextGV}, + OperandBundleDef("funclet", CPI)); PersCI->setDoesNotThrow(); // Pseudocode: int selector = __wasm_lpad_context.selector; >From e4a209636ddee64e684b6805b3e435dad129ef58 Mon Sep 17 00:00:00 2001 From: hmelder <[email protected]> Date: Fri, 9 Jan 2026 09:17:31 +0000 Subject: [PATCH 2/5] [WebAssembly] Remove _Unwind_CallPersonality This is now unused and implemented directly in codegen. --- libunwind/src/Unwind-wasm.c | 23 ----------------------- llvm/include/llvm/IR/RuntimeLibcalls.td | 3 --- 2 files changed, 26 deletions(-) diff --git a/libunwind/src/Unwind-wasm.c b/libunwind/src/Unwind-wasm.c index b8b7bc2779f17..4ffd74f34c238 100644 --- a/libunwind/src/Unwind-wasm.c +++ b/libunwind/src/Unwind-wasm.c @@ -37,29 +37,6 @@ struct _Unwind_LandingPadContext { // function thread_local struct _Unwind_LandingPadContext __wasm_lpad_context; -/// Calls to this function is in landing pads in compiler-generated user code. -/// In other EH schemes, stack unwinding is done by libunwind library, which -/// calls the personality function for each each frame it lands. On the other -/// hand, WebAssembly stack unwinding process is performed by a VM, and the -/// personality function cannot be called from there. So the compiler inserts -/// a call to this function in landing pads in the user code, which in turn -/// calls the personality function. -_Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) { - struct _Unwind_Exception *exception_object = - (struct _Unwind_Exception *)exception_ptr; - _LIBUNWIND_TRACE_API("_Unwind_CallPersonality(exception_object=%p)", - (void *)exception_object); - - // Reset the selector. - __wasm_lpad_context.selector = 0; - - // Call personality function. Wasm does not have two-phase unwinding, so we - // only do the cleanup phase. - return __gxx_personality_wasm0( - 1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object, - (struct _Unwind_Context *)&__wasm_lpad_context); -} - /// Called by __cxa_throw. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td index 8e032f20905f0..b6f5b8497b93a 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -1833,9 +1833,6 @@ defset list<RuntimeLibcallImpl> SjLjExceptionHandlingLibcalls = { def _Unwind_SjLj_Unregister : RuntimeLibcallImpl<UNWIND_UNREGISTER>; } -// Only used on wasm? -def _Unwind_CallPersonality : RuntimeLibcallImpl<UNWIND_CALL_PERSONALITY>; - // Used on OpenBSD def __stack_smash_handler : RuntimeLibcallImpl<STACK_SMASH_HANDLER>; >From 560598b59f095fb7ebdd5b6816264cbe8f6e81f6 Mon Sep 17 00:00:00 2001 From: hmelder <[email protected]> Date: Fri, 9 Jan 2026 16:17:11 +0000 Subject: [PATCH 3/5] [WebAssembly] Fix WebAssembly EH unit tests Fix WebAssembly EH unit tests after moving away from _Unwind_CallPersonality. --- .../CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll | 12 ++++++------ llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll | 10 +++++----- llvm/test/CodeGen/WebAssembly/eh-lsda.ll | 5 ++++- llvm/test/CodeGen/WebAssembly/exception-legacy.ll | 6 +++++- llvm/test/CodeGen/WebAssembly/exception.ll | 11 ++++++++++- .../WebAssembly/wasm-eh-invalid-personality.ll | 2 +- llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll | 9 ++++++--- 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll index f0a1d9805c806..b1156f07b1274 100644 --- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll +++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll @@ -100,23 +100,23 @@ try.cont: ; preds = %catch, %catch2, %en ; CHECK: catch ; CHECK: block ; CHECK: block -; CHECK: br_if 0, {{.*}} # 0: down to label[[L0:[0-9+]]] +; CHECK: br_if 0, {{.*}} # 0: down to label[[L0:[0-9]+]] ; CHECK: call $drop=, __cxa_begin_catch, $0 ; CHECK: try ; CHECK: try ; CHECK: call foo -; CHECK: br 3 # 3: down to label[[L1:[0-9+]]] +; CHECK: br 3 # 3: down to label[[L1:[0-9]+]] ; CHECK: catch ; CHECK: block ; CHECK: block -; CHECK: br_if 0, {{.*}} # 0: down to label[[L2:[0-9+]]] +; CHECK: br_if 0, {{.*}} # 0: down to label[[L2:[0-9]+]] ; CHECK: call $drop=, __cxa_begin_catch ; CHECK: try ; CHECK: call foo -; CHECK: br 2 # 2: down to label[[L3:[0-9+]]] +; CHECK: br 2 # 2: down to label[[L3:[0-9]+]] ; CHECK: catch_all ; CHECK: call __cxa_end_catch -; CHECK: rethrow 0 # down to catch[[L4:[0-9+]]] +; CHECK: rethrow 0 # down to catch[[L4:[0-9]+]] ; CHECK: end_try ; CHECK: end_block # label[[L2]]: ; CHECK: rethrow 1 # down to catch[[L4]] @@ -1736,7 +1736,7 @@ unreachable: ; preds = %rethrow, %entry } ; Check if the unwind destination mismatch stats are correct -; NOSORT: 24 wasm-cfg-stackify - Number of call unwind mismatches found +; NOSORT: 32 wasm-cfg-stackify - Number of call unwind mismatches found ; NOSORT: 5 wasm-cfg-stackify - Number of catch unwind mismatches found declare void @foo() diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll index 98de9a267b95a..c89f88c67ac46 100644 --- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll +++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll @@ -35,7 +35,7 @@ target triple = "wasm32-unknown-unknown" ; CHECK: local.set 2 ; CHECK: local.set 1 ; CHECK: local.get 0 -; CHECK: call _Unwind_CallPersonality +; CHECK: call __gxx_wasm_personality_v0 ; CHECK: block ; CHECK: br_if 0 # 0: down to label[[L2:[0-9]+]] ; CHECK: call __cxa_begin_catch @@ -111,7 +111,7 @@ try.cont: ; preds = %catch, %catch2, %en ; CHECK: br 2 # 2: down to label[[L1:[0-9]+]] ; CHECK: end_try_table ; CHECK: end_block # label[[L0]]: -; CHECK: call _Unwind_CallPersonality +; CHECK: call __gxx_wasm_personality_v0 ; CHECK: block ; CHECK: block ; CHECK: br_if 0 # 0: down to label[[L2:[0-9]+]] @@ -124,7 +124,7 @@ try.cont: ; preds = %catch, %catch2, %en ; CHECK: br 5 # 5: down to label[[L5:[0-9]+]] ; CHECK: end_try_table ; CHECK: end_block # label[[L4]]: -; CHECK: call _Unwind_CallPersonality +; CHECK: call __gxx_wasm_personality_v0 ; CHECK: block ; CHECK: block ; CHECK: br_if 0 # 0: down to label[[L6:[0-9]+]] @@ -750,7 +750,7 @@ try.cont: ; preds = %catch.start0 ; NOSORT: end_block # label[[L0]]: ; NOSORT: call __cxa_begin_catch ; NOSORT: call __cxa_end_catch -; NOSORT: end_block # label74: +; NOSORT: end_block ; NOSORT: return ; NOSORT: end_block # label[[L1]]: ; NOSORT: throw_ref @@ -1507,7 +1507,7 @@ unreachable: ; preds = %rethrow, %entry } ; Check if the unwind destination mismatch stats are correct -; NOSORT: 23 wasm-cfg-stackify - Number of call unwind mismatches found +; NOSORT: 30 wasm-cfg-stackify - Number of call unwind mismatches found ; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found declare void @foo() diff --git a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll index d5b28b279d419..f069f77147e57 100644 --- a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll +++ b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll @@ -66,7 +66,10 @@ try.cont: ; preds = %entry, %catch.start ; CHECK-LABEL: test1: ; In static linking, we load GCC_except_table as a constant directly. -; NOPIC: i[[PTR]].const $push[[CONTEXT:.*]]=, {{[48]}} +; NOPIC: i[[PTR]].const $push[[SELECTOR_OFF:.*]]=, {{(8|16)}} +; NOPIC-NEXT: i[[PTR]].const $push[[SELECTOR:.*]]=, 0 +; NOPIC-NEXT: i[[PTR]].store __wasm_lpad_context($pop[[SELECTOR_OFF]]), $pop[[SELECTOR]] +; NOPIC-NEXT: i[[PTR]].const $push[[CONTEXT:.*]]=, {{[48]}} ; NOPIC-NEXT: i[[PTR]].const $push[[EXCEPT_TABLE:.*]]=, GCC_except_table1 ; NOPIC-NEXT: i[[PTR]].store __wasm_lpad_context($pop[[CONTEXT]]), $pop[[EXCEPT_TABLE]] diff --git a/llvm/test/CodeGen/WebAssembly/exception-legacy.ll b/llvm/test/CodeGen/WebAssembly/exception-legacy.ll index b96a664166f42..e638af4ad3bb2 100644 --- a/llvm/test/CodeGen/WebAssembly/exception-legacy.ll +++ b/llvm/test/CodeGen/WebAssembly/exception-legacy.ll @@ -35,7 +35,11 @@ define void @throw(ptr %p) { ; CHECK: catch $[[EXN:[0-9]+]]=, __cpp_exception ; CHECK: global.set __stack_pointer ; CHECK: i32.store __wasm_lpad_context -; CHECK: call $drop=, _Unwind_CallPersonality, $[[EXN]] +; CHECK: i32.const $push[[ACTION:[0-9]+]]=, 1 +; CHECK: i32.const $push[[PHASE:[0-9]+]]=, 1 +; CHECK: i64.load $push[[EH_CLASS:[0-9]+]]=, 0($[[EXN]]) +; CHECK: i32.const $push[[LPAD_CTX:[0-9]+]]=, __wasm_lpad_context +; CHECK: call $drop=, __gxx_wasm_personality_v0, $pop[[ACTION]], $pop[[PHASE]], $pop[[EH_CLASS]], $0, $pop[[LPAD_CTX]] ; CHECK: block ; CHECK: br_if 0 ; CHECK: call $drop=, __cxa_begin_catch diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll index 873386b3dcc6d..f48ce2fc9d537 100644 --- a/llvm/test/CodeGen/WebAssembly/exception.ll +++ b/llvm/test/CodeGen/WebAssembly/exception.ll @@ -47,7 +47,16 @@ define void @throw(ptr %p) { ; CHECK: local.get 0 ; CHECK: global.set __stack_pointer ; CHECK: i32.store __wasm_lpad_context -; CHECK: call _Unwind_CallPersonality + +; CHECK: i32.const 1 +; CHECK: i32.const 1 +; CHECK: local.get 1 +; CHECK: i64.load 0 +; CHECK: local.get 1 +; CHECK: i32.const __wasm_lpad_context +; CHECK: call __gxx_wasm_personality_v0 +; CHECK: drop + ; CHECK: block ; CHECK: br_if 0 ; CHECK: call __cxa_begin_catch diff --git a/llvm/test/CodeGen/WebAssembly/wasm-eh-invalid-personality.ll b/llvm/test/CodeGen/WebAssembly/wasm-eh-invalid-personality.ll index 1a4e888a26ef5..36340c1444525 100644 --- a/llvm/test/CodeGen/WebAssembly/wasm-eh-invalid-personality.ll +++ b/llvm/test/CodeGen/WebAssembly/wasm-eh-invalid-personality.ll @@ -6,7 +6,7 @@ target triple = "wasm32-unknown-unknown" ; not have a correct Wasm personality function. define void @test() personality ptr @invalid_personality { -; CHECK: LLVM ERROR: Function 'test' does not have a correct Wasm personality function '__gxx_wasm_personality_v0' +; CHECK: LLVM ERROR: Function 'test' does not have a supported Wasm personality function entry: invoke void @foo() to label %try.cont unwind label %catch.dispatch diff --git a/llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll b/llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll index 164c138cb7578..a88a6f01351e7 100644 --- a/llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll +++ b/llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll @@ -46,7 +46,10 @@ catch.start: ; preds = %catch.dispatch ; CHECK-NEXT: store i32 0, ptr @__wasm_lpad_context ; CHECK-NEXT: %[[LSDA:.*]] = call ptr @llvm.wasm.lsda() ; CHECK-NEXT: store ptr %[[LSDA]], ptr getelementptr inbounds ({ i32, ptr, i32 }, ptr @__wasm_lpad_context, i32 0, i32 1) -; CHECK-NEXT: call i32 @_Unwind_CallPersonality(ptr %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] +; CHECK-NEXT: store i32 0, ptr getelementptr inbounds ({ i32, ptr, i32 }, ptr @__wasm_lpad_context, i32 0, i32 2), align 4 +; CHECK-NEXT: %exception_class_gep = getelementptr inbounds { i64, ptr }, ptr %[[EXN]], i32 0, i32 0 +; CHECK-NEXT: %[[CLASS:.*]] = load i64, ptr %exception_class_gep, align 8 +; CHECK-NEXT: %{{.*}} = call i32 @__gxx_wasm_personality_v0(i32 1, i32 1, i64 %[[CLASS]], ptr %[[EXN]], ptr @__wasm_lpad_context) #{{.*}} [ "funclet"(token %[[CATCHPAD]]) ] ; CHECK-NEXT: %[[SELECTOR:.*]] = load i32, ptr getelementptr inbounds ({ i32, ptr, i32 }, ptr @__wasm_lpad_context, i32 0, i32 2) ; CHECK: icmp eq i32 %[[SELECTOR]] @@ -103,7 +106,7 @@ catch.start: ; preds = %catch.dispatch ; CHECK-NOT: call void @llvm.wasm.landingpad.index ; CHECK-NOT: store {{.*}} @__wasm_lpad_context ; CHECK-NOT: call ptr @llvm.wasm.lsda() -; CHECK-NOT: call i32 @_Unwind_CallPersonality +; CHECK-NOT: call i32 @__gxx_wasm_personality_v0 ; CHECK-NOT: load {{.*}} @__wasm_lpad_context try.cont: ; preds = %entry, %catch.start @@ -277,4 +280,4 @@ attributes #1 = { noreturn } ; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32 immarg) ; CHECK-DAG: declare ptr @llvm.wasm.lsda() -; CHECK-DAG: declare i32 @_Unwind_CallPersonality(ptr) +; CHECK-DAG: declare i32 @__gxx_wasm_personality_v0(...) >From 9cab568516ad238897974f1853e0213091e64569 Mon Sep 17 00:00:00 2001 From: hmelder <[email protected]> Date: Fri, 9 Jan 2026 16:18:45 +0000 Subject: [PATCH 4/5] [WebAssembly] Use uintptr_t in WasmEHPrepare WasmEHPrepare is used by both wasm32 and wasm64 targets. The fields in _Unwind_LandingPadContext are uintptr_t. Fix the fields, constants and offsets accordingly. --- llvm/lib/CodeGen/WasmEHPrepare.cpp | 52 ++++++++++++++++++------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp index ab75372a50b06..cb97da33edef9 100644 --- a/llvm/lib/CodeGen/WasmEHPrepare.cpp +++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp @@ -66,10 +66,12 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/WasmEHFuncInfo.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/EHPersonalities.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicsWebAssembly.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/RuntimeLibcalls.h" #include "llvm/InitializePasses.h" @@ -100,6 +102,11 @@ class WasmEHPrepareImpl { Function *GetSelectorF = nullptr; // wasm.get.ehselector() intrinsic FunctionCallee PersonalityF = nullptr; + IntegerType *Int32Ty = nullptr; + IntegerType *Int64Ty = nullptr; + PointerType *PtrTy = nullptr; + IntegerType *IntPtrTy = nullptr; + bool prepareThrows(Function &F); bool prepareEHPads(Function &F); void prepareEHPad(BasicBlock *BB, bool NeedPersonality, unsigned Index = 0); @@ -131,14 +138,14 @@ class WasmEHPrepare : public FunctionPass { PreservedAnalyses WasmEHPreparePass::run(Function &F, FunctionAnalysisManager &) { auto &Context = F.getContext(); - auto *I32Ty = Type::getInt32Ty(Context); + const DataLayout &DL = F.getParent()->getDataLayout(); auto *I64Ty = Type::getInt64Ty(Context); auto *PtrTy = PointerType::get(Context, 0); - auto *LPadContextTy = - StructType::get(I32Ty /*lpad_index*/, PtrTy /*lsda*/, I32Ty /*selector*/); - auto *UnwindExceptionTy = - StructType::get(I64Ty /* exception_class*/, PtrTy /* exception_cleanup */, - I32Ty /* private_1 */, I32Ty /* private_2 */); + auto *IntPtrTy = DL.getIntPtrType(Context, /*AddressSpace=*/0); + auto *LPadContextTy = StructType::get(IntPtrTy /*lpad_index*/, PtrTy /*lsda*/, + IntPtrTy /*selector*/); + auto *UnwindExceptionTy = StructType::get(I64Ty /* exception_class*/, + PtrTy /* exception_cleanup */); WasmEHPrepareImpl P(LPadContextTy, UnwindExceptionTy); bool Changed = P.runOnFunction(F); return Changed ? PreservedAnalyses::none() : PreservedAnalyses ::all(); @@ -154,16 +161,16 @@ FunctionPass *llvm::createWasmEHPass() { return new WasmEHPrepare(); } bool WasmEHPrepare::doInitialization(Module &M) { IRBuilder<> IRB(M.getContext()); - auto *I32Ty = IRB.getInt32Ty(); + const DataLayout &DL = M.getDataLayout(); auto *I64Ty = IRB.getInt64Ty(); auto *PtrTy = IRB.getPtrTy(); - P.LPadContextTy = StructType::get(I32Ty, // lpad_index - PtrTy, // lsda - I32Ty // selector - ); - P.UnwindExceptionTy = StructType::get(I64Ty, /* exception_class*/ - PtrTy /* exception_cleanup */ + auto *IntPtrTy = DL.getIntPtrType(M.getContext(), /*AddressSpace=*/0); + P.LPadContextTy = StructType::get(IntPtrTy, // lpad_index + PtrTy, // lsda + IntPtrTy // selector ); + P.UnwindExceptionTy = StructType::get(I64Ty /* exception_class*/, + PtrTy /* exception_cleanup */); return false; } @@ -239,8 +246,7 @@ bool WasmEHPrepareImpl::prepareEHPads(Function &F) { if (!isScopedEHPersonality(Personality)) { report_fatal_error("Function '" + F.getName() + - "' does not have a correct Wasm personality function " - "'__gxx_personality_wasm0'"); + "' does not have a supported Wasm personality function"); } assert(F.hasPersonalityFn() && "Personality function not found"); @@ -275,11 +281,15 @@ bool WasmEHPrepareImpl::prepareEHPads(Function &F) { // instruction selection. CatchF = Intrinsic::getOrInsertDeclaration(&M, Intrinsic::wasm_catch); - auto *I32Ty = IRB.getInt32Ty(); - auto *I64Ty = IRB.getInt64Ty(); - auto *PtrTy = IRB.getPtrTy(); - auto *PersPrototype = - FunctionType::get(I32Ty, {I32Ty, I32Ty, I64Ty, PtrTy, PtrTy}, false); + auto DL = F.getParent()->getDataLayout(); + + Int32Ty = IRB.getInt32Ty(); + Int64Ty = IRB.getInt64Ty(); + PtrTy = IRB.getPtrTy(); + IntPtrTy = DL.getIntPtrType(M.getContext(), /*AddressSpace=*/0); + + auto *PersPrototype = FunctionType::get( + Int32Ty, {Int32Ty, Int32Ty, Int64Ty, PtrTy, PtrTy}, false); PersonalityF = M.getOrInsertFunction(getEHPersonalityName(Personality), PersPrototype); @@ -366,7 +376,7 @@ void WasmEHPrepareImpl::prepareEHPad(BasicBlock *BB, bool NeedPersonality, IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField); // Pseudocode: __wasm_lpad_context.selector = 0; - IRB.CreateStore(IRB.getInt32(0), SelectorField); + IRB.CreateStore(ConstantInt::get(IntPtrTy, 0), SelectorField); // Pseudocode: &exn->exception_class auto *ExceptionClassPtr = IRB.CreateConstInBoundsGEP2_32( >From 47ca19431cbab3509c5b2454559be7dcae97a7ca Mon Sep 17 00:00:00 2001 From: hmelder <[email protected]> Date: Fri, 9 Jan 2026 16:50:31 +0000 Subject: [PATCH 5/5] [libcxxabi] Rename Wasm EH Personality Function There is a function name mismatch between the declarations in codegen and libcxxabi. This was never caught because the personality function was never directly called. --- libcxxabi/src/cxa_personality.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp index 77b2eb53af0e4..258e4d1f49444 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -1021,7 +1021,7 @@ static inline void get_landing_pad(__cxa_catch_temp_type &dest, } #ifdef __WASM_EXCEPTIONS__ -_Unwind_Reason_Code __gxx_personality_wasm0 +_Unwind_Reason_Code __gxx_wasm_personality_v0 #elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) static _Unwind_Reason_Code __gxx_personality_imp #else _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
