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

Duncan Sands baldrick at free.fr
Fri Apr 9 05:28:00 PDT 2010


Author: baldrick
Date: Fri Apr  9 07:28:00 2010
New Revision: 100857

URL: http://llvm.org/viewvc/llvm-project?rev=100857&view=rev
Log:
Handle GIMPLE_RESX, i.e. reraising of an exception.

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=100857&r1=100856&r2=100857&view=diff
==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Fri Apr  9 07:28:00 2010
@@ -239,9 +239,12 @@
 TreeToLLVM::TreeToLLVM(tree fndecl) :
     TD(getTargetData()), Builder(Context, *TheFolder) {
   FnDecl = fndecl;
+  AllocaInsertionPoint = 0;
   Fn = 0;
-  ReturnBB = UnwindBB = 0;
+  ReturnBB = 0;
   ReturnOffset = 0;
+  RewindBB = 0;
+  RewindTmp = 0;
 
   if (EmitDebugInfo()) {
     expanded_location Location = expand_location(DECL_SOURCE_LOCATION (fndecl));
@@ -255,8 +258,6 @@
     }
   }
 
-  AllocaInsertionPoint = 0;
-
   assert(TheTreeToLLVM == 0 && "Reentering function creation?");
   TheTreeToLLVM = this;
 }
@@ -990,7 +991,8 @@
 
   // Now that phi nodes have been output, emit pending exception handling code.
   EmitLandingPads();
-  EmitUnwindBlock();
+  EmitFailureCode();
+  EmitRewindBlock();
 
 #ifndef NDEBUG
   if (!errorcount && !sorrycount)
@@ -2089,33 +2091,58 @@
   Invokes.clear();
 }
 
-/// EmitUnwindBlock - Emit the lazily created EH unwind block.
-void TreeToLLVM::EmitUnwindBlock() {
-  if (UnwindBB) {
-    BeginBlock(UnwindBB);
-abort();//FIXME
-//FIXME    // Fetch and store exception handler.
-//FIXME    Value *Arg = Builder.CreateLoad(ExceptionValue, "eh_ptr");
-//FIXME    assert(llvm_unwind_resume_libfunc && "no unwind resume function!");
-//FIXME
-//FIXME    // As we're emitting a naked call (not an expression) going through
-//FIXME    // EmitCallOf would be wasteful and incorrect. Manually adjust
-//FIXME    // the calling convention for this call here if necessary.
-//FIXME#ifdef TARGET_ADJUST_LLVM_CC
-//FIXME    tree fntype = TREE_TYPE(llvm_unwind_resume_libfunc);
-//FIXME    CallingConv::ID CallingConvention = CallingConv::C;
-//FIXME
-//FIXME    TARGET_ADJUST_LLVM_CC(CallingConvention, fntype);
-//FIXME    CallInst *Call = Builder.CreateCall(DECL_LOCAL(llvm_unwind_resume_libfunc),
-//FIXME                                       Arg);
-//FIXME    Call->setCallingConv(CallingConvention);
-//FIXME#else
-//FIXME    Builder.CreateCall(DECL_LOCAL(llvm_unwind_resume_libfunc), Arg);
-//FIXME#endif
+/// EmitFailureCode - 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);
+
+    // Determine the failure function to call.
+    Value *FailFunc = DECL_LLVM(I->first);
+
+    // 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.
+    CallInst *FailCall = Builder.CreateCall(FailFunc);
+
+    // This is always fatal.
+    FailCall->setDoesNotReturn();
+    FailCall->setDoesNotThrow();
     Builder.CreateUnreachable();
   }
 }
 
+/// EmitRewindBlock - Emit the block containing code to continue unwinding an
+/// exception.
+void TreeToLLVM::EmitRewindBlock() {
+  if (!RewindBB)
+    return;
+
+  BeginBlock (RewindBB);
+
+  // The exception pointer to continue unwinding.
+  assert(RewindTmp && "Rewind block but nothing to unwind?");
+  Value *ExcPtr = Builder.CreateLoad(RewindTmp);
+
+  // Generate an explicit call to _Unwind_Resume_or_Rethrow.
+  std::vector<const Type*> Params(1, Type::getInt8PtrTy(Context));
+  FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), Params,
+                                        false);
+  Constant *RewindFn =
+    TheModule->getOrInsertFunction("_Unwind_Resume_or_Rethrow", FTy);
+
+  // Pass it to _Unwind_Resume_or_Rethrow.
+  CallInst *Rewind = Builder.CreateCall(RewindFn, ExcPtr);
+
+  // This call does not return.
+  Rewind->setDoesNotReturn();
+  Builder.CreateUnreachable();
+}
+
+
 //===----------------------------------------------------------------------===//
 //                           ... Expressions ...
 //===----------------------------------------------------------------------===//
@@ -7013,7 +7040,9 @@
     // The result of a filter selection will be a negative index if there is a
     // match.
     // FIXME: It looks like you have to compare against a specific value,
-    // checking for any old negative number is not enough!
+    // checking for any old negative number is not enough!  This should not
+    // matter if the failure code branched to on a filter match is always the
+    // same (as in C++), but might cause problems with other languages.
     Value *Filter = Builder.CreateLoad(getExceptionFilter(RegionNo));
 
     // Compare with the filter action value.
@@ -7094,27 +7123,62 @@
 }
 
 void TreeToLLVM::RenderGIMPLE_RESX(gimple stmt) {
-  Builder.CreateUnreachable(); // FIXME
-//FIXME  int RegionNo = gimple_resx_region(stmt);
-//FIXME  std::vector<eh_region> Handlers;
-//FIXME
-//FIXME  foreach_reachable_handler(RegionNo, true, false, AddHandler, &Handlers);
-//FIXME
-//FIXME  if (!Handlers.empty()) {
-//FIXME    for (std::vector<eh_region>::iterator I = Handlers.begin(),
-//FIXME         E = Handlers.end(); I != E; ++I)
-//FIXME      // Create a post landing pad for the handler.
-//FIXME      getPostPad(get_eh_region_number(*I));
-//FIXME
-//FIXME    Builder.CreateBr(getPostPad(get_eh_region_number(*Handlers.begin())));
-//FIXME  } else {
-//FIXME    assert(can_throw_external_1(RegionNo, true, false) &&
-//FIXME           "Must-not-throw region handled by runtime?");
-//FIXME    // Unwinding continues in the caller.
-//FIXME    if (!UnwindBB)
-//FIXME      UnwindBB = BasicBlock::Create(Context, "Unwind");
-//FIXME    Builder.CreateBr(UnwindBB);
-//FIXME  }
+  // Reraise an exception.  If this statement is inside an exception handling
+  // region then the reraised exception may be caught by the current function,
+  // in which case it can be simplified into a branch.
+  int DstLPadNo = lookup_stmt_eh_lp(stmt);
+  eh_region dst_rgn = DstLPadNo ? get_eh_region_from_lp_number(DstLPadNo) : NULL;
+  eh_region src_rgn = get_eh_region_from_number(gimple_resx_region(stmt));
+
+  if (!src_rgn) {
+    // Unreachable block?
+    Builder.CreateUnreachable();
+    return;
+  }
+
+  if (dst_rgn) {
+    if (DstLPadNo < 0) {
+      // The reraise is inside a must-not-throw region.  Turn the reraise into a
+      // 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);
+      return;
+    }
+
+    // Use the exception pointer and filter value for the source region as the
+    // values for the destination region.
+    Value *ExcPtr = Builder.CreateLoad(getExceptionPtr(src_rgn->index));
+    Builder.CreateStore(ExcPtr, getExceptionPtr(dst_rgn->index));
+    Value *Filter = Builder.CreateLoad(getExceptionFilter(src_rgn->index));
+    Builder.CreateStore(Filter, getExceptionFilter(dst_rgn->index));
+
+    // Branch to the post landing pad for the destination region.
+    eh_landing_pad lp = get_eh_landing_pad_from_number(DstLPadNo);
+    assert(lp && "Post landing pad not found!");
+    Builder.CreateBr(getLabelDeclBlock(lp->post_landing_pad));
+    return;
+  }
+
+  // The exception unwinds out of the function.  Note the exception to unwind.
+  if (!RewindTmp) {
+    RewindTmp = CreateTemporary(Type::getInt8PtrTy(Context));
+    RewindTmp->setName("rewind_tmp");
+  }
+  Value *ExcPtr = Builder.CreateLoad(getExceptionPtr(src_rgn->index));
+  Builder.CreateStore(ExcPtr, RewindTmp);
+
+  // Jump to the block containing the rewind code.
+  if (!RewindBB)
+    RewindBB = BasicBlock::Create(Context, "rewind");
+  Builder.CreateBr(RewindBB);
 }
 
 void TreeToLLVM::RenderGIMPLE_RETURN(gimple stmt) {

Modified: dragonegg/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-internal.h?rev=100857&r1=100856&r2=100857&view=diff
==============================================================================
--- dragonegg/trunk/llvm-internal.h (original)
+++ dragonegg/trunk/llvm-internal.h Fri Apr  9 07:28:00 2010
@@ -31,7 +31,6 @@
 #include "llvm/CallingConv.h"
 #include "llvm/Intrinsics.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/IndexedMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/Support/IRBuilder.h"
@@ -360,7 +359,6 @@
   tree_node *FnDecl;
   Function *Fn;
   BasicBlock *ReturnBB;
-  BasicBlock *UnwindBB;
   unsigned ReturnOffset;
 
   // State that changes as the function is emitted.
@@ -427,12 +425,23 @@
   /// Invokes - The list of invoke instructions for a given landing pad.
   SmallVector<SmallVector<InvokeInst *, 8>, 16> Invokes;
 
-  /// ExceptionPtrs - The local holding the exception pointer for a EH region.
+  /// ExceptionPtrs - The local holding the exception pointer for an EH region.
   SmallVector<AllocaInst *, 16> ExceptionPtrs;
 
-  /// ExceptionFilters - The local holding the filter value for a EH region.
+  /// ExceptionFilters - The local holding the filter value for an EH 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;
+
+  /// RewindBB - Block containing code that continues unwinding an exception.
+  BasicBlock *RewindBB;
+
+  /// RewindTmp - Local holding the exception to continue unwinding.
+  AllocaInst *RewindTmp;
+
 public:
   TreeToLLVM(tree_node *fndecl);
   ~TreeToLLVM();
@@ -545,8 +554,13 @@
   /// EmitLandingPads - Emit EH landing pads.
   void EmitLandingPads();
 
-  /// EmitUnwindBlock - Emit the lazily created EH unwind block.
-  void EmitUnwindBlock();
+  /// EmitFailureCode - Emit the blocks containing failure code executed when
+  /// an exception is thrown in a must-not-throw region.
+  void EmitFailureCode();
+
+  /// EmitRewindBlock - Emit the block containing code to continue unwinding an
+  /// exception.
+  void EmitRewindBlock();
 
   /// EmitDebugInfo - Return true if debug info is to be emitted for current
   /// function.





More information about the llvm-commits mailing list