[llvm-commits] [llvm] r41484 - in /llvm/trunk: docs/ExceptionHandling.html include/llvm/CodeGen/MachineModuleInfo.h lib/CodeGen/MachineModuleInfo.cpp lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Duncan Sands baldrick at free.fr
Mon Aug 27 08:47:51 PDT 2007


Author: baldrick
Date: Mon Aug 27 10:47:50 2007
New Revision: 41484

URL: http://llvm.org/viewvc/llvm-project?rev=41484&view=rev
Log:
There is an impedance matching problem between LLVM and
gcc exception handling: if an exception unwinds through
an invoke, then execution must branch to the invoke's
unwind target.  We previously tried to enforce this by
appending a cleanup action to every selector, however
this does not always work correctly due to an optimization
in the C++ unwinding runtime: if only cleanups would be
run while unwinding an exception, then the program just
terminates without actually executing the cleanups, as
invoke semantics would require.  I was hoping this
wouldn't be a problem, but in fact it turns out to be the
cause of all the remaining failures in the LLVM testsuite
(these also fail with -enable-correct-eh-support, so turning
on -enable-eh didn't make things worse!).  Instead we need
to append a full-blown catch-all to the end of each
selector.  The correct way of doing this depends on the
personality function, i.e. it is language dependent, so
can only be done by gcc.  Thus this patch which generalizes
the eh.selector intrinsic so that it can handle all possible
kinds of action table entries (before it didn't accomodate
cleanups): now 0 indicates a cleanup, and filters have to be
specified using the number of type infos plus one rather than
the number of type infos.  Related gcc patches will cause
Ada to pass a cleanup (0) to force the selector to always
fire, while C++ will use a C++ catch-all (null).

Modified:
    llvm/trunk/docs/ExceptionHandling.html
    llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h
    llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Modified: llvm/trunk/docs/ExceptionHandling.html
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ExceptionHandling.html?rev=41484&r1=41483&r2=41484&view=diff

==============================================================================
--- llvm/trunk/docs/ExceptionHandling.html (original)
+++ llvm/trunk/docs/ExceptionHandling.html Mon Aug 27 10:47:50 2007
@@ -22,8 +22,9 @@
   <ol>
     <li><a href="#throw">Throw</a></li>
     <li><a href="#try_catch">Try/Catch</a></li>
-    <li><a href="#finallys">Finallys</a></li>
+    <li><a href="#cleanups">Cleanups</a></li>
     <li><a href="#throw_filters">Throw Filters</a></li>
+    <li><a href="#restrictions">Restrictions</a></li>
   </ol></li>
   <li><a href="#format_common_intrinsics">Exception Handling Intrinsics</a>
   <ol>
@@ -212,17 +213,19 @@
 three arguments.  The first argument is the reference to the exception
 structure. The second argument is a reference to the personality function to be
 used for this try catch sequence. Each of the remaining arguments is either a
-reference to the type info for a catch statement, or a non-negative integer
-followed by that many type info references, representing a
-<a href="#throw_filters">filter</a>.
+reference to the type info for a catch statement,
+a <a href="#throw_filters">filter</a> expression,
+or the number zero representing a <a href="#cleanups">cleanup</a>.
 The exception is tested against the arguments sequentially from first to last.
-The <i>catch all</i> (...) is represented with a <tt>null i8*</tt>.  The result
-of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is a positive
-number if the exception matched a type info, a negative number if it matched a
-filter, and zero if it didn't match anything.  If a type info matched then the
-returned value is the index of the type info in the exception table.
-The LLVM C++ front end generates code to save this value in an alloca location
-for further use in the landing pad and catch code.</p>
+The result of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is a
+positive number if the exception matched a type info, a negative number if it matched
+a filter, and zero if it matched a cleanup.  If nothing is matched, the behaviour of
+the program is <a href="#restrictions">undefined</a>.
+The LLVM C++ front end generates code to save the selector value in an alloca
+location for further use in the landing pad and catch code.
+If a type info matched then the selector value is the index of the type info in
+the exception table, which can be obtained using the
+<a href="#llvm_eh_typeid_for"><tt>llvm.eh.typeid.for</tt></a> intrinsic.</p>
 
 <p>Once the landing pad has the type info selector, the code branches to the
 code for the first catch.  The catch then checks the value of the type info
@@ -249,7 +252,7 @@
 
 <!-- ======================================================================= -->
 <div class="doc_subsection">
-  <a name="finallys">Finallys</a>
+  <a name="cleanups">Cleanups</a>
 </div>
 
 <div class="doc_text">
@@ -258,7 +261,12 @@
 from a landing pad to the first catch.  Control may actually flow from the
 landing pad to clean up code and then to the first catch.  Since the required
 clean up for each invoke in a try may be different (ex., intervening
-constructor), there may be several landing pads for a given try.</p>
+constructor), there may be several landing pads for a given try.  If cleanups
+need to be run, the number zero should be passed as the last
+<a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> argument.
+However for C++ a <tt>null i8*</tt> <a href="#restrictions">must</a> be passed
+instead.
+</p>
 
 </div>
 
@@ -273,8 +281,8 @@
 a function.  To represent this a top level landing pad may exist to filter out
 invalid types.  To express this in LLVM code the landing pad will call <a
 href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a>.  The arguments are the
-number of different type infos the function may throw, followed by the type
-infos themselves.
+length of the filter expression (the number of type infos plus one), followed by
+the type infos themselves.
 <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> will return a negative
 value if the exception does not match any of the type infos.  If no match is
 found then a call to <tt>__cxa_call_unexpected</tt> should be made, otherwise
@@ -284,6 +292,34 @@
 </div>
 
 <!-- ======================================================================= -->
+<div class="doc_subsection">
+  <a name="restrictions">Restrictions</a>
+</div>
+
+<div class="doc_text">
+
+<p>The semantics of the invoke instruction require that any exception that
+unwinds through an invoke call should result in a branch to the invoke's unwind
+label.  However such a branch will only happen if the
+<a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> matches.
+Thus in order to ensure correct operation, the front-end must only generate
+<a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> calls that are
+guaranteed to always match whatever exception unwinds through the invoke.
+For most languages it is enough to pass zero, indicating the presence of
+a <a href="#cleanups">cleanup</a>, as the last
+<a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> argument.
+However for C++ this is not sufficient, because the C++ personality function
+will terminate the program if it detects that unwinding the exception only
+results in matches with cleanups.  For C++ a <tt>null i8*</tt> should
+be passed as the last
+<a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> argument instead.
+This is interpreted as a catch-all by the C++ personality function, and will
+always match.
+</p>
+
+</div>
+
+<!-- ======================================================================= -->
 <div class="doc_section">
   <a name="format_common_intrinsics">Exception Handling Intrinsics</a>
 </div>
@@ -330,16 +366,18 @@
 <p><a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> takes a minimum of
 three arguments.  The first argument is the reference to the exception
 structure. The second argument is a reference to the personality function to be
-used for this try catch sequence.  Each of the remaining arguments is either a
-reference to the type info for a catch statement, or a non-negative integer
-followed by that many type info references, representing a
-<a href="#throw_filters">filter</a>.
+used for this try catch sequence. Each of the remaining arguments is either a
+reference to the type info for a catch statement,
+a <a href="#throw_filters">filter</a> expression,
+or the number zero representing a <a href="#cleanups">cleanup</a>.
 The exception is tested against the arguments sequentially from first to last.
-The <i>catch all</i> (...) is represented with a <tt>null i8*</tt>.  The result
-of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is a positive
-number if the exception matched a type info, a negative number if it matched a
-filter, and zero if it didn't match anything.  If a type info matched then the
-returned value is the index of the type info in the exception table.</p>
+The result of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is a
+positive number if the exception matched a type info, a negative number if it matched
+a filter, and zero if it matched a cleanup.  If nothing is matched, the behaviour of
+the program is <a href="#restrictions">undefined</a>.
+If a type info matched then the selector value is the index of the type info in
+the exception table, which can be obtained using the
+<a href="#llvm_eh_typeid_for"><tt>llvm.eh.typeid.for</tt></a> intrinsic.</p>
 
 </div>
 

Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h?rev=41484&r1=41483&r2=41484&view=diff

==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h Mon Aug 27 10:47:50 2007
@@ -966,7 +966,6 @@
   : LandingPadBlock(MBB)
   , LandingPadLabel(0)
   , Personality(NULL)  
-  , TypeIds(1, 0) // Always have cleanups
   {}
 };
 
@@ -1239,6 +1238,10 @@
   void addFilterTypeInfo(MachineBasicBlock *LandingPad,
                          std::vector<GlobalVariable *> &TyInfo);
 
+  /// addCleanup - Add a cleanup action for a landing pad.
+  ///
+  void addCleanup(MachineBasicBlock *LandingPad);
+
   /// getTypeIDFor - Return the type id for the specified typeinfo.  This is 
   /// function wide.
   unsigned getTypeIDFor(GlobalVariable *TI);

Modified: llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp?rev=41484&r1=41483&r2=41484&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp Mon Aug 27 10:47:50 2007
@@ -1726,6 +1726,13 @@
   LP.TypeIds.push_back(getFilterIDFor(IdsInFilter));
 }
 
+/// addCleanup - Add a cleanup action for a landing pad.
+///
+void MachineModuleInfo::addCleanup(MachineBasicBlock *LandingPad) {
+  LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad);
+  LP.TypeIds.push_back(0);
+}
+
 /// TidyLandingPads - Remap landing pad labels and remove any deleted landing
 /// pads.
 void MachineModuleInfo::TidyLandingPads() {

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp?rev=41484&r1=41483&r2=41484&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Mon Aug 27 10:47:50 2007
@@ -2519,7 +2519,7 @@
   for (unsigned i = N - 1; i > 2; --i) {
     if (ConstantInt *CI = dyn_cast<ConstantInt>(I.getOperand(i))) {
       unsigned FilterLength = CI->getZExtValue();
-      unsigned FirstCatch = i + FilterLength + 1;
+      unsigned FirstCatch = i + FilterLength + !FilterLength;
       assert (FirstCatch <= N && "Invalid filter length");
 
       if (FirstCatch < N) {
@@ -2530,11 +2530,17 @@
         TyInfo.clear();
       }
 
-      TyInfo.reserve(FilterLength);
-      for (unsigned j = i + 1; j < FirstCatch; ++j)
-        TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
-      MMI->addFilterTypeInfo(MBB, TyInfo);
-      TyInfo.clear();
+      if (!FilterLength) {
+        // Cleanup.
+        MMI->addCleanup(MBB);
+      } else {
+        // Filter.
+        TyInfo.reserve(FilterLength - 1);
+        for (unsigned j = i + 1; j < FirstCatch; ++j)
+          TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
+        MMI->addFilterTypeInfo(MBB, TyInfo);
+        TyInfo.clear();
+      }
 
       N = i;
     }





More information about the llvm-commits mailing list