forked from OSchip/llvm-project
Convert Clang over to resuming from landing pads with llvm.eh.resume.
It's quite likely that this will explode, but I need to know how. :) llvm-svn: 132269
This commit is contained in:
parent
6528a54946
commit
9b382dde92
|
@ -112,11 +112,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
|
|||
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
|
||||
}
|
||||
|
||||
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
|
||||
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
|
||||
llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy,
|
||||
/*IsVarArgs=*/false);
|
||||
llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
|
||||
|
||||
if (CGM.getLangOptions().SjLjExceptions)
|
||||
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
|
||||
return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume");
|
||||
}
|
||||
|
||||
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
|
||||
|
||||
if (CGM.getLangOptions().SjLjExceptions)
|
||||
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
|
||||
|
@ -354,13 +361,17 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
|
|||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::getExceptionSlot() {
|
||||
if (!ExceptionSlot) {
|
||||
const llvm::Type *i8p = llvm::Type::getInt8PtrTy(getLLVMContext());
|
||||
ExceptionSlot = CreateTempAlloca(i8p, "exn.slot");
|
||||
}
|
||||
if (!ExceptionSlot)
|
||||
ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");
|
||||
return ExceptionSlot;
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::getEHSelectorSlot() {
|
||||
if (!EHSelectorSlot)
|
||||
EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");
|
||||
return EHSelectorSlot;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
|
||||
if (!E->getSubExpr()) {
|
||||
if (getInvokeDest()) {
|
||||
|
@ -563,47 +574,59 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
|
|||
return LP;
|
||||
}
|
||||
|
||||
// This code contains a hack to work around a design flaw in
|
||||
// LLVM's EH IR which breaks semantics after inlining. This same
|
||||
// hack is implemented in llvm-gcc.
|
||||
//
|
||||
// The LLVM EH abstraction is basically a thin veneer over the
|
||||
// traditional GCC zero-cost design: for each range of instructions
|
||||
// in the function, there is (at most) one "landing pad" with an
|
||||
// associated chain of EH actions. A language-specific personality
|
||||
// function interprets this chain of actions and (1) decides whether
|
||||
// or not to resume execution at the landing pad and (2) if so,
|
||||
// provides an integer indicating why it's stopping. In LLVM IR,
|
||||
// the association of a landing pad with a range of instructions is
|
||||
// achieved via an invoke instruction, the chain of actions becomes
|
||||
// the arguments to the @llvm.eh.selector call, and the selector
|
||||
// call returns the integer indicator. Other than the required
|
||||
// presence of two intrinsic function calls in the landing pad,
|
||||
// the IR exactly describes the layout of the output code.
|
||||
//
|
||||
// A principal advantage of this design is that it is completely
|
||||
// language-agnostic; in theory, the LLVM optimizers can treat
|
||||
// landing pads neutrally, and targets need only know how to lower
|
||||
// the intrinsics to have a functioning exceptions system (assuming
|
||||
// that platform exceptions follow something approximately like the
|
||||
// GCC design). Unfortunately, landing pads cannot be combined in a
|
||||
// language-agnostic way: given selectors A and B, there is no way
|
||||
// to make a single landing pad which faithfully represents the
|
||||
// semantics of propagating an exception first through A, then
|
||||
// through B, without knowing how the personality will interpret the
|
||||
// (lowered form of the) selectors. This means that inlining has no
|
||||
// choice but to crudely chain invokes (i.e., to ignore invokes in
|
||||
// the inlined function, but to turn all unwindable calls into
|
||||
// invokes), which is only semantically valid if every unwind stops
|
||||
// at every landing pad.
|
||||
//
|
||||
// Therefore, the invoke-inline hack is to guarantee that every
|
||||
// landing pad has a catch-all.
|
||||
enum CleanupHackLevel_t {
|
||||
/// A level of hack that requires that all landing pads have
|
||||
/// catch-alls.
|
||||
CHL_MandatoryCatchall,
|
||||
|
||||
/// A level of hack that requires that all landing pads handle
|
||||
/// cleanups.
|
||||
CHL_MandatoryCleanup,
|
||||
|
||||
/// No hacks at all; ideal IR generation.
|
||||
CHL_Ideal
|
||||
};
|
||||
const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup;
|
||||
|
||||
llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
||||
assert(EHStack.requiresLandingPad());
|
||||
|
||||
// This function contains a hack to work around a design flaw in
|
||||
// LLVM's EH IR which breaks semantics after inlining. This same
|
||||
// hack is implemented in llvm-gcc.
|
||||
//
|
||||
// The LLVM EH abstraction is basically a thin veneer over the
|
||||
// traditional GCC zero-cost design: for each range of instructions
|
||||
// in the function, there is (at most) one "landing pad" with an
|
||||
// associated chain of EH actions. A language-specific personality
|
||||
// function interprets this chain of actions and (1) decides whether
|
||||
// or not to resume execution at the landing pad and (2) if so,
|
||||
// provides an integer indicating why it's stopping. In LLVM IR,
|
||||
// the association of a landing pad with a range of instructions is
|
||||
// achieved via an invoke instruction, the chain of actions becomes
|
||||
// the arguments to the @llvm.eh.selector call, and the selector
|
||||
// call returns the integer indicator. Other than the required
|
||||
// presence of two intrinsic function calls in the landing pad,
|
||||
// the IR exactly describes the layout of the output code.
|
||||
//
|
||||
// A principal advantage of this design is that it is completely
|
||||
// language-agnostic; in theory, the LLVM optimizers can treat
|
||||
// landing pads neutrally, and targets need only know how to lower
|
||||
// the intrinsics to have a functioning exceptions system (assuming
|
||||
// that platform exceptions follow something approximately like the
|
||||
// GCC design). Unfortunately, landing pads cannot be combined in a
|
||||
// language-agnostic way: given selectors A and B, there is no way
|
||||
// to make a single landing pad which faithfully represents the
|
||||
// semantics of propagating an exception first through A, then
|
||||
// through B, without knowing how the personality will interpret the
|
||||
// (lowered form of the) selectors. This means that inlining has no
|
||||
// choice but to crudely chain invokes (i.e., to ignore invokes in
|
||||
// the inlined function, but to turn all unwindable calls into
|
||||
// invokes), which is only semantically valid if every unwind stops
|
||||
// at every landing pad.
|
||||
//
|
||||
// Therefore, the invoke-inline hack is to guarantee that every
|
||||
// landing pad has a catch-all.
|
||||
const bool UseInvokeInlineHack = true;
|
||||
|
||||
for (EHScopeStack::iterator ir = EHStack.begin(); ; ) {
|
||||
assert(ir != EHStack.end() &&
|
||||
"stack requiring landing pad is nothing but non-EH scopes?");
|
||||
|
@ -736,16 +759,23 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
|||
EHSelector.append(EHFilters.begin(), EHFilters.end());
|
||||
|
||||
// Also check whether we need a cleanup.
|
||||
if (UseInvokeInlineHack || HasEHCleanup)
|
||||
EHSelector.push_back(UseInvokeInlineHack
|
||||
if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup)
|
||||
EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
|
||||
? getCatchAllValue(*this)
|
||||
: getCleanupValue(*this));
|
||||
|
||||
// Otherwise, signal that we at least have cleanups.
|
||||
} else if (UseInvokeInlineHack || HasEHCleanup) {
|
||||
EHSelector.push_back(UseInvokeInlineHack
|
||||
} else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) {
|
||||
EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
|
||||
? getCatchAllValue(*this)
|
||||
: getCleanupValue(*this));
|
||||
|
||||
// At the MandatoryCleanup hack level, we don't need to actually
|
||||
// spuriously tell the unwinder that we have cleanups, but we do
|
||||
// need to always be prepared to handle cleanups.
|
||||
} else if (CleanupHackLevel == CHL_MandatoryCleanup) {
|
||||
// Just don't decrement LastToEmitInLoop.
|
||||
|
||||
} else {
|
||||
assert(LastToEmitInLoop > 2);
|
||||
LastToEmitInLoop--;
|
||||
|
@ -758,6 +788,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
|||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
|
||||
EHSelector.begin(), EHSelector.end(), "eh.selector");
|
||||
Selection->setDoesNotThrow();
|
||||
|
||||
// Save the selector value in mandatory-cleanup mode.
|
||||
if (CleanupHackLevel == CHL_MandatoryCleanup)
|
||||
Builder.CreateStore(Selection, getEHSelectorSlot());
|
||||
|
||||
// Select the right handler.
|
||||
llvm::Value *llvm_eh_typeid_for =
|
||||
|
@ -833,22 +867,13 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
|||
|
||||
// If there was a cleanup, we'll need to actually check whether we
|
||||
// landed here because the filter triggered.
|
||||
if (UseInvokeInlineHack || HasEHCleanup) {
|
||||
llvm::BasicBlock *RethrowBB = createBasicBlock("cleanup");
|
||||
if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) {
|
||||
llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected");
|
||||
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(Builder.getInt32Ty(), 0);
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(Int32Ty, 0);
|
||||
llvm::Value *FailsFilter =
|
||||
Builder.CreateICmpSLT(SavedSelection, Zero, "ehspec.fails");
|
||||
Builder.CreateCondBr(FailsFilter, UnexpectedBB, RethrowBB);
|
||||
|
||||
// The rethrow block is where we land if this was a cleanup.
|
||||
// TODO: can this be _Unwind_Resume if the InvokeInlineHack is off?
|
||||
EmitBlock(RethrowBB);
|
||||
Builder.CreateCall(getUnwindResumeOrRethrowFn(),
|
||||
Builder.CreateLoad(getExceptionSlot()))
|
||||
->setDoesNotReturn();
|
||||
Builder.CreateUnreachable();
|
||||
Builder.CreateCondBr(FailsFilter, UnexpectedBB, getRethrowDest().getBlock());
|
||||
|
||||
EmitBlock(UnexpectedBB);
|
||||
}
|
||||
|
@ -863,7 +888,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
|||
Builder.CreateUnreachable();
|
||||
|
||||
// ...or a normal catch handler...
|
||||
} else if (!UseInvokeInlineHack && !HasEHCleanup) {
|
||||
} else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) {
|
||||
llvm::Value *Type = EHSelector.back();
|
||||
EmitBranchThroughEHCleanup(EHHandlers[Type]);
|
||||
|
||||
|
@ -1440,14 +1465,39 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
|
|||
// This can always be a call because we necessarily didn't find
|
||||
// anything on the EH stack which needs our help.
|
||||
llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName();
|
||||
llvm::Constant *RethrowFn;
|
||||
if (!RethrowName.empty())
|
||||
RethrowFn = getCatchallRethrowFn(*this, RethrowName);
|
||||
else
|
||||
RethrowFn = getUnwindResumeOrRethrowFn();
|
||||
if (!RethrowName.empty()) {
|
||||
Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
|
||||
Builder.CreateLoad(getExceptionSlot()))
|
||||
->setDoesNotReturn();
|
||||
} else {
|
||||
llvm::Value *Exn = Builder.CreateLoad(getExceptionSlot());
|
||||
|
||||
switch (CleanupHackLevel) {
|
||||
case CHL_MandatoryCatchall:
|
||||
// In mandatory-catchall mode, we need to use
|
||||
// _Unwind_Resume_or_Rethrow, or whatever the personality's
|
||||
// equivalent is.
|
||||
Builder.CreateCall(getUnwindResumeOrRethrowFn(), Exn)
|
||||
->setDoesNotReturn();
|
||||
break;
|
||||
case CHL_MandatoryCleanup: {
|
||||
// In mandatory-cleanup mode, we should use llvm.eh.resume.
|
||||
llvm::Value *Selector = Builder.CreateLoad(getEHSelectorSlot());
|
||||
Builder.CreateCall2(CGM.getIntrinsic(llvm::Intrinsic::eh_resume),
|
||||
Exn, Selector)
|
||||
->setDoesNotReturn();
|
||||
break;
|
||||
}
|
||||
case CHL_Ideal:
|
||||
// In an idealized mode where we don't have to worry about the
|
||||
// optimizer combining landing pads, we should just use
|
||||
// _Unwind_Resume (or the personality's equivalent).
|
||||
Builder.CreateCall(getUnwindResumeFn(), Exn)
|
||||
->setDoesNotReturn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot()))
|
||||
->setDoesNotReturn();
|
||||
Builder.CreateUnreachable();
|
||||
|
||||
Builder.restoreIP(SavedIP);
|
||||
|
|
|
@ -33,9 +33,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
|||
Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
|
||||
BlockInfo(0), BlockPointer(0),
|
||||
NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
|
||||
ExceptionSlot(0), DebugInfo(0), DisableDebugInfo(false), IndirectBranch(0),
|
||||
SwitchInsn(0), CaseRangeBlock(0),
|
||||
DidCallStackSave(false), UnreachableBlock(0),
|
||||
ExceptionSlot(0), EHSelectorSlot(0),
|
||||
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
|
||||
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
|
||||
CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
|
||||
OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0),
|
||||
TrapBB(0) {
|
||||
|
|
|
@ -603,6 +603,10 @@ public:
|
|||
/// exception pointer into this alloca.
|
||||
llvm::Value *ExceptionSlot;
|
||||
|
||||
/// The selector slot. Under the MandatoryCleanup model, all
|
||||
/// landing pads write the current selector value into this alloca.
|
||||
llvm::AllocaInst *EHSelectorSlot;
|
||||
|
||||
/// Emits a landing pad for the current EH stack.
|
||||
llvm::BasicBlock *EmitLandingPad();
|
||||
|
||||
|
@ -951,6 +955,10 @@ private:
|
|||
CGDebugInfo *DebugInfo;
|
||||
bool DisableDebugInfo;
|
||||
|
||||
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
|
||||
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
||||
bool DidCallStackSave;
|
||||
|
||||
/// IndirectBranch - The first time an indirect goto is seen we create a block
|
||||
/// with an indirect branch. Every time we see the address of a label taken,
|
||||
/// we add the label to the indirect goto. Every subsequent indirect goto is
|
||||
|
@ -997,10 +1005,6 @@ private:
|
|||
// enter/leave scopes.
|
||||
llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap;
|
||||
|
||||
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
|
||||
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
||||
bool DidCallStackSave;
|
||||
|
||||
/// A block containing a single 'unreachable' instruction. Created
|
||||
/// lazily by getUnreachableBlock().
|
||||
llvm::BasicBlock *UnreachableBlock;
|
||||
|
@ -1050,6 +1054,7 @@ public:
|
|||
/// Returns a pointer to the function's exception object slot, which
|
||||
/// is assigned in every landing pad.
|
||||
llvm::Value *getExceptionSlot();
|
||||
llvm::Value *getEHSelectorSlot();
|
||||
|
||||
llvm::Value *getNormalCleanupDestSlot();
|
||||
llvm::Value *getEHCleanupDestSlot();
|
||||
|
@ -1705,6 +1710,7 @@ public:
|
|||
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
|
||||
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
|
||||
|
||||
llvm::Constant *getUnwindResumeFn();
|
||||
llvm::Constant *getUnwindResumeOrRethrowFn();
|
||||
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
|
||||
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
|
||||
|
|
|
@ -7,5 +7,5 @@ void target() throw(int)
|
|||
// CHECK: invoke void @_Z8externalv()
|
||||
external();
|
||||
}
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*), i8* null) nounwind
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*)) nounwind
|
||||
// CHECK: call void @__cxa_call_unexpected
|
||||
|
|
|
@ -310,7 +310,7 @@ namespace test7 {
|
|||
|
||||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test74testEvE1x)
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK: call void @llvm.eh.resume(
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +349,7 @@ namespace test8 {
|
|||
|
||||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test84testEvE1x)
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK: call void @llvm.eh.resume(
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -334,7 +334,7 @@ namespace test7 {
|
|||
// CHECK: ret void
|
||||
// CHECK: call i8* @llvm.eh.exception(
|
||||
// CHECK: call void @_ZdlPv({{.*}}) nounwind
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK: call void @llvm.eh.resume(
|
||||
|
||||
// Checked at top of file:
|
||||
// @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
|
||||
|
@ -364,7 +364,7 @@ namespace test7 {
|
|||
// CHECK: ret void
|
||||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: call void @_ZdlPv({{.*}}) nounwind
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow(
|
||||
// CHECK: call void @llvm.eh.resume(
|
||||
|
||||
// CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
|
||||
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
|
||||
|
|
|
@ -30,7 +30,8 @@ void test2() {
|
|||
}
|
||||
|
||||
// CHECK: define void @_Z5test2v()
|
||||
// CHECK: [[EXNSLOTVAR:%.*]] = alloca i8*
|
||||
// CHECK: [[EXNVAR:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[CLEANUPDESTVAR:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
|
||||
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
|
||||
|
@ -104,6 +105,7 @@ namespace test7 {
|
|||
// CHECK: define i32 @_ZN5test73fooEv()
|
||||
int foo() {
|
||||
// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[EHCLEANUPDESTVAR:%.*]] = alloca i32
|
||||
try {
|
||||
|
@ -117,7 +119,8 @@ namespace test7 {
|
|||
|
||||
// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
|
||||
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
|
||||
// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
// CHECK-NEXT: [[SELECTOR:%.*]] = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]]
|
||||
// CHECK-NEXT: call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
|
||||
// CHECK-NEXT: icmp eq
|
||||
// CHECK-NEXT: br i1
|
||||
|
@ -130,7 +133,8 @@ namespace test7 {
|
|||
}
|
||||
// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
|
||||
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
|
||||
// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
|
||||
// CHECK-NEXT: [[SELECTOR:%.*]] = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
|
||||
// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]]
|
||||
// CHECK-NEXT: store i32 1, i32* [[EHCLEANUPDESTVAR]]
|
||||
// CHECK-NEXT: call void @__cxa_end_catch()
|
||||
// CHECK-NEXT: br label
|
||||
|
@ -190,7 +194,7 @@ namespace test9 {
|
|||
|
||||
// landing pad from first call to invoke
|
||||
// CHECK: call i8* @llvm.eh.exception
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*))
|
||||
}
|
||||
|
||||
// __cxa_end_catch can throw for some kinds of caught exceptions.
|
||||
|
@ -255,6 +259,7 @@ namespace test11 {
|
|||
void bar() {
|
||||
try {
|
||||
// CHECK: [[EXNSLOT:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[P:%.*]] = alloca [[A:%.*]]**,
|
||||
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]*
|
||||
// CHECK-NEXT: invoke void @_ZN6test116opaqueEv()
|
||||
|
@ -403,6 +408,7 @@ namespace test16 {
|
|||
// CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1
|
||||
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]],
|
||||
// CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[EHDEST:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1
|
||||
|
||||
|
|
|
@ -273,6 +273,7 @@ namespace test5 {
|
|||
|
||||
// CHECK: define void @_ZN5test54testEv()
|
||||
// CHECK: [[EXNSLOT:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
|
||||
// CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1
|
||||
// CHECK-NEXT: [[T:%.*]] = alloca [[T_T:%.*]], align 1
|
||||
// CHECK-NEXT: alloca i32
|
||||
|
@ -324,6 +325,7 @@ namespace test7 {
|
|||
// CHECK-NEXT: alloca [[A:%.*]],
|
||||
// CHECK-NEXT: alloca i8*
|
||||
// CHECK-NEXT: alloca i32
|
||||
// CHECK-NEXT: alloca i32
|
||||
// CHECK-NEXT: [[OUTER_A:%.*]] = alloca i1
|
||||
// CHECK-NEXT: alloca i8*
|
||||
// CHECK-NEXT: [[INNER_NEW:%.*]] = alloca i1
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace test0 {
|
|||
// CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]],
|
||||
// CHECK-NEXT: [[Z:%.*]] = alloca [[A]]
|
||||
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
|
||||
// CHECK-NEXT: [[SEL:%.*]] = alloca i32
|
||||
// CHECK-NEXT: alloca i32
|
||||
// CHECK-NEXT: [[V:%.*]] = alloca [[V:%.*]]*,
|
||||
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]
|
||||
|
|
|
@ -95,7 +95,7 @@ X test2(bool B) {
|
|||
|
||||
// %invoke.cont17: rethrow block for %eh.cleanup.
|
||||
// This really should be elsewhere in the function.
|
||||
// CHECK-EH: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK-EH: call void @llvm.eh.resume(
|
||||
// CHECK-EH-NEXT: unreachable
|
||||
|
||||
// %terminate.lpad: terminate landing pad.
|
||||
|
|
|
@ -24,6 +24,6 @@ void f() {
|
|||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector
|
||||
// CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x)
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK: call void @llvm.eh.resume(
|
||||
// CHECK: unreachable
|
||||
}
|
||||
|
|
|
@ -33,5 +33,5 @@ void test1() {
|
|||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: [[T1:%.*]] = bitcast [[N_T]]* [[N]] to i8*
|
||||
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8)
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow(
|
||||
// CHECK: call void @llvm.eh.resume(
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck --check-prefix=DEFAULT_EH %s
|
||||
// RUN: %clang_cc1 -fsjlj-exceptions -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck --check-prefix=SJLJ_EH %s
|
||||
|
||||
// DEFAULT_EH: declare void @_Unwind_Resume_or_Rethrow(i8*)
|
||||
// SJLJ_EH: declare void @_Unwind_SjLj_Resume_or_Rethrow(i8*)
|
||||
|
||||
void f1(), f2();
|
||||
void f0() {
|
||||
@try {
|
||||
f1();
|
||||
} @catch (...) {
|
||||
f2();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue