]> granicus.if.org Git - clang/commitdiff
Convert Clang over to resuming from landing pads with llvm.eh.resume.
authorJohn McCall <rjmccall@apple.com>
Sat, 28 May 2011 21:13:02 +0000 (21:13 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 28 May 2011 21:13:02 +0000 (21:13 +0000)
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

13 files changed:
lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
test/CXX/except/except.spec/p9-dynamic.cpp
test/CodeGenCXX/arm.cpp
test/CodeGenCXX/destructors.cpp
test/CodeGenCXX/eh.cpp
test/CodeGenCXX/exceptions.cpp
test/CodeGenCXX/goto.cpp
test/CodeGenCXX/nrvo.cpp
test/CodeGenCXX/threadsafe-statics-exceptions.cpp
test/CodeGenObjC/blocks-2.m
test/CodeGenObjC/unwind-fn.m [deleted file]

index 6cb9599e257dd4895aac5f0253d88931be871bda..e8ad6da2f98079f4b82b69be6c66a01dcae04895 100644 (file)
@@ -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);
index d42057aba033dbf2a7bfb74ab43def8a59be1ae9..150cb69b4d1ad8f561be2e3f1d4b10c1e47aa047 100644 (file)
@@ -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) {
index 9aa7903ab79ca4328a95d0e6be776e3385d08d9c..bb8fd8e243060383fec0cdbf8981b177e32c7d7a 100644 (file)
@@ -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);
index 490d2fa21f99962440d6a100b3c38dfcf9af4690..3f496f25c9ba26ead87df11b3ddd1fcfaf0ffb46 100644 (file)
@@ -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
index f56b1552ce6dc0c65f07dcc091b85cfd171bd010..dcb27ce0dab32b012df3e27a6aec66a26514613c 100644 (file)
@@ -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(
   }
 }
 
index 353b61061ad1c53ea90e6afcab6abbc955ebf0b1..94d88334f85b709f6b70c90ee7ea2e1cb9242cb8 100644 (file)
@@ -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
index 88c32724b84b62760546fcfd324d7a3b3eb8b023..44219b4f1754a08d01c081cb4e181d10b084f182 100644 (file)
@@ -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
 
index d9b850672cd1102dc435c0a8a18b92038679aef8..b32b90bf7412716f7c230c320a244ea46f533b66 100644 (file)
@@ -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
index 3286b228b25fba2f64c842e6ce53058b5f488462..9a12a9125398fc36525ca296f9208b845505485d 100644 (file)
@@ -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]]
index ad6fa4f744569dff8758b8cfd41d6c7932c962fa..82caff880f5c3e2b3f69dc4c9c4736dfe623431d 100644 (file)
@@ -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.
index 0bd810eeca56960d238cf16bdd4512a1cf1cc831..aa79a4f6dd3d2abca04e7da958959a5027694517 100644 (file)
@@ -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
 }
index 38b863560998d0b249d849ec7e174ef3c1b26928..5d63e919fb3172dd8165c89831645c8bd0b40ba6 100644 (file)
@@ -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 (file)
index 5e4a7a5..0000000
+++ /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();
-  }
-}