mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
[WebAssembly] Disable wasm.lsda() optimization in WasmEHPrepare
In every catchpad except `catch (...)`, we add a call to `_Unwind_CallPersonality`, which is a wapper to call the personality function. (In most of other Itanium-based architectures the call is done from libunwind, but in wasm we don't have the control over the VM.) Because the personatlity function is called to figure out whether the current exception is a type we should catch, such as `int` or `SomeClass&`, `catch (...)` does not need the personality function call. For the same reason, all cleanuppads don't need it. When we call `_Unwind_CallPersonality`, we store some necessary info in a data structure called `__wasm_lpad_context` of type `_Unwind_LandingPadContext`, which is defined in the wasm's port of libunwind in Emscripten. Also the personality wrapper function returns some info (selector and the caught pointer) in that data structure, so it is used as a medium for communication. One of the info we need to store is the address for LSDA info for the current function. `wasm.lsda()` intrinsic returns that address. (This intrinsic will be lowered to a symbol that points to the LSDA address.) The simpliest thing is call `wasm.lsda()` every time we need to call `_Unwind_CallPersonality` and store that info in `__wasm_lpad_context` data structure. But we tried to be better than that (D77423 and some more previous CLs), so if catchpad A dominates catchpad B and catchpad A is not `catch (...)`, we didn't insert `wasm.lsda()` call in catchpad B, thinking that the LSDA address is the same for a single function and we already visited catchpad A and `__wasm_lpad_context.lsda` field would already have that value. But this can be incorrect if there is a call to another function, which also can have the personality function and LSDA, between catchpad A and catchpad B, because `__wasm_lpad_context` is a globally defined structure and the callee function will overwrite its `lsda` field. So in this CL we don't try to do any optimizaions on adding `wasm.lsda()` call; we store the result of `wasm.lsda()` every time we call `_Unwind_CallPersonality`. We can do some complicated analysis, like checking if there is a function call between the dominating catchpad and the current catchpad, but at this time it seems overkill. This deletes three tests because they all tested `wasm.ldsa()` call optimization. Fixes https://github.com/emscripten-core/emscripten/issues/13548. Reviewed By: tlively Differential Revision: https://reviews.llvm.org/D97309
This commit is contained in:
parent
9c426fd3a4
commit
bf4a14e46a
@ -77,7 +77,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/BreadthFirstIterator.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
@ -117,13 +116,9 @@ class WasmEHPrepare : public FunctionPass {
|
||||
FunctionCallee CallPersonalityF =
|
||||
nullptr; // _Unwind_CallPersonality() wrapper
|
||||
|
||||
bool prepareEHPads(Function &F);
|
||||
bool prepareThrows(Function &F);
|
||||
|
||||
bool IsEHPadFunctionsSetUp = false;
|
||||
void setupEHPadFunctions(Function &F);
|
||||
void prepareEHPad(BasicBlock *BB, bool NeedPersonality, bool NeedLSDA = false,
|
||||
unsigned Index = 0);
|
||||
bool prepareEHPads(Function &F);
|
||||
void prepareEHPad(BasicBlock *BB, bool NeedPersonality, unsigned Index = 0);
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
@ -176,7 +171,6 @@ static void eraseDeadBBsAndChildren(const Container &BBs, DomTreeUpdater *DTU) {
|
||||
}
|
||||
|
||||
bool WasmEHPrepare::runOnFunction(Function &F) {
|
||||
IsEHPadFunctionsSetUp = false;
|
||||
bool Changed = false;
|
||||
Changed |= prepareThrows(F);
|
||||
Changed |= prepareEHPads(F);
|
||||
@ -216,95 +210,23 @@ bool WasmEHPrepare::prepareThrows(Function &F) {
|
||||
}
|
||||
|
||||
bool WasmEHPrepare::prepareEHPads(Function &F) {
|
||||
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
||||
bool Changed = false;
|
||||
|
||||
// There are two things to decide: whether we need a personality function call
|
||||
// and whether we need a `wasm.lsda()` call and its store.
|
||||
//
|
||||
// For the personality function call, catchpads with `catch (...)` and
|
||||
// cleanuppads don't need it, because exceptions are always caught. Others all
|
||||
// need it.
|
||||
//
|
||||
// For `wasm.lsda()` and its store, in order to minimize the number of them,
|
||||
// we need a way to figure out whether we have encountered `wasm.lsda()` call
|
||||
// in any of EH pads that dominates the current EH pad. To figure that out, we
|
||||
// now visit EH pads in BFS order in the dominator tree so that we visit
|
||||
// parent BBs first before visiting its child BBs in the domtree.
|
||||
//
|
||||
// We keep a set named `ExecutedLSDA`, which basically means "Do we have
|
||||
// `wasm.lsda() either in the current EH pad or any of its parent EH pads in
|
||||
// the dominator tree?". This is to prevent scanning the domtree up to the
|
||||
// root every time we examine an EH pad, in the worst case: each EH pad only
|
||||
// needs to check its immediate parent EH pad.
|
||||
//
|
||||
// - If any of its parent EH pads in the domtree has `wasm.lsda`, this means
|
||||
// we don't need `wasm.lsda()` in the current EH pad. We also insert the
|
||||
// current EH pad in `ExecutedLSDA` set.
|
||||
// - If none of its parent EH pad has `wasm.lsda()`,
|
||||
// - If the current EH pad is a `catch (...)` or a cleanuppad, done.
|
||||
// - If the current EH pad is neither a `catch (...)` nor a cleanuppad,
|
||||
// add `wasm.lsda()` and the store in the current EH pad, and add the
|
||||
// current EH pad to `ExecutedLSDA` set.
|
||||
//
|
||||
// TODO Can we not store LSDA address in user function but make libcxxabi
|
||||
// compute it?
|
||||
DenseSet<Value *> ExecutedLSDA;
|
||||
unsigned Index = 0;
|
||||
for (auto DomNode : breadth_first(&DT)) {
|
||||
auto *BB = DomNode->getBlock();
|
||||
auto *Pad = BB->getFirstNonPHI();
|
||||
if (!Pad || (!isa<CatchPadInst>(Pad) && !isa<CleanupPadInst>(Pad)))
|
||||
continue;
|
||||
Changed = true;
|
||||
|
||||
Value *ParentPad = nullptr;
|
||||
if (CatchPadInst *CPI = dyn_cast<CatchPadInst>(Pad)) {
|
||||
ParentPad = CPI->getCatchSwitch()->getParentPad();
|
||||
if (ExecutedLSDA.count(ParentPad)) {
|
||||
ExecutedLSDA.insert(CPI);
|
||||
// We insert its associated catchswitch too, because
|
||||
// FuncletPadInst::getParentPad() returns a CatchSwitchInst if the child
|
||||
// FuncletPadInst is a CleanupPadInst.
|
||||
ExecutedLSDA.insert(CPI->getCatchSwitch());
|
||||
}
|
||||
} else { // CleanupPadInst
|
||||
ParentPad = cast<CleanupPadInst>(Pad)->getParentPad();
|
||||
if (ExecutedLSDA.count(ParentPad))
|
||||
ExecutedLSDA.insert(Pad);
|
||||
}
|
||||
|
||||
if (CatchPadInst *CPI = dyn_cast<CatchPadInst>(Pad)) {
|
||||
if (CPI->getNumArgOperands() == 1 &&
|
||||
cast<Constant>(CPI->getArgOperand(0))->isNullValue())
|
||||
// In case of a single catch (...), we need neither personality call nor
|
||||
// wasm.lsda() call
|
||||
prepareEHPad(BB, false);
|
||||
else {
|
||||
if (ExecutedLSDA.count(CPI))
|
||||
// catch (type), but one of parents already has wasm.lsda() call
|
||||
prepareEHPad(BB, true, false, Index++);
|
||||
else {
|
||||
// catch (type), and none of parents has wasm.lsda() call. We have to
|
||||
// add the call in this EH pad, and record this EH pad in
|
||||
// ExecutedLSDA.
|
||||
ExecutedLSDA.insert(CPI);
|
||||
ExecutedLSDA.insert(CPI->getCatchSwitch());
|
||||
prepareEHPad(BB, true, true, Index++);
|
||||
}
|
||||
}
|
||||
} else if (isa<CleanupPadInst>(Pad)) {
|
||||
// Cleanup pads need neither personality call nor wasm.lsda() call
|
||||
prepareEHPad(BB, false);
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
void WasmEHPrepare::setupEHPadFunctions(Function &F) {
|
||||
Module &M = *F.getParent();
|
||||
IRBuilder<> IRB(F.getContext());
|
||||
|
||||
SmallVector<BasicBlock *, 16> CatchPads;
|
||||
SmallVector<BasicBlock *, 16> CleanupPads;
|
||||
for (BasicBlock &BB : F) {
|
||||
if (!BB.isEHPad())
|
||||
continue;
|
||||
auto *Pad = BB.getFirstNonPHI();
|
||||
if (isa<CatchPadInst>(Pad))
|
||||
CatchPads.push_back(&BB);
|
||||
else if (isa<CleanupPadInst>(Pad))
|
||||
CleanupPads.push_back(&BB);
|
||||
}
|
||||
if (CatchPads.empty() && CleanupPads.empty())
|
||||
return false;
|
||||
|
||||
assert(F.hasPersonalityFn() && "Personality function not found");
|
||||
|
||||
// __wasm_lpad_context global variable
|
||||
@ -336,16 +258,30 @@ void WasmEHPrepare::setupEHPadFunctions(Function &F) {
|
||||
"_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy());
|
||||
if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee()))
|
||||
F->setDoesNotThrow();
|
||||
|
||||
unsigned Index = 0;
|
||||
for (auto *BB : CatchPads) {
|
||||
auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
|
||||
// In case of a single catch (...), we don't need to emit a personalify
|
||||
// function call
|
||||
if (CPI->getNumArgOperands() == 1 &&
|
||||
cast<Constant>(CPI->getArgOperand(0))->isNullValue())
|
||||
prepareEHPad(BB, false);
|
||||
else
|
||||
prepareEHPad(BB, true, Index++);
|
||||
}
|
||||
|
||||
// Cleanup pads don't need a personality function call.
|
||||
for (auto *BB : CleanupPads)
|
||||
prepareEHPad(BB, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prepare an EH pad for Wasm EH handling. If NeedPersonality is false, Index is
|
||||
// ignored.
|
||||
void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
|
||||
bool NeedLSDA, unsigned Index) {
|
||||
if (!IsEHPadFunctionsSetUp) {
|
||||
IsEHPadFunctionsSetUp = true;
|
||||
setupEHPadFunctions(*BB->getParent());
|
||||
}
|
||||
unsigned Index) {
|
||||
assert(BB->isEHPad() && "BB is not an EHPad!");
|
||||
IRBuilder<> IRB(BB->getContext());
|
||||
IRB.SetInsertPoint(&*BB->getFirstInsertionPt());
|
||||
@ -399,7 +335,9 @@ void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
|
||||
IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
|
||||
|
||||
auto *CPI = cast<CatchPadInst>(FPI);
|
||||
if (NeedLSDA)
|
||||
// TODO Sometimes storing the LSDA address every time is not necessary, in
|
||||
// case it is already set in a dominating EH pad and there is no function call
|
||||
// between from that EH pad to here. Consider optimizing those cases.
|
||||
// Pseudocode: __wasm_lpad_context.lsda = wasm.lsda();
|
||||
IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
|
||||
|
||||
|
@ -132,310 +132,18 @@ try.cont7: ; preds = %try.cont, %catch4
|
||||
ret void
|
||||
}
|
||||
|
||||
; A nested try-catch within a catch. The outer catch catches 'int'.
|
||||
;
|
||||
; void foo();
|
||||
; void test2() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
; Within the nested catchpad, wasm.lsda() call should NOT be generated.
|
||||
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test2()
|
||||
entry:
|
||||
invoke void @foo()
|
||||
to label %try.cont9 unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%0 = catchswitch within none [label %catch.start] unwind to caller
|
||||
|
||||
catch.start: ; preds = %catch.dispatch
|
||||
%1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
|
||||
%2 = call i8* @llvm.wasm.get.exception(token %1)
|
||||
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
|
||||
%4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
|
||||
%matches = icmp eq i32 %3, %4
|
||||
br i1 %matches, label %catch, label %rethrow
|
||||
; CHECK: catch.start:
|
||||
; CHECK: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch: ; preds = %catch.start
|
||||
%5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
|
||||
invoke void @foo() [ "funclet"(token %1) ]
|
||||
to label %try.cont unwind label %catch.dispatch2
|
||||
|
||||
catch.dispatch2: ; preds = %catch
|
||||
%6 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup
|
||||
|
||||
catch.start3: ; preds = %catch.dispatch2
|
||||
%7 = catchpad within %6 [i8* bitcast (i8** @_ZTIi to i8*)]
|
||||
%8 = call i8* @llvm.wasm.get.exception(token %7)
|
||||
%9 = call i32 @llvm.wasm.get.ehselector(token %7)
|
||||
%10 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
|
||||
%matches4 = icmp eq i32 %9, %10
|
||||
br i1 %matches4, label %catch6, label %rethrow5
|
||||
; CHECK: catch.start3:
|
||||
; CHECK-NOT: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch6: ; preds = %catch.start3
|
||||
%11 = call i8* @__cxa_begin_catch(i8* %8) [ "funclet"(token %7) ]
|
||||
call void @__cxa_end_catch() [ "funclet"(token %7) ]
|
||||
catchret from %7 to label %try.cont
|
||||
|
||||
rethrow5: ; preds = %catch.start3
|
||||
invoke void @llvm.wasm.rethrow() [ "funclet"(token %7) ]
|
||||
to label %unreachable unwind label %ehcleanup
|
||||
|
||||
try.cont: ; preds = %catch, %catch6
|
||||
call void @__cxa_end_catch() [ "funclet"(token %1) ]
|
||||
catchret from %1 to label %try.cont9
|
||||
|
||||
rethrow: ; preds = %catch.start
|
||||
call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
|
||||
unreachable
|
||||
|
||||
try.cont9: ; preds = %entry, %try.cont
|
||||
ret void
|
||||
|
||||
ehcleanup: ; preds = %rethrow5, %catch.dispatch2
|
||||
%12 = cleanuppad within %1 []
|
||||
call void @__cxa_end_catch() [ "funclet"(token %12) ]
|
||||
cleanupret from %12 unwind to caller
|
||||
; CHECK: ehcleanup:
|
||||
; CHECK-NEXT: cleanuppad
|
||||
; CHECK-NOT: call void @llvm.wasm.landingpad.index
|
||||
; CHECK-NOT: store {{.*}} @__wasm_lpad_context
|
||||
; CHECK-NOT: call i8* @llvm.wasm.lsda()
|
||||
; CHECK-NOT: call i32 @_Unwind_CallPersonality
|
||||
; CHECK-NOT: load {{.*}} @__wasm_lpad_context
|
||||
|
||||
unreachable: ; preds = %rethrow5
|
||||
unreachable
|
||||
}
|
||||
|
||||
; A nested try-catch within a catch. The outer catch is (...).
|
||||
;
|
||||
; void foo();
|
||||
; void test2() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
; Within the innermost catchpad, wasm.lsda() call should be generated, because
|
||||
; the outer catch is 'catch (...)', which does not need wasm.lsda() call.
|
||||
define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test3()
|
||||
entry:
|
||||
invoke void @foo()
|
||||
to label %try.cont8 unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%0 = catchswitch within none [label %catch.start] unwind to caller
|
||||
|
||||
catch.start: ; preds = %catch.dispatch
|
||||
%1 = catchpad within %0 [i8* null]
|
||||
%2 = call i8* @llvm.wasm.get.exception(token %1)
|
||||
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
|
||||
%4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
|
||||
invoke void @foo() [ "funclet"(token %1) ]
|
||||
to label %try.cont unwind label %catch.dispatch2
|
||||
; CHECK: catch.start:
|
||||
; CHECK-NOT: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch.dispatch2: ; preds = %catch.start
|
||||
%5 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup
|
||||
|
||||
catch.start3: ; preds = %catch.dispatch2
|
||||
%6 = catchpad within %5 [i8* bitcast (i8** @_ZTIi to i8*)]
|
||||
%7 = call i8* @llvm.wasm.get.exception(token %6)
|
||||
%8 = call i32 @llvm.wasm.get.ehselector(token %6)
|
||||
%9 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
|
||||
%matches = icmp eq i32 %8, %9
|
||||
br i1 %matches, label %catch4, label %rethrow
|
||||
; CHECK: catch.start3:
|
||||
; CHECK: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch4: ; preds = %catch.start3
|
||||
%10 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ]
|
||||
%11 = bitcast i8* %10 to i32*
|
||||
%12 = load i32, i32* %11, align 4
|
||||
call void @__cxa_end_catch() [ "funclet"(token %6) ]
|
||||
catchret from %6 to label %try.cont
|
||||
|
||||
rethrow: ; preds = %catch.start3
|
||||
invoke void @llvm.wasm.rethrow() [ "funclet"(token %6) ]
|
||||
to label %unreachable unwind label %ehcleanup
|
||||
|
||||
try.cont: ; preds = %catch.start, %catch4
|
||||
call void @__cxa_end_catch() [ "funclet"(token %1) ]
|
||||
catchret from %1 to label %try.cont8
|
||||
|
||||
try.cont8: ; preds = %entry, %try.cont
|
||||
ret void
|
||||
|
||||
ehcleanup: ; preds = %rethrow, %catch.dispatch2
|
||||
%13 = cleanuppad within %1 []
|
||||
invoke void @__cxa_end_catch() [ "funclet"(token %13) ]
|
||||
to label %invoke.cont6 unwind label %terminate
|
||||
|
||||
invoke.cont6: ; preds = %ehcleanup
|
||||
cleanupret from %13 unwind to caller
|
||||
|
||||
unreachable: ; preds = %rethrow
|
||||
unreachable
|
||||
|
||||
terminate: ; preds = %ehcleanup
|
||||
%14 = cleanuppad within %13 []
|
||||
%15 = call i8* @llvm.wasm.get.exception(token %14)
|
||||
call void @__clang_call_terminate(i8* %15) [ "funclet"(token %14) ]
|
||||
unreachable
|
||||
}
|
||||
|
||||
; void foo();
|
||||
; void test4() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
; wasm.lsda() call should be generated only once in the outermost catchpad. The
|
||||
; innermost 'catch (int)' can reuse the wasm.lsda() generated in the outermost
|
||||
; catch.
|
||||
define void @test4() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test4()
|
||||
entry:
|
||||
invoke void @foo()
|
||||
to label %try.cont19 unwind label %catch.dispatch
|
||||
|
||||
catch.dispatch: ; preds = %entry
|
||||
%0 = catchswitch within none [label %catch.start] unwind to caller
|
||||
|
||||
catch.start: ; preds = %catch.dispatch
|
||||
%1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
|
||||
%2 = call i8* @llvm.wasm.get.exception(token %1)
|
||||
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
|
||||
%4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
|
||||
%matches = icmp eq i32 %3, %4
|
||||
br i1 %matches, label %catch, label %rethrow
|
||||
; CHECK: catch.start:
|
||||
; CHECK: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch: ; preds = %catch.start
|
||||
%5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
|
||||
%6 = bitcast i8* %5 to i32*
|
||||
%7 = load i32, i32* %6, align 4
|
||||
invoke void @foo() [ "funclet"(token %1) ]
|
||||
to label %try.cont16 unwind label %catch.dispatch2
|
||||
|
||||
catch.dispatch2: ; preds = %catch
|
||||
%8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup17
|
||||
|
||||
catch.start3: ; preds = %catch.dispatch2
|
||||
%9 = catchpad within %8 [i8* null]
|
||||
%10 = call i8* @llvm.wasm.get.exception(token %9)
|
||||
%11 = call i32 @llvm.wasm.get.ehselector(token %9)
|
||||
%12 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ]
|
||||
invoke void @foo() [ "funclet"(token %9) ]
|
||||
to label %try.cont unwind label %catch.dispatch7
|
||||
; CHECK: catch.start3:
|
||||
; CHECK-NOT: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch.dispatch7: ; preds = %catch.start3
|
||||
%13 = catchswitch within %9 [label %catch.start8] unwind label %ehcleanup
|
||||
|
||||
catch.start8: ; preds = %catch.dispatch7
|
||||
%14 = catchpad within %13 [i8* bitcast (i8** @_ZTIi to i8*)]
|
||||
%15 = call i8* @llvm.wasm.get.exception(token %14)
|
||||
%16 = call i32 @llvm.wasm.get.ehselector(token %14)
|
||||
%17 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
|
||||
%matches9 = icmp eq i32 %16, %17
|
||||
br i1 %matches9, label %catch11, label %rethrow10
|
||||
; CHECK: catch.start8:
|
||||
; CHECK-NOT: call i8* @llvm.wasm.lsda()
|
||||
|
||||
catch11: ; preds = %catch.start8
|
||||
%18 = call i8* @__cxa_begin_catch(i8* %15) [ "funclet"(token %14) ]
|
||||
%19 = bitcast i8* %18 to i32*
|
||||
%20 = load i32, i32* %19, align 4
|
||||
call void @__cxa_end_catch() [ "funclet"(token %14) ]
|
||||
catchret from %14 to label %try.cont
|
||||
|
||||
rethrow10: ; preds = %catch.start8
|
||||
invoke void @llvm.wasm.rethrow() [ "funclet"(token %14) ]
|
||||
to label %unreachable unwind label %ehcleanup
|
||||
|
||||
try.cont: ; preds = %catch.start3, %catch11
|
||||
invoke void @__cxa_end_catch() [ "funclet"(token %9) ]
|
||||
to label %invoke.cont13 unwind label %ehcleanup17
|
||||
|
||||
invoke.cont13: ; preds = %try.cont
|
||||
catchret from %9 to label %try.cont16
|
||||
|
||||
try.cont16: ; preds = %catch, %invoke.cont13
|
||||
call void @__cxa_end_catch() [ "funclet"(token %1) ]
|
||||
catchret from %1 to label %try.cont19
|
||||
|
||||
rethrow: ; preds = %catch.start
|
||||
call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
|
||||
unreachable
|
||||
|
||||
try.cont19: ; preds = %entry, %try.cont16
|
||||
ret void
|
||||
|
||||
ehcleanup: ; preds = %rethrow10, %catch.dispatch7
|
||||
%21 = cleanuppad within %9 []
|
||||
invoke void @__cxa_end_catch() [ "funclet"(token %21) ]
|
||||
to label %invoke.cont14 unwind label %terminate
|
||||
|
||||
invoke.cont14: ; preds = %ehcleanup
|
||||
cleanupret from %21 unwind label %ehcleanup17
|
||||
|
||||
ehcleanup17: ; preds = %invoke.cont14, %try.cont, %catch.dispatch2
|
||||
%22 = cleanuppad within %1 []
|
||||
call void @__cxa_end_catch() [ "funclet"(token %22) ]
|
||||
cleanupret from %22 unwind to caller
|
||||
|
||||
unreachable: ; preds = %rethrow10
|
||||
unreachable
|
||||
|
||||
terminate: ; preds = %ehcleanup
|
||||
%23 = cleanuppad within %21 []
|
||||
%24 = call i8* @llvm.wasm.get.exception(token %23)
|
||||
call void @__clang_call_terminate(i8* %24) [ "funclet"(token %23) ]
|
||||
unreachable
|
||||
}
|
||||
|
||||
; A cleanuppad with a call to __clang_call_terminate().
|
||||
;
|
||||
; void foo();
|
||||
; void test5() {
|
||||
; void test2() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; foo();
|
||||
; }
|
||||
; }
|
||||
define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test5
|
||||
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test2
|
||||
entry:
|
||||
invoke void @foo()
|
||||
to label %try.cont unwind label %catch.dispatch
|
||||
@ -486,7 +194,7 @@ terminate: ; preds = %ehcleanup
|
||||
; ~Temp() {}
|
||||
; };
|
||||
;
|
||||
; void test6() {
|
||||
; void test3() {
|
||||
; int num;
|
||||
; try {
|
||||
; Temp t;
|
||||
@ -506,8 +214,8 @@ terminate: ; preds = %ehcleanup
|
||||
; bar(num);
|
||||
; }
|
||||
; }
|
||||
define void @test6() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test6
|
||||
define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test3
|
||||
entry:
|
||||
%t = alloca %struct.Temp, align 1
|
||||
invoke void @foo()
|
||||
@ -571,8 +279,8 @@ try.cont10: ; preds = %invoke.cont3, %catc
|
||||
; Tests if instructions after a call to @llvm.wasm.throw are deleted and the
|
||||
; BB's dead children are deleted.
|
||||
|
||||
; CHECK-LABEL: @test7
|
||||
define i32 @test7(i1 %b, i8* %p) {
|
||||
; CHECK-LABEL: @test4
|
||||
define i32 @test4(i1 %b, i8* %p) {
|
||||
entry:
|
||||
br i1 %b, label %bb.true, label %bb.false
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user