From: John McCall Date: Sat, 28 May 2011 21:13:02 +0000 (+0000) Subject: Convert Clang over to resuming from landing pads with llvm.eh.resume. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93c332a8ba2c193c435b293966d343dab15f555b;p=clang 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. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132269 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 6cb9599e25..e8ad6da2f9 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -112,11 +112,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } +llvm::Constant *CodeGenFunction::getUnwindResumeFn() { + const llvm::FunctionType *FTy = + 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::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); 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_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); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index d42057aba0..150cb69b4d 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -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) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 9aa7903ab7..bb8fd8e243 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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 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); diff --git a/test/CXX/except/except.spec/p9-dynamic.cpp b/test/CXX/except/except.spec/p9-dynamic.cpp index 490d2fa21f..3f496f25c9 100644 --- a/test/CXX/except/except.spec/p9-dynamic.cpp +++ b/test/CXX/except/except.spec/p9-dynamic.cpp @@ -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 diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index f56b1552ce..dcb27ce0da 100644 --- a/test/CodeGenCXX/arm.cpp +++ b/test/CodeGenCXX/arm.cpp @@ -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( } } diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 353b61061a..94d88334f8 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -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 diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp index 88c32724b8..44219b4f17 100644 --- a/test/CodeGenCXX/eh.cpp +++ b/test/CodeGenCXX/eh.cpp @@ -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 diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp index d9b850672c..b32b90bf74 100644 --- a/test/CodeGenCXX/exceptions.cpp +++ b/test/CodeGenCXX/exceptions.cpp @@ -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 diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp index 3286b228b2..9a12a91253 100644 --- a/test/CodeGenCXX/goto.cpp +++ b/test/CodeGenCXX/goto.cpp @@ -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]] diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp index ad6fa4f744..82caff880f 100644 --- a/test/CodeGenCXX/nrvo.cpp +++ b/test/CodeGenCXX/nrvo.cpp @@ -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. diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp index 0bd810eeca..aa79a4f6dd 100644 --- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp +++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp @@ -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 } diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m index 38b8635609..5d63e919fb 100644 --- a/test/CodeGenObjC/blocks-2.m +++ b/test/CodeGenObjC/blocks-2.m @@ -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( } diff --git a/test/CodeGenObjC/unwind-fn.m b/test/CodeGenObjC/unwind-fn.m deleted file mode 100644 index 5e4a7a5863..0000000000 --- a/test/CodeGenObjC/unwind-fn.m +++ /dev/null @@ -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(); - } -}