[llvm-commits] [dragonegg] r101360 - in /dragonegg/trunk: llvm-convert.cpp llvm-internal.h

Duncan Sands baldrick at free.fr
Wed Apr 14 23:55:46 PDT 2010


Author: baldrick
Date: Thu Apr 15 01:55:46 2010
New Revision: 101360

URL: http://llvm.org/viewvc/llvm-project?rev=101360&view=rev
Log:
If an exception is thrown in a must-not-throw region, then arrange
for control to branch to the block calling std::terminate (or the
language equivalent).

Modified:
    dragonegg/trunk/llvm-convert.cpp
    dragonegg/trunk/llvm-internal.h

Modified: dragonegg/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-convert.cpp?rev=101360&r1=101359&r2=101360&view=diff
==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Thu Apr 15 01:55:46 2010
@@ -991,7 +991,7 @@
 
   // Now that phi nodes have been output, emit pending exception handling code.
   EmitLandingPads();
-  EmitFailureCode();
+  EmitFailureBlocks();
   EmitRewindBlock();
 
 #ifndef NDEBUG
@@ -1872,19 +1872,33 @@
   return ExceptionFilter;
 }
 
+/// getFailureBlock - Return the basic block containing the failure code for
+/// the given exception handling region, creating it if necessary.
+BasicBlock *TreeToLLVM::getFailureBlock(unsigned RegionNo) {
+  if (RegionNo >= FailureBlocks.size())
+    FailureBlocks.resize(RegionNo + 1, 0);
+
+  BasicBlock *&FailureBlock = FailureBlocks[RegionNo];
+
+  if (!FailureBlock)
+    FailureBlock = BasicBlock::Create(Context, "fail");
+
+  return FailureBlock;
+}
+
 /// EmitLandingPads - Emit EH landing pads.
 void TreeToLLVM::EmitLandingPads() {
   // If there are no invokes then there is nothing to do.
-  if (Invokes.empty())
+  if (NormalInvokes.empty())
     return;
 
   // If a GCC post landing pad is shared by several exception handling regions,
   // or if there is a normal edge to it, then create LLVM landing pads for each
   // eh region.  Calls to eh.exception and eh.selector will then go in the LLVM
   // landing pad, which branches to the GCC post landing pad.
-  for (unsigned LPadNo = 1; LPadNo < Invokes.size(); ++LPadNo) {
+  for (unsigned LPadNo = 1; LPadNo < NormalInvokes.size(); ++LPadNo) {
     // Get the list of invokes for this GCC landing pad.
-    SmallVector<InvokeInst *, 8> &InvokesForPad = Invokes[LPadNo];
+    SmallVector<InvokeInst *, 8> &InvokesForPad = NormalInvokes[LPadNo];
 
     if (InvokesForPad.empty())
       continue;
@@ -1955,11 +1969,11 @@
   std::vector<Value*> Args;
   Function *ExcIntr = Intrinsic::getDeclaration(TheModule,
                                                 Intrinsic::eh_exception);
-  Function *SelectorIntr = Intrinsic::getDeclaration(TheModule,
-                                                     Intrinsic::eh_selector);
-  for (unsigned LPadNo = 1; LPadNo < Invokes.size(); ++LPadNo) {
+  Function *SlctrIntr = Intrinsic::getDeclaration(TheModule,
+                                                  Intrinsic::eh_selector);
+  for (unsigned LPadNo = 1; LPadNo < NormalInvokes.size(); ++LPadNo) {
     // Get the list of invokes for this GCC landing pad.
-    SmallVector<InvokeInst *, 8> &InvokesForPad = Invokes[LPadNo];
+    SmallVector<InvokeInst *, 8> &InvokesForPad = NormalInvokes[LPadNo];
 
     if (InvokesForPad.empty())
       continue;
@@ -2084,7 +2098,7 @@
       Args.push_back(CatchAll);
 
     // Emit the selector call.
-    Value *Filter = Builder.CreateCall(SelectorIntr, Args.begin(), Args.end(),
+    Value *Filter = Builder.CreateCall(SlctrIntr, Args.begin(), Args.end(),
                                        "filter");
 
     // Store it if made use of elsewhere.
@@ -2094,24 +2108,97 @@
     Args.clear();
   }
 
-  Invokes.clear();
+  NormalInvokes.clear();
 }
 
-/// EmitFailureCode - Emit the blocks containing failure code executed when
+/// EmitFailureBlocks - Emit the blocks containing failure code executed when
 /// an exception is thrown in a must-not-throw region.
-void TreeToLLVM::EmitFailureCode() {
-  for (DenseMap<tree, BasicBlock *>::iterator I = FailureCode.begin(),
-       E = FailureCode.end(); I != E; ++I) {
-    BeginBlock(I->second);
+void TreeToLLVM::EmitFailureBlocks() {
+  for (unsigned RegionNo = 1; RegionNo < FailureBlocks.size(); ++RegionNo) {
+    BasicBlock *FailureBlock = FailureBlocks[RegionNo];
+
+    if (!FailureBlock)
+      continue;
+
+    eh_region region = get_eh_region_from_number(RegionNo);
+    assert(region->type == ERT_MUST_NOT_THROW && "Unexpected region type!");
+
+    // Check whether all predecessors are invokes or not.  Nothing exotic can
+    // occur here, only direct branches and unwinding via an invoke.
+    bool hasBranchPred = false;
+    bool hasInvokePred = false;
+    for (pred_iterator I = pred_begin(FailureBlock), E = pred_end(FailureBlock);
+         I != E && (!hasInvokePred || !hasBranchPred); ++I) {
+      TerminatorInst *T = (*I)->getTerminator();
+      if (isa<InvokeInst>(T)) {
+        assert(FailureBlock != T->getSuccessor(0) && "Expected unwind target!");
+        hasInvokePred = true;
+      } else {
+        assert(isa<BranchInst>(T) && "Wrong kind of failure predecessor!");
+        hasBranchPred = true;
+      }
+    }
+    assert((hasBranchPred || hasInvokePred) && "No predecessors!");
+
+    // Determine the landing pad that invokes will unwind to.  If there are no
+    // invokes, then there is no landing pad.
+    BasicBlock *LandingPad = NULL;
+    if (hasInvokePred) {
+      // If all predecessors are invokes, then the failure block can be used as
+      // the landing pad.  Otherwise, create a landing pad.
+      if (hasBranchPred)
+        LandingPad = BasicBlock::Create(Context, "pad");
+      else
+        LandingPad = FailureBlock;
+    }
+
+    if (LandingPad) {
+      BeginBlock(LandingPad);
+
+      // Generate an empty (i.e. catch-all) filter in the landing pad.
+      Function *ExcIntr = Intrinsic::getDeclaration(TheModule,
+                                                    Intrinsic::eh_exception);
+      Function *SlctrIntr = Intrinsic::getDeclaration(TheModule,
+                                                      Intrinsic::eh_selector);
+      Value *Args[3];
+      // The exception pointer.
+      Args[0] = Builder.CreateCall(ExcIntr, "exc_ptr");
+      // The personality function.
+      tree personality = DECL_FUNCTION_PERSONALITY(FnDecl);
+      assert(personality && "No-throw region but no personality function!");
+      Args[1] = Builder.CreateBitCast(DECL_LLVM(personality),
+                                      Type::getInt8PtrTy(Context));
+      // One more than the filter length.
+      Args[2] = ConstantInt::get(Type::getInt32Ty(Context), 1);
+      // Create the selector call.
+      Builder.CreateCall(SlctrIntr, Args, Args + 3, "filter");
+
+      if (LandingPad != FailureBlock) {
+        // Make sure all invokes unwind to the new landing pad.
+        for (pred_iterator I = pred_begin(FailureBlock),
+             E = pred_end(FailureBlock); I != E; ) {
+          TerminatorInst *T = (*I++)->getTerminator();
+          if (isa<InvokeInst>(T))
+            T->setSuccessor(1, LandingPad);
+        }
+
+        // Branch to the failure block at the end of the landing pad.
+        Builder.CreateBr(FailureBlock);
+      }
+    }
+
+    if (LandingPad != FailureBlock)
+      BeginBlock(FailureBlock);
 
     // Determine the failure function to call.
-    Value *FailFunc = DECL_LLVM(I->first);
+    Value *FailFunc = DECL_LLVM(region->u.must_not_throw.failure_decl);
 
     // Make sure it has the right type.
     FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), false);
     FailFunc = Builder.CreateBitCast(FailFunc, FTy->getPointerTo());
 
     // Spank the user for being naughty.
+    // TODO: Set the correct debug location.
     CallInst *FailCall = Builder.CreateCall(FailFunc);
 
     // This is always fatal.
@@ -2650,8 +2737,8 @@
     // an invoke rather than a simple call.
     LPadNo = lookup_stmt_eh_lp(stmt);
 
-    // Is the call in an exception handling region with a landing pad?
     if (LPadNo > 0) {
+      // The call is in an exception handling region with a landing pad.
       // Generate an invoke, with the GCC landing pad as the unwind destination.
       // The destination may change to an LLVM only landing pad,  which precedes
       // the GCC one, after phi nodes have been populated (doing things this way
@@ -2659,6 +2746,14 @@
       eh_landing_pad lp = get_eh_landing_pad_from_number(LPadNo);
       assert(lp && "Post landing pad not found!");
       LandingPad = getLabelDeclBlock(lp->post_landing_pad);
+    } else if (LPadNo < 0) {
+      eh_region region = get_eh_region_from_lp_number(LPadNo);
+      // The call is in a must-not-throw region.  Generate an invoke that causes
+      // the region's failure code to be run if an exception is thrown.
+      assert(region->type == ERT_MUST_NOT_THROW && "Unexpected region type!");
+
+      // Unwind to the block containing the failure code.
+      LandingPad = getFailureBlock(region->index);
     }
   }
 
@@ -2776,14 +2871,15 @@
     cast<InvokeInst>(Call)->setCallingConv(CallingConvention);
     cast<InvokeInst>(Call)->setAttributes(PAL);
 
-    // The invoke's destination may change to an LLVM only landing pad, which
-    // precedes the GCC one, after phi nodes have been populated (doing things
-    // this way simplifies the generation of phi nodes).  Record the invoke as
-    // well as the GCC exception handling region.
-    assert(LPadNo > 0 && "Invoke but no GCC landing pad?");
-    if ((unsigned)LPadNo >= Invokes.size())
-      Invokes.resize(LPadNo + 1);
-    Invokes[LPadNo].push_back(cast<InvokeInst>(Call));
+    if (LPadNo > 0) {
+      // The invoke's destination may change to an LLVM only landing pad, which
+      // precedes the GCC one, after phi nodes have been populated (doing things
+      // this way simplifies the generation of phi nodes).  Record the invoke as
+      // well as the GCC exception handling region.
+      if ((unsigned)LPadNo >= NormalInvokes.size())
+        NormalInvokes.resize(LPadNo + 1);
+      NormalInvokes[LPadNo].push_back(cast<InvokeInst>(Call));
+    }
 
     BeginBlock(NextBlock);
   }
@@ -7149,14 +7245,8 @@
       // call to the failure routine (eg: std::terminate).
       assert(dst_rgn->type == ERT_MUST_NOT_THROW && "Unexpected region type!");
 
-      // Look up the block containing the failure code.
-      tree failfunc = dst_rgn->u.must_not_throw.failure_decl;
-      BasicBlock *&FailureBlock = FailureCode[failfunc];
-      if (!FailureBlock)
-        FailureBlock = BasicBlock::Create(Context, "fail");
-
-      // Branch to it.
-      Builder.CreateBr(FailureBlock);
+      // Branch to the block containing the failure code.
+      Builder.CreateBr(getFailureBlock(dst_rgn->index));
       return;
     }
 

Modified: dragonegg/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-internal.h?rev=101360&r1=101359&r2=101360&view=diff
==============================================================================
--- dragonegg/trunk/llvm-internal.h (original)
+++ dragonegg/trunk/llvm-internal.h Thu Apr 15 01:55:46 2010
@@ -422,19 +422,22 @@
 
   //===---------------------- Exception Handling --------------------------===//
 
-  /// Invokes - The list of invoke instructions for a given landing pad.
-  SmallVector<SmallVector<InvokeInst *, 8>, 16> Invokes;
+  /// NormalInvokes - Mapping from landing pad number to the set of invoke
+  /// instructions that unwind to that landing pad.
+  SmallVector<SmallVector<InvokeInst *, 8>, 16> NormalInvokes;
 
-  /// ExceptionPtrs - The local holding the exception pointer for an EH region.
+  /// ExceptionPtrs - Mapping from EH region index to the local holding the
+  /// exception pointer for that region.
   SmallVector<AllocaInst *, 16> ExceptionPtrs;
 
-  /// ExceptionFilters - The local holding the filter value for an EH region.
+  /// ExceptionFilters - Mapping from EH region index to the local holding the
+  /// filter value for that region.
   SmallVector<AllocaInst *, 16> ExceptionFilters;
 
-  /// FailureCode - The block holding the failure call for the given failure
-  /// function declaration (for must-not-throw regions - this is what is called
-  /// if an exception is nonetheless thrown).
-  DenseMap<tree_node *, BasicBlock *> FailureCode;
+  /// FailureBlocks - Mapping from the index of a must-not-throw EH region to
+  /// the block containing the failure code for the region (the code that is
+  /// run if an exception is thrown in this region).
+  SmallVector<BasicBlock *, 16> FailureBlocks;
 
   /// RewindBB - Block containing code that continues unwinding an exception.
   BasicBlock *RewindBB;
@@ -554,9 +557,9 @@
   /// EmitLandingPads - Emit EH landing pads.
   void EmitLandingPads();
 
-  /// EmitFailureCode - Emit the blocks containing failure code executed when
+  /// EmitFailureBlocks - Emit the blocks containing failure code executed when
   /// an exception is thrown in a must-not-throw region.
-  void EmitFailureCode();
+  void EmitFailureBlocks();
 
   /// EmitRewindBlock - Emit the block containing code to continue unwinding an
   /// exception.
@@ -580,6 +583,10 @@
   /// given exception handling region, creating it if necessary.
   AllocaInst *getExceptionFilter(unsigned RegionNo);
 
+  /// getFailureBlock - Return the basic block containing the failure code for
+  /// the given exception handling region, creating it if necessary.
+  BasicBlock *getFailureBlock(unsigned RegionNo);
+
 private:
   void EmitAutomaticVariableDecl(tree_node *decl);
 





More information about the llvm-commits mailing list