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

Reply via email to