[llvm-commits] [llvm-gcc-4-2] r39805 - in /llvm-gcc-4-2/trunk/gcc: llvm-convert.cpp llvm-internal.h

Duncan Sands baldrick at free.fr
Fri Jul 13 05:10:00 PDT 2007


Author: baldrick
Date: Fri Jul 13 07:09:59 2007
New Revision: 39805

URL: http://llvm.org/viewvc/llvm-project?rev=39805&view=rev
Log:
Forward port of [129185].

Handle nested try-catch statements: From Duncan

These patches, to LLVM and llvm-gcc, add support for nested
try-catch statements.  Previously, only the inner most
catch or filter was being taken into account.  Thanks to
inlining it is possible for a function to contain any
number of filters and catches nested within each other
(without inlining filters only occur outermost).  To support
this I've junked the eh.filter intrinsic and extended the
eh.selector intrinsic so it can simultaneously contain catches
and filters.  To indicate a filter, the number of typeinfos
in the filter is given as an argument, followed by the typeinfos
themselves.  For example,
%s = eh.selector(exception,personality,t1,2,t2,t3,t4);
has a catch (typeinfo t1) followed by a filter of length 2
(typeinfos t2 and t3) followed by another catch (typeinfo t4).
This is not very beautiful but it is simple, effective and
unambiguous.

An alternative would have been to keep eh.filter and output
multiple filter/selector intrinsics like this:
        %s1 = eh.selector(exception,personality,t4);
        %s2 = eh.filter(exception,personality,t2,t3);
        %s3 = eh.selector(exception,personality,t1);
(yes, in reverse order).  Then %s1 and %s2 would never be used,
and %s3 would be tested against the various typeinfos, even if
they were never mentioned in the %s3 selector itself (eg t4).
It also requires extra mucking around with the live-in markings
for the exception and selector registers produced during codegen.
I decided it was better to enhance eh.selector and get rid of
eh.filter.  Note that this means that eh.selector now corresponds
directly to the action sequence in the dwarf eh table.

The testcase shows the difference before and after (I've simplified
the output a bit):
Before:
  %eh_select = call @llvm.eh.filter(%eh_ptr, @__gxx_personality_v0,
        null)   ; "empty" filter [the "null" should not be here - also fixed in this patch]
After:
  %eh_select = call @llvm.eh.selector(%eh_ptr, @__gxx_personality_v0,
        i32 0,                          ; empty filter
        @_ZTI3One,                      ; catch
        i32 1, @_ZTI3Two,               ; filter of length 1
        @_ZTI5Three, @_ZTI4Four,        ; two catches
        i32 2, @_ZTI4Five, @_ZTI3Six,   ; filter of length 2
        null)                           ; catch-all

Modified:
    llvm-gcc-4-2/trunk/gcc/llvm-convert.cpp
    llvm-gcc-4-2/trunk/gcc/llvm-internal.h

Modified: llvm-gcc-4-2/trunk/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4-2/trunk/gcc/llvm-convert.cpp?rev=39805&r1=39804&r2=39805&view=diff

==============================================================================
--- llvm-gcc-4-2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4-2/trunk/gcc/llvm-convert.cpp Fri Jul 13 07:09:59 2007
@@ -350,7 +350,6 @@
   ExceptionSelectorValue = 0;
   FuncEHException = 0;
   FuncEHSelector = 0;
-  FuncEHFilter = 0;
   FuncEHGetTypeID = 0;
   FuncCPPPersonality = 0;
   FuncUnwindResume = 0; 
@@ -1965,16 +1964,18 @@
 /// GatherTypeInfo - Walk through the expression gathering all the
 /// typeinfos that are used.
 void TreeToLLVM::GatherTypeInfo(tree exp,
-                                std::vector<Value *> &TypeInfos) {
+                                std::vector<Constant *> &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(PointerType::get(Type::Int8Ty))
-      );
+      // Catch all or empty filter.
+      if (TREE_CODE(exp) == CATCH_EXPR)
+        // Catch all.
+        TypeInfos.push_back(
+          Constant::getNullValue(PointerType::get(Type::Int8Ty))
+        );
     } else if (TREE_CODE(Types) != TREE_LIST) {
       // Construct typeinfo object.  Each call will produce a new expression
       // even if duplicate.
@@ -1982,7 +1983,7 @@
       // Produce value.  Duplicate typeinfo get folded here.
       Value *TypeInfo = Emit(TypeInfoNopExpr, 0);
       // Capture typeinfo.
-      TypeInfos.push_back(TypeInfo);
+      TypeInfos.push_back(cast<Constant>(TypeInfo));
     } else {
       for (; Types; Types = TREE_CHAIN (Types)) {
         // Construct typeinfo object.  Each call will produce a new expression
@@ -1991,7 +1992,7 @@
         // Produce value.  Duplicate typeinfo get folded here.
         Value *TypeInfo = Emit(TypeInfoNopExpr, 0);
         // Capture typeinfo.
-        TypeInfos.push_back(TypeInfo);
+        TypeInfos.push_back(cast<Constant>(TypeInfo));
       }
     }
   } else if (TREE_CODE(exp) == STATEMENT_LIST) {
@@ -2007,47 +2008,53 @@
 /// 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;
-    }
-  }
-
   CreateExceptionValues();
 
   // Fetch and store the exception.
   Value *Ex = Builder.CreateCall(FuncEHException, "eh_ptr");
   Builder.CreateStore(Ex, ExceptionValue);
 
-  if (!TryCatch) return;
-  
-  // Gather the typeinfo.
-  std::vector<Value *> TypeInfos;
-  tree Catches = TREE_OPERAND(TryCatch, 1);
-  GatherTypeInfo(Catches, TypeInfos);
-  
-  // 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 exception handler.
+  // Fetch and store the exception selector.
   std::vector<Value*> Args;
-  Args.push_back(Builder.CreateLoad(ExceptionValue, "eh_ptr"));
-  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 = Builder.CreateCall(F, &Args[0], Args.size(), "eh_select");
-  Builder.CreateStore(Select, ExceptionSelectorValue);
+
+  for (std::vector<EHScope>::reverse_iterator I = CurrentEHScopes.rbegin(),
+       E = CurrentEHScopes.rend(); I != E; ++I) {
+    if (TREE_CODE(I->TryExpr) == TRY_CATCH_EXPR) {
+      if (I->InfosType == Unknown) {
+         // Gather the type info and determine the catch type.
+         tree Catches = TREE_OPERAND(I->TryExpr, 1);
+         GatherTypeInfo(Catches, I->TypeInfos);
+         I->InfosType = (TREE_CODE(Catches) == STATEMENT_LIST &&
+                         !tsi_end_p(tsi_start(Catches)) &&
+                         TREE_CODE(tsi_stmt(tsi_start(Catches))) ==
+                         EH_FILTER_EXPR) ? FilterExpr : CatchList;
+      }
+
+      if (I->InfosType == CatchList && !I->TypeInfos.size())
+        continue;
+
+      // Lazily add the exception and the personality function.
+      if (!Args.size()) {
+        Args.push_back(Builder.CreateLoad(ExceptionValue, "eh_ptr"));
+        Args.push_back(CastToType(Instruction::BitCast, FuncCPPPersonality,
+                                  PointerType::get(Type::Int8Ty)));
+      }
+
+      if (I->InfosType == FilterExpr)
+        // Filter - note the size.
+        Args.push_back(ConstantInt::get(Type::Int32Ty, I->TypeInfos.size()));
+
+      Args.reserve(Args.size() + I->TypeInfos.size());
+      for (unsigned j = 0, N = I->TypeInfos.size(); j < N; ++j)
+        Args.push_back(I->TypeInfos[j]);
+    }
+  }
+
+  if (Args.size()) {
+    Value *Select = Builder.CreateCall(FuncEHSelector, &Args[0], Args.size(),
+                                       "eh_select");
+    Builder.CreateStore(Select, ExceptionSelectorValue);
+  }
 }
 
 
@@ -2067,10 +2074,6 @@
                                               Intrinsic::eh_exception);
   FuncEHSelector  = Intrinsic::getDeclaration(TheModule,
                                               Intrinsic::eh_selector);
-#if 0 /* FIXME FIXME */
-  FuncEHFilter    = Intrinsic::getDeclaration(TheModule,
-                                              Intrinsic::eh_filter);
-#endif
   FuncEHGetTypeID = Intrinsic::getDeclaration(TheModule,
                                               Intrinsic::eh_typeid_for);
                                                       

Modified: llvm-gcc-4-2/trunk/gcc/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4-2/trunk/gcc/llvm-internal.h?rev=39805&r1=39804&r2=39805&view=diff

==============================================================================
--- llvm-gcc-4-2/trunk/gcc/llvm-internal.h (original)
+++ llvm-gcc-4-2/trunk/gcc/llvm-internal.h Fri Jul 13 07:09:59 2007
@@ -258,25 +258,38 @@
     BranchFixup(BranchInst *srcBranch, bool IsExceptionEdge)
       : SrcBranch(srcBranch), isExceptionEdge(IsExceptionEdge) {}
   };
-  
+
+  enum CatchTypes { Unknown = 0, CatchList, FilterExpr };
+
   /// EHScope - One of these scopes is maintained for each TRY_CATCH_EXPR and
   /// TRY_FINALLY_EXPR blocks that we are currently in.
   struct EHScope {
     /// TryExpr - This is the actual TRY_CATCH_EXPR or TRY_FINALLY_EXPR.
     tree_node *TryExpr;
-    
+
     /// UnwindBlock - A basic block in this scope that branches to the unwind
     /// destination.  This is lazily created by the first invoke in this scope.
     BasicBlock *UnwindBlock;
-    
+
     // The basic blocks that are directly in this region.
     std::vector<BasicBlock*> Blocks;
-    
+
     /// BranchFixups - This is a list of fixups we need to process in this scope
     /// or in a parent scope.
     std::vector<BranchFixup> BranchFixups;
-    
-    EHScope(tree_node *expr) : TryExpr(expr), UnwindBlock(0) {}
+
+    /// InfosType - The nature of the type infos TryExpr contains: a list of
+    /// CATCH_EXPR (-> CatchList) or an EH_FILTER_EXPR (-> FilterExpr).  Equal
+    /// to Unknown if type info information has not yet been gathered.
+    CatchTypes InfosType;
+
+    /// TypeInfos - The type infos corresponding to the catches or filter in
+    /// TryExpr.  If InfosType is Unknown then this information has not yet
+    /// been gathered.
+    std::vector<Constant *> TypeInfos;
+
+    EHScope(tree_node *expr) :
+        TryExpr(expr), UnwindBlock(0), InfosType(Unknown) {}
   };
   
   /// CurrentEHScopes - The current stack of exception scopes we are
@@ -305,10 +318,6 @@
   ///
   Function *FuncEHSelector;
   
-  /// FuncEHFilter - Function used to handle the exception filtering.
-  ///
-  Function *FuncEHFilter;
-
   /// FuncEHGetTypeID - Function used to return type id for give typeinfo.
   ///
   Function *FuncEHGetTypeID;
@@ -457,7 +466,7 @@
 private:
   /// GatherTypeInfo - Walk through the expression gathering all the
   /// typeinfos that are used.
-  void GatherTypeInfo(tree_node *exp, std::vector<Value *> &TypeInfos);
+  void GatherTypeInfo(tree_node *exp, std::vector<Constant *> &TypeInfos);
 
   /// AddLandingPad - Insert code to fetch and save the exception and exception
   /// selector.





More information about the llvm-commits mailing list