diff options
-rw-r--r-- | lib/CodeGen/CGException.cpp | 131 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 1 | ||||
-rw-r--r-- | test/CXX/except/except.spec/p9-dynamic.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/arm.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenCXX/destructors.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenCXX/eh.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/nrvo.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/threadsafe-statics-exceptions.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenObjC/blocks-2.m | 2 | ||||
-rw-r--r-- | test/CodeGenObjC/unwind-fn.m | 4 |
10 files changed, 62 insertions, 92 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 91be321d31..6cb9599e25 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -112,18 +112,11 @@ 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(VoidTy, Int8PtrTy, /*IsVarArgs=*/false); + llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy, + /*IsVarArgs=*/false); if (CGM.getLangOptions().SjLjExceptions) return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow"); @@ -570,59 +563,47 @@ 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?"); @@ -755,23 +736,16 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { EHSelector.append(EHFilters.begin(), EHFilters.end()); // Also check whether we need a cleanup. - if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) - EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall + if (UseInvokeInlineHack || HasEHCleanup) + EHSelector.push_back(UseInvokeInlineHack ? getCatchAllValue(*this) : getCleanupValue(*this)); // Otherwise, signal that we at least have cleanups. - } else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) { - EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall + } else if (UseInvokeInlineHack || HasEHCleanup) { + EHSelector.push_back(UseInvokeInlineHack ? 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--; @@ -859,7 +833,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // If there was a cleanup, we'll need to actually check whether we // landed here because the filter triggered. - if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) { + if (UseInvokeInlineHack || HasEHCleanup) { llvm::BasicBlock *RethrowBB = createBasicBlock("cleanup"); llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected"); @@ -869,11 +843,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { 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); - llvm::Constant *RethrowFn = - CleanupHackLevel == CHL_MandatoryCatchall ? getUnwindResumeOrRethrowFn() - : getUnwindResumeFn(); - Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot())) + Builder.CreateCall(getUnwindResumeOrRethrowFn(), + Builder.CreateLoad(getExceptionSlot())) ->setDoesNotReturn(); Builder.CreateUnreachable(); @@ -890,7 +863,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { Builder.CreateUnreachable(); // ...or a normal catch handler... - } else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) { + } else if (!UseInvokeInlineHack && !HasEHCleanup) { llvm::Value *Type = EHSelector.back(); EmitBranchThroughEHCleanup(EHHandlers[Type]); @@ -1471,9 +1444,7 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { if (!RethrowName.empty()) RethrowFn = getCatchallRethrowFn(*this, RethrowName); else - RethrowFn = (CleanupHackLevel == CHL_MandatoryCatchall - ? getUnwindResumeOrRethrowFn() - : getUnwindResumeFn()); + RethrowFn = getUnwindResumeOrRethrowFn(); Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot())) ->setDoesNotReturn(); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 8613f05e92..9aa7903ab7 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1705,7 +1705,6 @@ 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 3f496f25c9..490d2fa21f 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*)) nounwind +// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*), i8* null) nounwind // CHECK: call void @__cxa_call_unexpected diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index a3333171c1..f56b1552ce 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( + // CHECK: call void @_Unwind_Resume_or_Rethrow } } @@ -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( + // CHECK: call void @_Unwind_Resume_or_Rethrow } } diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index bc32d7d743..353b61061a 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( + // CHECK: call void @_Unwind_Resume_or_Rethrow // 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( + // CHECK: call void @_Unwind_Resume_or_Rethrow( // 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 250d47edd2..88c32724b8 100644 --- a/test/CodeGenCXX/eh.cpp +++ b/test/CodeGenCXX/eh.cpp @@ -190,7 +190,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*)) + // 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) } // __cxa_end_catch can throw for some kinds of caught exceptions. diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp index 3104f937f1..ad6fa4f744 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( + // CHECK-EH: call void @_Unwind_Resume_or_Rethrow // 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 06ebe0a71b..0bd810eeca 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( + // CHECK: call void @_Unwind_Resume_or_Rethrow // CHECK: unreachable } diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m index 1f1c272fbf..38b8635609 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( + // CHECK: call void @_Unwind_Resume_or_Rethrow( } diff --git a/test/CodeGenObjC/unwind-fn.m b/test/CodeGenObjC/unwind-fn.m index 8d13c98969..5e4a7a5863 100644 --- a/test/CodeGenObjC/unwind-fn.m +++ b/test/CodeGenObjC/unwind-fn.m @@ -1,8 +1,8 @@ // 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(i8*) -// SJLJ_EH: declare void @_Unwind_SjLj_Resume(i8*) +// DEFAULT_EH: declare void @_Unwind_Resume_or_Rethrow(i8*) +// SJLJ_EH: declare void @_Unwind_SjLj_Resume_or_Rethrow(i8*) void f1(), f2(); void f0() { |