[cfe-commits] r90305 - in /cfe/trunk/lib/CodeGen: CGException.cpp CodeGenFunction.cpp CodeGenFunction.h

Mike Stump mrs at apple.com
Tue Dec 1 23:41:42 PST 2009


Author: mrs
Date: Wed Dec  2 01:41:41 2009
New Revision: 90305

URL: http://llvm.org/viewvc/llvm-project?rev=90305&view=rev
Log:
More exception handling improvements...  WIP.

Highlights include:

  Add a helper to generate __cxa_free_exception and _ZSt9terminatev.
  Add a region to handle EH object deallocation for ctor failures for throw.
  Add a terminate handler for __cxa_end_catch.
  A framework for adding cleanup actions for the exceptional edges only.

Modified:
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=90305&r1=90304&r2=90305&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Wed Dec  2 01:41:41 2009
@@ -31,9 +31,21 @@
   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
 }
 
+static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
+  // void __cxa_free_exception(void *thrown_exception);
+  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+  std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+  
+  const llvm::FunctionType *FTy = 
+  llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+                          Args, false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
+}
+
 static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
-  // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, 
-  //                   void (*dest) (void *) );
+  // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, 
+  //                  void (*dest) (void *));
 
   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
   std::vector<const llvm::Type*> Args(3, Int8PtrTy);
@@ -46,7 +58,7 @@
 }
 
 static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
-  // void __cxa_rethrow ();
+  // void __cxa_rethrow();
 
   const llvm::FunctionType *FTy = 
     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
@@ -55,7 +67,7 @@
 }
 
 static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
-  // void* __cxa_begin_catch ();
+  // void* __cxa_begin_catch();
 
   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@@ -67,7 +79,7 @@
 }
 
 static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
-  // void __cxa_end_catch ();
+  // void __cxa_end_catch();
 
   const llvm::FunctionType *FTy = 
     llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
@@ -92,6 +104,15 @@
   return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
 }
 
+static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
+  // void __terminate();
+
+  const llvm::FunctionType *FTy = 
+    llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
+}
+
 // CopyObject - Utility to copy an object.  Calls copy constructor as necessary.
 // N is casted to the right type.
 static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
@@ -112,7 +133,19 @@
       CGF.EmitAggExpr(E, This, false);
     } else if (CXXConstructorDecl *CopyCtor
                = RD->getCopyConstructor(CGF.getContext(), 0)) {
-      // FIXME: region management
+      // All temporaries end before we call __cxa_throw
+      CodeGenFunction::CleanupScope TryScope(CGF);
+      {
+        // These actions are only on the exceptional edge.
+        CodeGenFunction::DelayedCleanupBlock Scope(CGF, true);
+
+        llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
+        const llvm::Type *Int8PtrTy
+          = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+        llvm::Value *ExceptionPtr = CGF.Builder.CreateBitCast(N, Int8PtrTy);
+        CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
+      }
+
       llvm::Value *Src = CGF.EmitLValue(E).getAddress();
 
       // Stolen from EmitClassAggrMemberwiseCopy
@@ -129,9 +162,8 @@
         CopyCtor->getType()->getAs<FunctionType>()->getResultType();
       CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
                    Callee, CallArgs, CopyCtor);
-      // FIXME: region management
     } else
-      CGF.ErrorUnsupported(E, "uncopyable object");
+      llvm::llvm_unreachable("uncopyable object");
   }
 }
 
@@ -154,7 +186,7 @@
       CGF.EmitAggregateCopy(This, E, ObjectType);
     } else if (CXXConstructorDecl *CopyCtor
                = RD->getCopyConstructor(CGF.getContext(), 0)) {
-      // FIXME: region management 
+      // FIXME: region management, call terminate
       llvm::Value *Src = E;
 
       // Stolen from EmitClassAggrMemberwiseCopy
@@ -241,16 +273,12 @@
 
   llvm::BasicBlock *PrevLandingPad = getInvokeDest();
   llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
-#if 0
   llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
-#endif
   llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
   llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
 
-#if 0
   // Push an EH context entry, used for handling rethrows.
   PushCleanupBlock(FinallyBlock);
-#endif
 
   // Emit the statements in the try {} block
   setInvokeDest(TryHandler);
@@ -306,6 +334,7 @@
   llvm::Value *Selector
     = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
                          SelectorArgs.end(), "selector");
+  llvm::BasicBlock *TerminateHandler = 0;
   for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
     const CXXCatchStmt *C = S.getHandler(i);
     VarDecl *CatchParam = C->getExceptionDecl();
@@ -375,13 +404,15 @@
 
     EmitBlock(MatchEnd);
 
-    // Unfortunately, we also have to generate another EH frame here
-    // in case this throws.
-    llvm::BasicBlock *MatchEndHandler =
-      createBasicBlock("match.end.handler");
-    llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont");
+    // Set up terminate handler
+    bool GenerateTerminate = false;
+    if (!TerminateHandler) {
+      TerminateHandler = createBasicBlock("terminate.handler");
+      GenerateTerminate = true;
+    }
+    llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
     Builder.CreateInvoke(getEndCatchFn(*this),
-                         Cont, MatchEndHandler,
+                         Cont, TerminateHandler,
                          Args.begin(), Args.begin());
 
     EmitBlock(Cont);
@@ -390,19 +421,31 @@
     if (Info.EndBlock)
       EmitBlock(Info.EndBlock);
 
-    EmitBlock(MatchEndHandler);
     Exc = Builder.CreateCall(llvm_eh_exception, "exc");
-    // We are required to emit this call to satisfy LLVM, even
-    // though we don't use the result.
-    Args.clear();
-    Args.push_back(Exc);
-    Args.push_back(Personality);
-    Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
-                                          0));
-    Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
     Builder.CreateStore(Exc, RethrowPtr);
     EmitBranchThroughCleanup(FinallyRethrow);
 
+    if (GenerateTerminate) {
+      GenerateTerminate = false;
+      EmitBlock(TerminateHandler);
+      Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+      // We are required to emit this call to satisfy LLVM, even
+      // though we don't use the result.
+      Args.clear();
+      Args.push_back(Exc);
+      Args.push_back(Personality);
+      Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+                                            0));
+      Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+      llvm::CallInst *TerminateCall = 
+        Builder.CreateCall(getTerminateFn(*this));
+      TerminateCall->setDoesNotReturn();
+      Builder.CreateUnreachable();
+
+      // Clear the insertion point to indicate we are in unreachable code.
+      Builder.ClearInsertionPoint();
+    }
+
     if (Next)
       EmitBlock(Next);
   }
@@ -413,7 +456,6 @@
 
   setInvokeDest(PrevLandingPad);
 
-#if 0
   EmitBlock(FinallyBlock);
 
   if (Info.SwitchBlock)
@@ -423,7 +465,6 @@
 
   // Branch around the rethrow code.
   EmitBranch(FinallyEnd);
-#endif
 
   EmitBlock(FinallyRethrow);
   Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=90305&r1=90304&r2=90305&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Dec  2 01:41:41 2009
@@ -606,8 +606,10 @@
 }
 
 void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
-                                       llvm::BasicBlock *CleanupExitBlock) {
-  CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock));
+                                       llvm::BasicBlock *CleanupExitBlock,
+                                       bool EHOnly) {
+  CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock,
+                                        EHOnly));
 }
 
 void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
@@ -629,6 +631,8 @@
   std::vector<llvm::BranchInst *> BranchFixups;
   std::swap(BranchFixups, CE.BranchFixups);
 
+  bool EHOnly = CE.EHOnly;
+
   CleanupEntries.pop_back();
 
   // Check if any branch fixups pointed to the scope we just popped. If so,
@@ -663,8 +667,9 @@
 
     Builder.SetInsertPoint(SwitchBlock);
 
-    llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
-                                                "cleanup.dst");
+    llvm::Value *DestCodePtr
+      = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
+                         "cleanup.dst");
     llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp");
 
     // Create a switch instruction to determine where to jump next.
@@ -710,15 +715,16 @@
         new llvm::StoreInst(ID, DestCodePtr, BI);
       } else {
         // We need to jump through another cleanup block. Create a pad block
-        // with a branch instruction that jumps to the final destination and
-        // add it as a branch fixup to the current cleanup scope.
+        // with a branch instruction that jumps to the final destination and add
+        // it as a branch fixup to the current cleanup scope.
 
         // Create the pad block.
         llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn);
 
         // Create a unique case ID.
-        llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
-                                                       SI->getNumSuccessors());
+        llvm::ConstantInt *ID
+          = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+                                   SI->getNumSuccessors());
 
         // Store the jump destination before the branch instruction.
         new llvm::StoreInst(ID, DestCodePtr, BI);
@@ -744,12 +750,19 @@
     BlockScopes.erase(Blocks[i]);
   }
 
-  return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock);
+  return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock, EHOnly);
 }
 
 void CodeGenFunction::EmitCleanupBlock() {
   CleanupBlockInfo Info = PopCleanupBlock();
 
+  if (Info.EHOnly) {
+    // FIXME: Add this to the exceptional edge
+    if (Info.CleanupBlock->getNumUses() == 0)
+      delete Info.CleanupBlock;
+    return;
+  }
+
   llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
   if (CurBB && !CurBB->getTerminator() &&
       Info.CleanupBlock->getNumUses() == 0) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=90305&r1=90304&r2=90305&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Dec  2 01:41:41 2009
@@ -109,7 +109,8 @@
   /// PushCleanupBlock - Push a new cleanup entry on the stack and set the
   /// passed in block as the cleanup block.
   void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
-                        llvm::BasicBlock *CleanupExitBlock = 0);
+                        llvm::BasicBlock *CleanupExitBlock = 0,
+                        bool EHOnly = false);
 
   /// CleanupBlockInfo - A struct representing a popped cleanup block.
   struct CleanupBlockInfo {
@@ -123,9 +124,13 @@
     /// EndBlock - the default destination for the switch instruction.
     llvm::BasicBlock *EndBlock;
 
+    /// EHOnly - True iff this cleanup should only be performed on the
+    /// exceptional edge.
+    bool EHOnly;
+
     CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb,
-                     llvm::BasicBlock *eb)
-      : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {}
+                     llvm::BasicBlock *eb, bool ehonly = false)
+      : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {}
   };
 
   /// PopCleanupBlock - Will pop the cleanup entry on the stack, process all
@@ -141,11 +146,13 @@
     llvm::BasicBlock *CurBB;
     llvm::BasicBlock *CleanupEntryBB;
     llvm::BasicBlock *CleanupExitBB;
+    bool EHOnly;
     
   public:
-    DelayedCleanupBlock(CodeGenFunction &cgf)
+    DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
       : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
-      CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) {
+      CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
+      EHOnly(ehonly) {
       CGF.Builder.SetInsertPoint(CleanupEntryBB);
     }
 
@@ -156,7 +163,7 @@
     }
     
     ~DelayedCleanupBlock() {
-      CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB);
+      CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, EHOnly);
       // FIXME: This is silly, move this into the builder.
       if (CurBB)
         CGF.Builder.SetInsertPoint(CurBB);
@@ -303,10 +310,14 @@
     /// inserted into the current function yet.
     std::vector<llvm::BranchInst *> BranchFixups;
 
+    /// EHOnly - Perform this only on the exceptional edge, not the main edge.
+    bool EHOnly;
+
     explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock,
-                          llvm::BasicBlock *CleanupExitBlock)
+                          llvm::BasicBlock *CleanupExitBlock, bool ehonly)
       : CleanupEntryBlock(CleanupEntryBlock), 
-      CleanupExitBlock(CleanupExitBlock) {}
+        CleanupExitBlock(CleanupExitBlock),
+        EHOnly(ehonly) {}
   };
 
   /// CleanupEntries - Stack of cleanup entries.





More information about the cfe-commits mailing list