[llvm-commits] [124438] EH support.

jlaskey at apple.com jlaskey at apple.com
Thu Mar 1 15:11:14 PST 2007


Revision: 124438
Author:   jlaskey
Date:     2007-03-01 15:11:13 -0800 (Thu, 01 Mar 2007)

Log Message:
-----------
EH support.

Modified Paths:
--------------
    apple-local/branches/llvm/gcc/llvm-convert.cpp
    apple-local/branches/llvm/gcc/llvm-internal.h

Modified: apple-local/branches/llvm/gcc/llvm-convert.cpp
===================================================================
--- apple-local/branches/llvm/gcc/llvm-convert.cpp	2007-03-01 10:54:52 UTC (rev 124437)
+++ apple-local/branches/llvm/gcc/llvm-convert.cpp	2007-03-01 23:11:13 UTC (rev 124438)
@@ -58,10 +58,13 @@
 #include "flags.h"
 #include "target.h"
 #include "hard-reg-set.h"
+#include "except.h"
 extern bool tree_could_throw_p(tree);  // tree-flow.h uses non-C++ C constructs.
 extern int get_pointer_alignment (tree exp, unsigned int max_align);
 }
 
+#define ITANIUM_STYLE_EXCEPTIONS
+
 //===----------------------------------------------------------------------===//
 //                   Matching LLVM Values with GCC DECL trees
 //===----------------------------------------------------------------------===//
@@ -261,6 +264,16 @@
   }
 
   AllocaInsertionPoint = 0;
+  
+  ExceptionValue = 0;
+  ExceptionSelectorValue = 0;
+  FuncEHException = 0;
+  FuncEHSelector = 0;
+  FuncEHFilter = 0;
+  FuncEHGetTypeID = 0;
+  FuncCPPPersonality = 0;
+  FuncUnwindResume = 0; 
+  
   NumAddressTakenBlocks = 0;
   IndirectGotoBlock = 0;
   CurrentEHScopes.reserve(16);
@@ -596,7 +609,19 @@
   // If this function has exceptions, emit the lazily created unwind block.
   if (UnwindBB) {
     EmitBlock(UnwindBB);
+#ifdef ITANIUM_STYLE_EXCEPTIONS
+    if (ExceptionValue) {
+      // Fetch and store exception handler.
+      std::vector<Value*> Args;
+      Args.push_back(new LoadInst(ExceptionValue, "eh_ptr", CurBB));
+      new CallInst(FuncUnwindResume,
+                   &Args[0], Args.size(), "",
+                   CurBB);
+      new UnreachableInst(CurBB);
+    }
+#else
     new UnwindInst(UnwindBB);
+#endif
   }
   
   // If this function takes the address of a label, emit the indirect goto
@@ -640,15 +665,8 @@
     std::cerr << "Unhandled expression!\n";
     debug_tree(exp);
     abort();
-  case EH_FILTER_EXPR:
-  case CATCH_EXPR: {
-    static bool PrintedWarning = false;
-    if (!PrintedWarning) std::cerr << "WARNING: EH not supported yet!\n";
-    PrintedWarning = true;
-    return 0;
-  }
     
-    // Basic lists and binding scopes
+  // Basic lists and binding scopes
   case BIND_EXPR:      Result = EmitBIND_EXPR(exp, DestLoc); break;
   case STATEMENT_LIST: Result = EmitSTATEMENT_LIST(exp, DestLoc); break;
 
@@ -660,6 +678,9 @@
   case SWITCH_EXPR:    Result = EmitSWITCH_EXPR(exp); break;
   case TRY_FINALLY_EXPR:
   case TRY_CATCH_EXPR: Result = EmitTRY_EXPR(exp); break;
+  case EXC_PTR_EXPR:   Result = EmitEXC_PTR_EXPR(exp); break;
+  case CATCH_EXPR:     Result = EmitCATCH_EXPR(exp); break;
+  case EH_FILTER_EXPR: Result = EmitEH_FILTER_EXPR(exp); break;
     
   // Expressions
   case VAR_DECL:
@@ -1737,6 +1758,132 @@
   walk_tree_without_duplicates(&code, StripLLVMTranslationFn, 0);
 }
 
+
+/// GatherTypeInfo - Walk through the expression gathering all the
+/// typeinfos that are used.
+void TreeToLLVM::GatherTypeInfo(tree exp,
+                                std::vector<Value *> &TypeInfos) {
+  if (TREE_CODE(exp) == CATCH_EXPR || TREE_CODE(exp) == EH_FILTER_EXPR) {
+    tree Types = TREE_CODE(exp) == CATCH_EXPR ? CATCH_TYPES(exp)
+                                              : EH_FILTER_TYPES(exp);
+
+    if (!Types) {
+      // Catch all.
+      TypeInfos.push_back(Constant::getNullValue(Type::Int32Ty));
+    } else if (TREE_CODE(Types) != TREE_LIST) {
+      // Construct typeinfo object.  Each call will produce a new expression
+      // even if duplicate.
+      tree TypeInfoNopExpr = (*lang_eh_runtime_type)(Types);
+      // Produce value.  Duplicate typeinfo get folded here.
+      Value *TypeInfo = Emit(TypeInfoNopExpr, 0);
+      // Capture typeinfo.
+      TypeInfos.push_back(TypeInfo);
+    } else {
+      for (; Types; Types = TREE_CHAIN (Types)) {
+        // Construct typeinfo object.  Each call will produce a new expression
+        // even if duplicate.
+        tree TypeInfoNopExpr = (*lang_eh_runtime_type)(TREE_VALUE(Types));
+        // Produce value.  Duplicate typeinfo get folded here.
+        Value *TypeInfo = Emit(TypeInfoNopExpr, 0);
+        // Capture typeinfo.
+        TypeInfos.push_back(TypeInfo);
+      }
+    }
+  } else {
+    assert(TREE_CODE(exp) == STATEMENT_LIST && "Need an exp with typeinfo");
+    // Each statement in the statement list will be a catch.
+    for (tree_stmt_iterator I = tsi_start(exp); !tsi_end_p(I); tsi_next(&I))
+      GatherTypeInfo(tsi_stmt(I), TypeInfos);
+  }
+}
+
+
+/// AddLandingPad - Insert code to fetch and save the exception and exception
+/// selector.
+void TreeToLLVM::AddLandingPad() {
+  tree TryCatch = 0;
+  for (std::vector<EHScope>::reverse_iterator I = CurrentEHScopes.rbegin(),
+                                              E = CurrentEHScopes.rend();
+       I != E; ++I) {
+    if (TREE_CODE(I->TryExpr) == TRY_CATCH_EXPR) {
+      TryCatch = I->TryExpr;
+      break;
+    }
+  }
+  
+  if (!TryCatch) return;
+  
+  // Gather the typeinfo.
+  std::vector<Value *> TypeInfos;
+  tree Catches = TREE_OPERAND(TryCatch, 1);
+  GatherTypeInfo(Catches, TypeInfos);
+  
+  CreateExceptionValues();
+  
+  // Choose type of landing pad type.
+  Function *F = FuncEHSelector;
+  
+  if (TREE_CODE(Catches) == STATEMENT_LIST &&
+      !tsi_end_p(tsi_start(Catches)) &&
+      TREE_CODE(tsi_stmt(tsi_start(Catches))) == EH_FILTER_EXPR) {
+    F = FuncEHFilter;
+  }
+  
+  // Fetch and store the exception.
+  Value *Ex = new CallInst(FuncEHException, "eh_ptr", CurBB);
+  new StoreInst(Ex, ExceptionValue, CurBB);
+        
+  // Fetch and store exception handler.
+  std::vector<Value*> Args;
+  Args.push_back(new LoadInst(ExceptionValue, "eh_ptr", CurBB));
+  Args.push_back(CastToType(Instruction::BitCast, FuncCPPPersonality,
+                            PointerType::get(Type::Int8Ty)));
+  for (unsigned i = 0, N = TypeInfos.size(); i < N; ++i)
+    Args.push_back(TypeInfos[i]);
+  Value *Select = new CallInst(F, &Args[0], Args.size(), "eh_select", CurBB);
+  new StoreInst(Select, ExceptionSelectorValue, CurBB);
+}
+
+
+/// CreateExceptionValues - Create values used internally by exception handling.
+///
+void TreeToLLVM::CreateExceptionValues() {
+  // Check to see if the exception values have been constructed.
+  if (ExceptionValue) return;
+  
+  ExceptionValue = CreateTemporary(PointerType::get(Type::Int8Ty));
+  ExceptionValue->setName("eh_exception");
+  
+  ExceptionSelectorValue = CreateTemporary(Type::Int32Ty);
+  ExceptionSelectorValue->setName("eh_selector");
+  
+  FuncEHException = Intrinsic::getDeclaration(TheModule,
+                                              Intrinsic::eh_exception);
+  FuncEHSelector  = Intrinsic::getDeclaration(TheModule,
+                                              Intrinsic::eh_selector);
+  FuncEHFilter    = Intrinsic::getDeclaration(TheModule,
+                                              Intrinsic::eh_filter);
+  FuncEHGetTypeID = Intrinsic::getDeclaration(TheModule,
+                                              Intrinsic::eh_typeid_for);
+                                                      
+  FuncCPPPersonality = cast<Function>(
+    TheModule->getOrInsertFunction("__gxx_personality_v0",
+                                   Type::getPrimitiveType(Type::VoidTyID),
+                                   NULL));
+  FuncCPPPersonality->setLinkage(Function::ExternalLinkage);
+  FuncCPPPersonality->setCallingConv(CallingConv::C);
+
+  FuncUnwindResume = cast<Function>(
+    TheModule->getOrInsertFunction("_Unwind_Resume",
+                                   Type::getPrimitiveType(Type::VoidTyID),
+                                   PointerType::get(Type::Int8Ty),
+                                   NULL));
+  FuncUnwindResume->setLinkage(Function::ExternalLinkage);
+  FuncUnwindResume->setCallingConv(CallingConv::C);
+
+}
+
+
 /// EmitTRY_EXPR - Handle TRY_FINALLY_EXPR and TRY_CATCH_EXPR.
 Value *TreeToLLVM::EmitTRY_EXPR(tree exp) {
   // The C++ front-end produces a lot of TRY_FINALLY_EXPR nodes that have empty
@@ -1847,32 +1994,40 @@
     // Add a basic block to emit the code into.
     BasicBlock *CleanupBB = new BasicBlock("cleanup");
     EmitBlock(CleanupBB);
-
+    
+    // Provide exit point for cleanup code.
+    FinallyStack.push_back(FinallyBlock);
+    
     // Emit the code.
     Emit(CleanupCode, 0);
 
+    // Clear exit point for cleanup code.
+    FinallyStack.pop_back();
+
     // Because we can emit the same cleanup in more than one context, we must
     // strip off LLVM information from the decls in the code.  Otherwise, the
     // we will try to insert the same label into multiple places in the code.
     StripLLVMTranslation(CleanupCode);
+     
     
-    // Because we can emit the same cleanup in more than one context, we must
-    // strip off LLVM information from the decls in the code.  Otherwise, the
-    // we will try to insert the same label into multiple places in the code.
-    //StripLLVMTranslation(CleanupCode);
+    // Catches will supply own terminator.
+    if (!CurBB->getTerminator()) {
+      // Emit a branch to the new target.
+      BranchInst *BI = new BranchInst(FixupBr->getSuccessor(0), CurBB);
     
-    // Emit a branch to the new target.
-    BranchInst *BI = new BranchInst(FixupBr->getSuccessor(0), CurBB);
+      // The old branch now goes to the cleanup block.
+      FixupBr->setSuccessor(0, CleanupBB);
     
-    // The old branch now goes to the cleanup block.
-    FixupBr->setSuccessor(0, CleanupBB);
-    
-    // Fixup this new branch now.
-    FixupBr = BI;
-    
-    // Add the fixup to the next cleanup scope if there is one.
-    if (!CurrentEHScopes.empty())
-      AddBranchFixup(FixupBr, FixupIsExceptionEdge);
+      // Fixup this new branch now.
+      FixupBr = BI;
+      
+      // Add the fixup to the next cleanup scope if there is one.
+      if (!CurrentEHScopes.empty())
+        AddBranchFixup(FixupBr, FixupIsExceptionEdge);
+    } else {
+      // The old branch now goes to the cleanup block.
+      FixupBr->setSuccessor(0, CleanupBB);
+    }
   }
 
   // Move the finally block to the end of the function so we can continue
@@ -1895,6 +2050,138 @@
 }
 
 
+/// EmitCATCH_EXPR - Handle CATCH_EXPR.
+///
+Value *TreeToLLVM::EmitCATCH_EXPR(tree exp) {
+#ifndef ITANIUM_STYLE_EXCEPTIONS
+  return 0;
+#endif
+
+  // Make sure we have all the exception values in place.
+  CreateExceptionValues();
+
+  // Break out parts of catch.
+  tree Types = CATCH_TYPES(exp);
+  tree Body = CATCH_BODY(exp);
+  
+  // Destinations of the catch entry conditions.
+  BasicBlock *ThenBlock = 0;
+  BasicBlock *ElseBlock = 0;
+  
+  // FiXME - Determine last case so we don't need to emit test.
+  if (!Types) {
+    // Catch all - no testing required.
+  } else if (TREE_CODE(Types) != TREE_LIST) {
+    // Construct typeinfo object.  Each call will produce a new expression
+    // even if duplicate.
+    tree TypeInfoNopExpr = (*lang_eh_runtime_type)(Types);
+    // Produce value.  Duplicate typeinfo get folded here.
+    Value *TypeInfo = Emit(TypeInfoNopExpr, 0);
+
+    // Call get eh type id.
+    std::vector<Value*> Args;
+    Args.push_back(TypeInfo);
+    Value *TypeID = new CallInst(cast<Value>(FuncEHGetTypeID),
+                                 &Args[0], Args.size(), "eh_typeid", CurBB);
+    Value *Select = new LoadInst(ExceptionSelectorValue, "tmp", CurBB);
+
+    // Compare with the exception selector.
+    Value *Compare =
+           new ICmpInst(ICmpInst::ICMP_EQ, Select, TypeID, "tmp", CurBB);
+    ThenBlock = new BasicBlock("eh_then");
+    ElseBlock = new BasicBlock("eh_else");
+    
+    // Branch on the compare.
+    new BranchInst(ThenBlock, ElseBlock, Compare, CurBB);
+  } else {
+    ThenBlock = new BasicBlock("eh_then");
+  
+    for (; Types; Types = TREE_CHAIN (Types)) {
+      if (ElseBlock) EmitBlock(ElseBlock);
+    
+      // Construct typeinfo object.  Each call will produce a new expression
+      // even if duplicate.
+      tree TypeInfoNopExpr = (*lang_eh_runtime_type)(TREE_VALUE(Types));
+      // Produce value.  Duplicate typeinfo get folded here.
+      Value *TypeInfo = Emit(TypeInfoNopExpr, 0);
+
+      // Call get eh type id.
+      std::vector<Value*> Args;
+      Args.push_back(TypeInfo);
+      Value *TypeID = new CallInst(cast<Value>(FuncEHGetTypeID),
+                                 &Args[0], Args.size(), "eh_typeid", CurBB);
+      Value *Select = new LoadInst(ExceptionSelectorValue, "tmp", CurBB);
+
+      // Compare with the exception selector.
+      Value *Compare =
+             new ICmpInst(ICmpInst::ICMP_EQ, Select, TypeID, "tmp", CurBB);
+      ElseBlock = new BasicBlock("eh_else");
+      
+      // Branch on the compare.
+      new BranchInst(ThenBlock, ElseBlock, Compare, CurBB);
+    }
+  }
+  
+  // Start the then block.
+  if (ThenBlock) EmitBlock(ThenBlock);
+  
+  // Emit the body.
+  Emit(Body, 0);
+
+  // Branch to the try exit.
+  assert(!FinallyStack.empty() && "Need an exit point");
+  if (!CurBB->getTerminator())
+    new BranchInst(FinallyStack.back(), CurBB);
+
+  // Start the else block.
+  if (ElseBlock) EmitBlock(ElseBlock);
+  
+  return 0;
+}
+
+/// EmitEXC_PTR_EXPR - Handle EXC_PTR_EXPR.
+///
+Value *TreeToLLVM::EmitEXC_PTR_EXPR(tree exp) {
+#ifndef ITANIUM_STYLE_EXCEPTIONS
+  return 0;
+#endif
+
+  // Load exception address.
+  CreateExceptionValues();
+  return new LoadInst(ExceptionValue, "eh_value", CurBB);
+}
+
+/// EmitEH_FILTER_EXPR - Handle EH_FILTER_EXPR.
+///
+Value *TreeToLLVM::EmitEH_FILTER_EXPR(tree exp) {
+#ifndef ITANIUM_STYLE_EXCEPTIONS
+  return 0;
+#endif
+
+  CreateExceptionValues();
+
+  // The result of a filter landing pad will be a negative index if there is
+  // a match.
+  Value *Select = new LoadInst(ExceptionSelectorValue, "tmp", CurBB);
+
+  // Compare with the filter action value.
+  Value *Zero = ConstantInt::get(Type::Int32Ty, 0);
+  Value *Compare =
+         new ICmpInst(ICmpInst::ICMP_SLT, Select, Zero, "tmp", CurBB);
+  
+  // Branch on the compare.
+  BasicBlock *FilterBB = new BasicBlock("filter");
+  BasicBlock *NoFilterBB = new BasicBlock("nofilter");
+  new BranchInst(FilterBB, NoFilterBB, Compare, CurBB);
+
+  EmitBlock(FilterBB);
+  Emit(EH_FILTER_FAILURE(exp), 0);
+  
+  EmitBlock(NoFilterBB);
+  
+  return 0;
+}
+
 //===----------------------------------------------------------------------===//
 //                           ... Expressions ...
 //===----------------------------------------------------------------------===//
@@ -2170,13 +2457,6 @@
     if (UnwindBB == 0)
       UnwindBB = new BasicBlock("Unwind");
     UnwindBlock = UnwindBB;
-FIXME: "Call terminate if needed!";
-#if 0
-    if (ThrownExceptionsCallTerminate())
-      UnwindBlock = getTerminateBlock();
-    else
-      UnwindBlock = getInvokeDestination();
-#endif
   }
   
   SmallVector<Value*, 16> CallOperands;
@@ -2264,10 +2544,16 @@
     // branch in.
     if (CurrentEHScopes.back().UnwindBlock == 0) {
       EmitBlock(CurrentEHScopes.back().UnwindBlock = new BasicBlock("unwind"));
-      // This branch to the unwind edge should have exception cleanups inserted
-      // onto it.
+      
+#ifdef ITANIUM_STYLE_EXCEPTIONS
+      // Add landing pad entry code.
+      AddLandingPad();
+#endif
+      // This branch to the unwind edge should have exception cleanups
+      // inserted onto it.
       EmitBranchInternal(UnwindBlock, true);
     }
+
     cast<InvokeInst>(Call)->setUnwindDest(CurrentEHScopes.back().UnwindBlock);
     
     EmitBlock(NextBlock);

Modified: apple-local/branches/llvm/gcc/llvm-internal.h
===================================================================
--- apple-local/branches/llvm/gcc/llvm-internal.h	2007-03-01 10:54:52 UTC (rev 124437)
+++ apple-local/branches/llvm/gcc/llvm-internal.h	2007-03-01 23:11:13 UTC (rev 124438)
@@ -242,6 +242,42 @@
   /// this map.
   std::map<BasicBlock*, unsigned> BlockEHScope;
   
+  /// ExceptionValue - Is the local to receive the current exception.
+  /// 
+  Value *ExceptionValue;
+  
+  /// ExceptionSelectorValue - Is the local to receive the current exception
+  /// selector.
+  Value *ExceptionSelectorValue;
+  
+  /// FuncEHException - Function used to receive the exception.
+  ///
+  Function *FuncEHException;
+  
+  /// FuncEHSelector - Function used to receive the exception selector.
+  ///
+  Function *FuncEHSelector;
+  
+  /// FuncEHFilter - Function used to handle the exception filtering.
+  ///
+  Function *FuncEHFilter;
+
+  /// FuncEHGetTypeID - Function used to return type id for give typeinfo.
+  ///
+  Function *FuncEHGetTypeID;
+  
+  /// FuncCPPPersonality - Function handling c++ personality.
+  ///
+  Function *FuncCPPPersonality;
+  
+  /// FuncUnwindResume - Function used to continue exception unwinding.
+  ///
+  Function *FuncUnwindResume;
+  
+  /// FinallyStack - Stack for nested try exit points.
+  ///
+  std::vector<BasicBlock *> FinallyStack;
+  
   /// NumAddressTakenBlocks - Count the number of labels whose addresses are
   /// taken.
   uint64_t NumAddressTakenBlocks;
@@ -368,6 +404,18 @@
 
   void HandleMultiplyDefinedGCCTemp(tree_node *var);
 private:
+  /// GatherTypeInfo - Walk through the expression gathering all the
+  /// typeinfos that are used.
+  void GatherTypeInfo(tree_node *exp, std::vector<Value *> &TypeInfos);
+
+  /// AddLandingPad - Insert code to fetch and save the exception and exception
+  /// selector.
+  void AddLandingPad();
+
+  /// CreateExceptionValues - Create values used internally by exception handling.
+  ///
+  void CreateExceptionValues();
+
   // Emit* - These are delgates from Emit, and have the same parameter
   // characteristics.
     
@@ -382,6 +430,9 @@
   Value *EmitCOND_EXPR(tree_node *exp);
   Value *EmitSWITCH_EXPR(tree_node *exp);
   Value *EmitTRY_EXPR(tree_node *exp);
+  Value *EmitCATCH_EXPR(tree_node *exp);
+  Value *EmitEXC_PTR_EXPR(tree_node *exp);
+  Value *EmitEH_FILTER_EXPR(tree_node *exp);
   
   // Expressions.
   void   EmitINTEGER_CST_Aggregate(tree_node *exp, Value *DestLoc);





More information about the llvm-commits mailing list