[WebAssembly] Call EH personality function instead of Unwind_CallPersonality (#209282)

On Wasm, it's not currently possibly to change which `personality` is
attached to a given IR function. This is primarily because no matter
what `personality` is attached, codegen creates a call to a
`Unwind_CallPersonality` wrapper hard-coded to call c++abi's
personality.

In order to allow alternative personalities without introducing bloat at
each personality call site, this PR adjusts the ABI of the personality
on Wasm. `Unwind_CallPersonality` is moved to `libcxxabi` under the name
`__gxx_wasm_personality_v0`, with the "real" personality code renamed
`__gxx_personality_imp` and called by `__gxx_wasm_personality_v0` (after
resetting the landing pad context).

The signature of EH personalities on Wasm is now `int personality(void*
exception_object)` (where the int return is `_Unwind_Reason_Code` and
the `void*` is `_Unwind_Exception*`), and personalities are expected to
`__wasm_lpad_context.selector = 0;`.

Based on #175202
This commit is contained in:
Demetrius Kanios 2026-07-28 20:05:45 -07:00 committed by GitHub
parent e73371acbc
commit 1d4e04f7a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 107 additions and 117 deletions

View file

@ -265,8 +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),
Personality.PersonalityFn,
llvm::FunctionType *FTy;
if (Personality.isWasmPersonality()) {
FTy = llvm::FunctionType::get(CGM.Int32Ty, {CGM.VoidPtrTy}, false);
} else {
FTy = llvm::FunctionType::get(CGM.Int32Ty, true);
}
return CGM.CreateRuntimeFunction(FTy, Personality.PersonalityFn,
llvm::AttributeList(), /*Local=*/true);
}

View file

@ -30,9 +30,8 @@ try.cont: ; preds = %entry, %catch.start
}
declare void @foo()
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare ptr @llvm.wasm.get.exception(token)
declare i32 @llvm.wasm.get.ehselector(token)
declare ptr @__cxa_begin_catch(ptr)
declare void @__cxa_end_catch()

View file

@ -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,20 @@ __gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
}
#endif
#ifdef __WASM_EXCEPTIONS__
extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __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 search phase.
return __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*);

View file

@ -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,

View file

@ -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__

View file

@ -19,46 +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 search phase.
return __gxx_personality_wasm0(
1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object,
(struct _Unwind_Context *)&__wasm_lpad_context);
}
_LIBUNWIND_EXPORT thread_local struct _Unwind_LandingPadContext
__wasm_lpad_context;
/// Called by __cxa_throw.
_LIBUNWIND_EXPORT _Unwind_Reason_Code

View file

@ -1785,9 +1785,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>;
@ -3525,7 +3522,6 @@ def WasmSystemLibrary
(add DefaultRuntimeLibcallImpls, Int128RTLibcalls,
CompilerRTOnlyInt64Libcalls, CompilerRTOnlyInt128Libcalls,
exp10f, exp10,
_Unwind_CallPersonality,
emscripten_return_address,
LibcallImpls<(add __small_printf,
__small_sprintf,

View file

@ -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;
// ...
//
@ -39,9 +39,9 @@
// 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.
// function (e.g. in libcxxabi) cannot be called from libunwind during the
// unwinding process. So after a catch instruction, we insert a direct call to
// the personality instead.
//
// 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
@ -49,7 +49,7 @@
// 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 +60,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 +99,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 +222,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 +264,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 +354,9 @@ 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 =
IRB.CreateCall(PersonalityF, CatchCI, OperandBundleDef("funclet", CPI));
PersCI->setDoesNotThrow();
// Pseudocode: int selector = __wasm_lpad_context.selector;

View file

@ -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 i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind

View file

@ -3,7 +3,7 @@
--- |
target triple = "wasm32-unknown-unknown"
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare void @foo()
define void @rethrow_arg_test() personality ptr @__gxx_wasm_personality_v0 {
ret void

View file

@ -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 i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind

View file

@ -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 i32 @__gxx_wasm_personality_v0(ptr)
attributes #0 = { nounwind }

View file

@ -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 $drop=, __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 i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: noreturn
declare void @llvm.wasm.throw(i32, ptr) #1
; Function Attrs: nounwind

View file

@ -3,7 +3,7 @@
--- |
target triple = "wasm32-unknown-unknown"
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare void @foo()
define void @eh_label_test() personality ptr @__gxx_wasm_personality_v0 {
ret void

View file

@ -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 i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: noreturn
declare void @llvm.wasm.throw(i32, ptr) #1
; Function Attrs: nounwind

View file

@ -3,7 +3,7 @@
--- |
target triple = "wasm32-unknown-unknown"
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare void @foo()
define void @function_property_test() {
ret void

View file

@ -110,7 +110,7 @@ ehcleanup: ; preds = %bb3, %catch.start,
}
declare i32 @setjmp(ptr)
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare void @foo()
declare void @longjmpable()
declare void @use_i32(i32)

View file

@ -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 i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #2
; Function Attrs: nounwind

View file

@ -30,7 +30,7 @@ try.cont: ; preds = %entry, %catch.start
}
declare void @foo()
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind

View file

@ -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

View file

@ -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 i32 @__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 i32 @__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 i32 @__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 i32 @__gxx_wasm_personality_v0(ptr)

View file

@ -49,7 +49,7 @@ ehcleanup: ; preds = %catch
}
declare void @foo()
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nounwind
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nounwind

View file

@ -65,7 +65,7 @@ try.cont: ; preds = %entry, %catch
declare void @may_throw(...)
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn
declare ptr @llvm.wasm.get.exception(token)
@ -85,5 +85,3 @@ declare void @__cxa_end_catch()
; Function Attrs: noreturn
declare void @llvm.wasm.rethrow()

View file

@ -10,7 +10,7 @@ target triple = "wasm32-unknown-unknown"
declare void @foo()
declare void @bar(ptr)
declare i32 @baz()
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: noreturn
declare void @llvm.wasm.rethrow() #0

View file

@ -30,7 +30,7 @@ try.cont: ; preds = %catch.start, %entry
}
declare void @foo()
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
; Function Attrs: nocallback nofree nosync nounwind willreturn
declare ptr @llvm.wasm.get.exception(token) #0
; Function Attrs: nocallback nofree nosync nounwind willreturn

View file

@ -6,7 +6,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
%struct.foo = type { i32 }
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare void @foo()
; Tests if the SROA pass correctly bails out on rewriting PHIs in a catchswitch

View file

@ -2,7 +2,7 @@
; CHECK: if.end{{.*}}:
; CHECK-NOT: if.end{{.*}}:
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)
declare void @foo()
@ -30,4 +30,3 @@ catch: ; preds = %catch.dispatch
cleanup: ; preds = %invoke.cont
br label %while.body
}

View file

@ -40,4 +40,4 @@ catch: ; preds = %catchswitch
declare void @foo()
declare void @bar(i32, i32)
declare i32 @__gxx_wasm_personality_v0(...)
declare i32 @__gxx_wasm_personality_v0(ptr)