[clang] [libcxxabi] [libunwind] [llvm] [WebAssembly] Call EH personality function instead of `Unwind_CallPersonality` (PR #209282)
Demetrius Kanios via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 13 12:45:59 PDT 2026
https://github.com/QuantumSegfault updated https://github.com/llvm/llvm-project/pull/209282
>From 03a177003d05f9275a59ca6e6c79952abda782da Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Mon, 13 Jul 2026 12:30:49 -0700
Subject: [PATCH 1/2] Call declared personality function
---
clang/lib/CodeGen/CGException.cpp | 9 ++-
libcxxabi/src/cxa_personality.cpp | 22 ++++++-
libunwind/include/unwind.h | 4 ++
libunwind/include/unwind_wasm.h | 27 ++++++++
libunwind/src/Unwind-wasm.c | 39 -----------
libunwind/src/config.h | 2 +-
llvm/include/llvm/IR/RuntimeLibcalls.td | 4 --
llvm/lib/CodeGen/WasmEHPrepare.cpp | 64 ++++++++-----------
.../WebAssembly/cfg-stackify-eh-legacy.ll | 2 +-
.../WebAssembly/cfg-stackify-eh-legacy.mir | 2 +-
.../CodeGen/WebAssembly/cfg-stackify-eh.ll | 8 +--
llvm/test/CodeGen/WebAssembly/eh-lsda.ll | 2 +-
.../CodeGen/WebAssembly/exception-legacy.ll | 4 +-
.../CodeGen/WebAssembly/exception-legacy.mir | 2 +-
llvm/test/CodeGen/WebAssembly/exception.ll | 4 +-
.../CodeGen/WebAssembly/function-info.mir | 2 +-
.../WebAssembly/lower-wasm-ehsjlj-phi.ll | 2 +-
.../CodeGen/WebAssembly/lower-wasm-ehsjlj.ll | 2 +-
.../WebAssembly/wasm-eh-em-sjlj-error.ll | 2 +-
.../wasm-eh-invalid-personality.ll | 2 +-
.../CodeGen/WebAssembly/wasm-eh-prepare.ll | 8 +--
.../wasm-eh-sjlj-setjmp-within-catch.ll | 2 +-
22 files changed, 108 insertions(+), 107 deletions(-)
create mode 100644 libunwind/include/unwind_wasm.h
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 99dfaa80be429..25b57a0334413 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -265,7 +265,14 @@ const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) {
static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM,
const EHPersonality &Personality) {
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true),
+ llvm::FunctionType *FTy;
+
+ if (Personality.isWasmPersonality()) {
+ FTy = llvm::FunctionType::get(CGM.VoidTy, {CGM.VoidPtrTy}, false);
+ } else {
+ FTy = llvm::FunctionType::get(CGM.Int32Ty, true);
+ }
+ return CGM.CreateRuntimeFunction(FTy,
Personality.PersonalityFn,
llvm::AttributeList(), /*Local=*/true);
}
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 6599f89740113..970cd0355ddf4 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -1011,9 +1011,7 @@ static inline void get_landing_pad(__cxa_catch_temp_type &dest,
#endif
}
-#ifdef __WASM_EXCEPTIONS__
-_Unwind_Reason_Code __gxx_personality_wasm0
-#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#if (defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)) || defined(__WASM_EXCEPTIONS__)
static _Unwind_Reason_Code __gxx_personality_imp
#else
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
@@ -1114,6 +1112,24 @@ __gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
}
#endif
+
+#ifdef __WASM_EXCEPTIONS__
+extern "C" _LIBCXXABI_FUNC_VIS
+void __gxx_wasm_personality_v0(void* exception_ptr) {
+ struct _Unwind_Exception *exception_object =
+ (struct _Unwind_Exception *)exception_ptr;
+
+ // 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.
+ __gxx_personality_imp(
+ 1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)&__wasm_lpad_context);
+}
+#endif
+
#else
extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, _Unwind_Context*);
diff --git a/libunwind/include/unwind.h b/libunwind/include/unwind.h
index b1775d3a3decc..93a9d92f327d3 100644
--- a/libunwind/include/unwind.h
+++ b/libunwind/include/unwind.h
@@ -61,6 +61,10 @@ typedef struct _Unwind_Context _Unwind_Context; // opaque
#include <unwind_itanium.h>
#endif
+#if defined(__WASM_EXCEPTIONS__)
+#include <unwind_wasm.h>
+#endif
+
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(int version,
_Unwind_Action actions,
diff --git a/libunwind/include/unwind_wasm.h b/libunwind/include/unwind_wasm.h
new file mode 100644
index 0000000000000..7bf3f30562bd8
--- /dev/null
+++ b/libunwind/include/unwind_wasm.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __WASM_UNWIND_H__
+#define __WASM_UNWIND_H__
+
+#include <threads.h>
+
+struct _Unwind_LandingPadContext {
+ // Input information to personality function
+ uintptr_t lpad_index; // landing pad index
+ uintptr_t lsda; // LSDA address
+
+ // Output information computed by personality function
+ uintptr_t selector; // selector value
+};
+
+// Communication channel between compiler-generated user code and personality
+// function
+extern thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
+
+#endif // __WASM_UNWIND_H__
diff --git a/libunwind/src/Unwind-wasm.c b/libunwind/src/Unwind-wasm.c
index c0ca9b775d244..81793b3f36060 100644
--- a/libunwind/src/Unwind-wasm.c
+++ b/libunwind/src/Unwind-wasm.c
@@ -19,47 +19,8 @@
#include "unwind.h"
#include <threads.h>
-_Unwind_Reason_Code __gxx_personality_wasm0(int version, _Unwind_Action actions,
- uint64_t exceptionClass,
- _Unwind_Exception *unwind_exception,
- _Unwind_Context *context);
-
-struct _Unwind_LandingPadContext {
- // Input information to personality function
- uintptr_t lpad_index; // landing pad index
- uintptr_t lsda; // LSDA address
-
- // Output information computed by personality function
- uintptr_t selector; // selector value
-};
-
-// Communication channel between compiler-generated user code and personality
-// function
thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
-/// Calls to this function are 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 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/libunwind/src/config.h b/libunwind/src/config.h
index f017403fa2234..fd1aba25e6822 100644
--- a/libunwind/src/config.h
+++ b/libunwind/src/config.h
@@ -75,7 +75,7 @@
#define _LIBUNWIND_EXPORT
#define _LIBUNWIND_HIDDEN
#else
- #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX)
+ #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX) && !defined(__wasm__)
#define _LIBUNWIND_EXPORT __declspec(dllexport)
#define _LIBUNWIND_HIDDEN
#else
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index a7e45570c1b24..3745001b936f8 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -1849,9 +1849,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>;
@@ -3567,7 +3564,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 b83bcf67716f9..363e7221f7118 100644
--- a/llvm/lib/CodeGen/WasmEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp
@@ -28,7 +28,7 @@
// wasm.landingpad.index(index);
// __wasm_lpad_context.lpad_index = index;
// __wasm_lpad_context.lsda = wasm.lsda();
-// _Unwind_CallPersonality(exn);
+// personality_fn(exn);
// selector = __wasm_lpad_context.selector;
// ...
//
@@ -38,18 +38,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 +55,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.
//
//===----------------------------------------------------------------------===//
@@ -111,8 +94,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);
@@ -235,11 +217,14 @@ 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'");
+ "' does not have a supported Wasm personality function");
}
assert(F.hasPersonalityFn() && "Personality function not found");
@@ -274,15 +259,12 @@ 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);
+ auto *PersPrototype = FunctionType::get(
+ IRB.getInt32Ty(), {IRB.getPtrTy()}, false);
+ PersonalityF =
+ M.getOrInsertFunction(getEHPersonalityName(Personality), PersPrototype);
- // _Unwind_CallPersonality() wrapper function, which calls the personality
- CallPersonalityF = M.getOrInsertFunction(UnwindCallPersonalityName,
- IRB.getInt32Ty(), IRB.getPtrTy());
- if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee()))
+ if (Function *F = dyn_cast<Function>(PersonalityF.getCallee()))
F->setDoesNotThrow();
unsigned Index = 0;
@@ -367,9 +349,17 @@ 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: personality_fn(exn);
+ CallInst *PersCI;
+
+ // Grab direct function when possible to use `call` instead of `call_indirect`
+ if (Function *F = dyn_cast<Function>(PersonalityF.getCallee()))
+ PersCI = IRB.CreateCall(F, CatchCI,
+ OperandBundleDef("funclet", CPI));
+ else
+ PersCI = IRB.CreateCall(PersonalityF, CatchCI,
+ OperandBundleDef("funclet", CPI));
+
PersCI->setDoesNotThrow();
// Pseudocode: int selector = __wasm_lpad_context.selector;
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
index a35129effcdee..301f7d81a4274 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
@@ -1911,7 +1911,7 @@ declare ptr @_ZN7MyClassD2Ev(ptr returned) #0
; Function Attrs: nounwind
declare ptr @_ZN7MyClassC2ERKS_(ptr returned, ptr dereferenceable(4)) #0
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.mir b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.mir
index 324dd29f2295e..f0341ed420241 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.mir
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.mir
@@ -3,7 +3,7 @@
--- |
target triple = "wasm32-unknown-unknown"
- declare i32 @__gxx_wasm_personality_v0(...)
+ declare void @__gxx_wasm_personality_v0(ptr)
declare void @foo()
define void @rethrow_arg_test() personality ptr @__gxx_wasm_personality_v0 {
ret void
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
index a1e7616711ab9..a6611899806ea 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]+]]
@@ -1644,7 +1644,7 @@ declare ptr @_ZN7MyClassD2Ev(ptr returned) #0
; Function Attrs: nounwind
declare ptr @_ZN7MyClassC2ERKS_(ptr returned, ptr dereferenceable(4)) #0
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
index d5b28b279d419..0c0fa9f840601 100644
--- a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
+++ b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
@@ -251,6 +251,6 @@ declare i32 @llvm.wasm.get.ehselector(token) #0
declare void @__cxa_rethrow()
declare ptr @__cxa_begin_catch(ptr)
declare void @__cxa_end_catch()
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
attributes #0 = { nounwind }
diff --git a/llvm/test/CodeGen/WebAssembly/exception-legacy.ll b/llvm/test/CodeGen/WebAssembly/exception-legacy.ll
index 573f69df8b859..217da5c39e27f 100644
--- a/llvm/test/CodeGen/WebAssembly/exception-legacy.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception-legacy.ll
@@ -35,7 +35,7 @@ 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: call __gxx_wasm_personality_v0, $[[EXN]]
; CHECK: block
; CHECK: br_if 0
; CHECK: call $drop=, __cxa_begin_catch
@@ -547,7 +547,7 @@ try.cont: ; preds = %entry
declare void @foo()
declare void @bar(ptr)
declare void @take_i32(i32)
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: noreturn
declare void @llvm.wasm.throw(i32, ptr) #1
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/exception-legacy.mir b/llvm/test/CodeGen/WebAssembly/exception-legacy.mir
index 95929af4f4cea..7b8ba72ddfad9 100644
--- a/llvm/test/CodeGen/WebAssembly/exception-legacy.mir
+++ b/llvm/test/CodeGen/WebAssembly/exception-legacy.mir
@@ -3,7 +3,7 @@
--- |
target triple = "wasm32-unknown-unknown"
- declare i32 @__gxx_wasm_personality_v0(...)
+ declare void @__gxx_wasm_personality_v0(ptr)
declare void @foo()
define void @eh_label_test() personality ptr @__gxx_wasm_personality_v0 {
ret void
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index f738216d087ec..a972fceba4715 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -47,7 +47,7 @@ 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: call __gxx_wasm_personality_v0
; CHECK: block
; CHECK: br_if 0
; CHECK: call __cxa_begin_catch
@@ -648,7 +648,7 @@ try.cont: ; preds = %entry
declare void @foo()
declare void @bar(ptr)
declare void @take_i32(i32)
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: noreturn
declare void @llvm.wasm.throw(i32, ptr) #1
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/function-info.mir b/llvm/test/CodeGen/WebAssembly/function-info.mir
index b81cdffde819f..be87bad9ec72c 100644
--- a/llvm/test/CodeGen/WebAssembly/function-info.mir
+++ b/llvm/test/CodeGen/WebAssembly/function-info.mir
@@ -3,7 +3,7 @@
--- |
target triple = "wasm32-unknown-unknown"
- declare i32 @__gxx_wasm_personality_v0(...)
+ declare void @__gxx_wasm_personality_v0(ptr)
declare void @foo()
define void @function_property_test() {
ret void
diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj-phi.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj-phi.ll
index 5e8ebcf247000..b4ecb2911c89b 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj-phi.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj-phi.ll
@@ -110,7 +110,7 @@ ehcleanup: ; preds = %bb3, %catch.start,
}
declare i32 @setjmp(ptr)
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
declare void @foo()
declare void @longjmpable()
declare void @use_i32(i32)
diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
index d5ae37d7e98bc..37e98c6a302d1 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
@@ -299,7 +299,7 @@ declare ptr @_ZN4TempD2Ev(ptr %this) #2
declare i32 @setjmp(ptr) #0
; Function Attrs: noreturn
declare void @longjmp(ptr, i32) #1
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #2
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/wasm-eh-em-sjlj-error.ll b/llvm/test/CodeGen/WebAssembly/wasm-eh-em-sjlj-error.ll
index 35637a996e3ab..8547b68824ee6 100644
--- a/llvm/test/CodeGen/WebAssembly/wasm-eh-em-sjlj-error.ll
+++ b/llvm/test/CodeGen/WebAssembly/wasm-eh-em-sjlj-error.ll
@@ -30,7 +30,7 @@ try.cont: ; preds = %entry, %catch.start
}
declare void @foo()
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind
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..daa3bb0207b55 100644
--- a/llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll
+++ b/llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll
@@ -46,7 +46,7 @@ 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: call void @__gxx_wasm_personality_v0(ptr %[[EXN]]) {{.*}} [ "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 +103,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 void @__gxx_wasm_personality_v0
; CHECK-NOT: load {{.*}} @__wasm_lpad_context
try.cont: ; preds = %entry, %catch.start
@@ -257,7 +257,7 @@ merge: ; preds = %bb.true.0, %bb.fals
declare void @foo()
declare void @bar(i32)
declare ptr @_ZN4TempD2Ev(ptr returned)
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind
@@ -277,4 +277,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 void @__gxx_wasm_personality_v0(ptr)
diff --git a/llvm/test/CodeGen/WebAssembly/wasm-eh-sjlj-setjmp-within-catch.ll b/llvm/test/CodeGen/WebAssembly/wasm-eh-sjlj-setjmp-within-catch.ll
index ed9b62941a9c7..6cca5af633751 100644
--- a/llvm/test/CodeGen/WebAssembly/wasm-eh-sjlj-setjmp-within-catch.ll
+++ b/llvm/test/CodeGen/WebAssembly/wasm-eh-sjlj-setjmp-within-catch.ll
@@ -49,7 +49,7 @@ ehcleanup: ; preds = %catch
}
declare void @foo()
-declare i32 @__gxx_wasm_personality_v0(...)
+declare void @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind
>From f6d21590fc0d7ec1fe07daf8b24096d58bf60f3c Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Mon, 13 Jul 2026 12:45:05 -0700
Subject: [PATCH 2/2] Update comment per #206660
---
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 970cd0355ddf4..e697950840e99 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -1123,7 +1123,7 @@ void __gxx_wasm_personality_v0(void* exception_ptr) {
__wasm_lpad_context.selector = 0;
// Call personality function. Wasm does not have two-phase unwinding, so we
- // only do the cleanup phase.
+ // only do the search phase.
__gxx_personality_imp(
1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object,
(struct _Unwind_Context *)&__wasm_lpad_context);
More information about the cfe-commits
mailing list