[cfe-commits] r133601 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGObjCRuntime.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenObjC/exceptions-nonfragile.m

John McCall rjmccall at apple.com
Tue Jun 21 19:32:12 PDT 2011


Author: rjmccall
Date: Tue Jun 21 21:32:12 2011
New Revision: 133601

URL: http://llvm.org/viewvc/llvm-project?rev=133601&view=rev
Log:
Emit @finally blocks completely lazily instead of forcing their
existence by always threading an edge from the catchall.  Not doing
this was previously causing a crash in the very extreme case where
neither the normal cleanup nor the EH catchall was actually reachable:
we would delete the catchall entry block, which would cause us to
delete the entry block of the finally cleanup as well because the
cleanup logic would merge the blocks, which in turn triggered an assert
because later blocks in the finally would still be using values from the
entry.  Laziness turns out to be the most elegant solution to the problem.


Modified:
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGObjCRuntime.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenObjC/exceptions-nonfragile.m

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=133601&r1=133600&r2=133601&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Jun 21 21:32:12 2011
@@ -1298,14 +1298,16 @@
 /// Enters a finally block for an implementation using zero-cost
 /// exceptions.  This is mostly general, but hard-codes some
 /// language/ABI-specific behavior in the catch-all sections.
-CodeGenFunction::FinallyInfo
-CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
-                                   llvm::Constant *BeginCatchFn,
-                                   llvm::Constant *EndCatchFn,
-                                   llvm::Constant *RethrowFn) {
-  assert((BeginCatchFn != 0) == (EndCatchFn != 0) &&
+void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
+                                         const Stmt *body,
+                                         llvm::Constant *beginCatchFn,
+                                         llvm::Constant *endCatchFn,
+                                         llvm::Constant *rethrowFn) {
+  assert((beginCatchFn != 0) == (endCatchFn != 0) &&
          "begin/end catch functions not paired");
-  assert(RethrowFn && "rethrow function is required");
+  assert(rethrowFn && "rethrow function is required");
+
+  BeginCatchFn = beginCatchFn;
 
   // The rethrow function has one of the following two types:
   //   void (*)()
@@ -1313,13 +1315,12 @@
   // In the latter case we need to pass it the exception object.
   // But we can't use the exception slot because the @finally might
   // have a landing pad (which would overwrite the exception slot).
-  const llvm::FunctionType *RethrowFnTy =
+  const llvm::FunctionType *rethrowFnTy =
     cast<llvm::FunctionType>(
-      cast<llvm::PointerType>(RethrowFn->getType())
-      ->getElementType());
-  llvm::Value *SavedExnVar = 0;
-  if (RethrowFnTy->getNumParams())
-    SavedExnVar = CreateTempAlloca(Builder.getInt8PtrTy(), "finally.exn");
+      cast<llvm::PointerType>(rethrowFn->getType())->getElementType());
+  SavedExnVar = 0;
+  if (rethrowFnTy->getNumParams())
+    SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn");
 
   // A finally block is a statement which must be executed on any edge
   // out of a given scope.  Unlike a cleanup, the finally block may
@@ -1333,67 +1334,64 @@
   // The finally block itself is generated in the context of a cleanup
   // which conditionally leaves the catch-all.
 
-  FinallyInfo Info;
-
   // Jump destination for performing the finally block on an exception
   // edge.  We'll never actually reach this block, so unreachable is
   // fine.
-  JumpDest RethrowDest = getJumpDestInCurrentScope(getUnreachableBlock());
+  RethrowDest = CGF.getJumpDestInCurrentScope(CGF.getUnreachableBlock());
 
   // Whether the finally block is being executed for EH purposes.
-  llvm::AllocaInst *ForEHVar = CreateTempAlloca(Builder.getInt1Ty(),
-                                                "finally.for-eh");
-  InitTempAlloca(ForEHVar, llvm::ConstantInt::getFalse(getLLVMContext()));
+  ForEHVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "finally.for-eh");
+  CGF.Builder.CreateStore(CGF.Builder.getFalse(), ForEHVar);
 
   // Enter a normal cleanup which will perform the @finally block.
-  EHStack.pushCleanup<PerformFinally>(NormalCleanup, Body,
-                                      ForEHVar, EndCatchFn,
-                                      RethrowFn, SavedExnVar);
+  CGF.EHStack.pushCleanup<PerformFinally>(NormalCleanup, body,
+                                          ForEHVar, endCatchFn,
+                                          rethrowFn, SavedExnVar);
 
   // Enter a catch-all scope.
-  llvm::BasicBlock *CatchAllBB = createBasicBlock("finally.catchall");
-  CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
-  Builder.SetInsertPoint(CatchAllBB);
-
-  // If there's a begin-catch function, call it.
-  if (BeginCatchFn) {
-    Builder.CreateCall(BeginCatchFn, Builder.CreateLoad(getExceptionSlot()))
-      ->setDoesNotThrow();
-  }
-
-  // If we need to remember the exception pointer to rethrow later, do so.
-  if (SavedExnVar) {
-    llvm::Value *SavedExn = Builder.CreateLoad(getExceptionSlot());
-    Builder.CreateStore(SavedExn, SavedExnVar);
-  }
-
-  // Tell the finally block that we're in EH.
-  Builder.CreateStore(llvm::ConstantInt::getTrue(getLLVMContext()), ForEHVar);
+  llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall");
+  EHCatchScope *catchScope = CGF.EHStack.pushCatch(1);
+  catchScope->setCatchAllHandler(0, catchBB);
+}
 
-  // Thread a jump through the finally cleanup.
-  EmitBranchThroughCleanup(RethrowDest);
+void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
+  // Leave the finally catch-all.
+  EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin());
+  llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block;
+  CGF.EHStack.popCatch();
+
+  // If there are any references to the catch-all block, emit it.
+  if (catchBB->use_empty()) {
+    delete catchBB;
+  } else {
+    CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP();
+    CGF.EmitBlock(catchBB);
 
-  Builder.restoreIP(SavedIP);
+    llvm::Value *exn = 0;
 
-  EHCatchScope *CatchScope = EHStack.pushCatch(1);
-  CatchScope->setCatchAllHandler(0, CatchAllBB);
+    // If there's a begin-catch function, call it.
+    if (BeginCatchFn) {
+      exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+      CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
+    }
 
-  return Info;
-}
+    // If we need to remember the exception pointer to rethrow later, do so.
+    if (SavedExnVar) {
+      if (!exn) exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+      CGF.Builder.CreateStore(exn, SavedExnVar);
+    }
 
-void CodeGenFunction::ExitFinallyBlock(FinallyInfo &Info) {
-  // Leave the finally catch-all.
-  EHCatchScope &Catch = cast<EHCatchScope>(*EHStack.begin());
-  llvm::BasicBlock *CatchAllBB = Catch.getHandler(0).Block;
-  EHStack.popCatch();
+    // Tell the cleanups in the finally block that we're do this for EH.
+    CGF.Builder.CreateStore(CGF.Builder.getTrue(), ForEHVar);
 
-  // And leave the normal cleanup.
-  PopCleanupBlock();
+    // Thread a jump through the finally cleanup.
+    CGF.EmitBranchThroughCleanup(RethrowDest);
 
-  CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
-  EmitBlock(CatchAllBB, true);
+    CGF.Builder.restoreIP(savedIP);
+  }
 
-  Builder.restoreIP(SavedIP);
+  // Finally, leave the @finally cleanup.
+  CGF.PopCleanupBlock();
 }
 
 llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {

Modified: cfe/trunk/lib/CodeGen/CGObjCRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCRuntime.cpp?rev=133601&r1=133600&r2=133601&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCRuntime.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCRuntime.cpp Tue Jun 21 21:32:12 2011
@@ -175,10 +175,8 @@
 
   CodeGenFunction::FinallyInfo FinallyInfo;
   if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
-    FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(),
-                                        beginCatchFn,
-                                        endCatchFn,
-                                        exceptionRethrowFn);
+    FinallyInfo.enter(CGF, Finally->getFinallyBody(),
+                      beginCatchFn, endCatchFn, exceptionRethrowFn);
 
   llvm::SmallVector<CatchHandler, 8> Handlers;
 
@@ -266,9 +264,9 @@
   // Go back to the try-statement fallthrough.
   CGF.Builder.restoreIP(SavedIP);
 
-  // Pop out of the normal cleanup on the finally.
+  // Pop out of the finally.
   if (S.getFinallyStmt())
-    CGF.ExitFinallyBlock(FinallyInfo);
+    FinallyInfo.exit(CGF);
 
   if (Cont.isValid())
     CGF.EmitBlock(Cont.getBlock());

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=133601&r1=133600&r2=133601&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jun 21 21:32:12 2011
@@ -635,16 +635,28 @@
   /// rethrows.
   llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack;
 
-  // A struct holding information about a finally block's IR
-  // generation.  For now, doesn't actually hold anything.
-  struct FinallyInfo {
-  };
+  /// A class controlling the emission of a finally block.
+  class FinallyInfo {
+    /// Where the catchall's edge through the cleanup should go.
+    JumpDest RethrowDest;
+
+    /// A function to call to enter the catch.
+    llvm::Constant *BeginCatchFn;
+
+    /// An i1 variable indicating whether or not the @finally is
+    /// running for an exception.
+    llvm::AllocaInst *ForEHVar;
+
+    /// An i8* variable into which the exception pointer to rethrow
+    /// has been saved.
+    llvm::AllocaInst *SavedExnVar;
 
-  FinallyInfo EnterFinallyBlock(const Stmt *Stmt,
-                                llvm::Constant *BeginCatchFn,
-                                llvm::Constant *EndCatchFn,
-                                llvm::Constant *RethrowFn);
-  void ExitFinallyBlock(FinallyInfo &FinallyInfo);
+  public:
+    void enter(CodeGenFunction &CGF, const Stmt *Finally,
+               llvm::Constant *beginCatchFn, llvm::Constant *endCatchFn,
+               llvm::Constant *rethrowFn);
+    void exit(CodeGenFunction &CGF);
+  };
 
   /// pushFullExprCleanup - Push a cleanup to be run at the end of the
   /// current full-expression.  Safe against the possibility that

Modified: cfe/trunk/test/CodeGenObjC/exceptions-nonfragile.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/exceptions-nonfragile.m?rev=133601&r1=133600&r2=133601&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/exceptions-nonfragile.m (original)
+++ cfe/trunk/test/CodeGenObjC/exceptions-nonfragile.m Tue Jun 21 21:32:12 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
 
 // rdar://problem/8535238
 // CHECK: declare void @objc_exception_rethrow()
@@ -15,3 +15,17 @@
 void throwing() {
   @throw(@"error!");
 }
+
+// rdar://problem/9431547
+void die(void) __attribute__((nothrow, noreturn));
+void test2(void) {
+  @try {
+    die();
+  } @finally {
+    extern void test2_helper(void);
+    test2_helper();
+  }
+
+  // CHECK: define void @test2()
+  // CHECK-NOT: call void @test2_helper()
+}





More information about the cfe-commits mailing list