Fix PR1628. When exception handling is turned on,
authorDuncan Sands <baldrick@free.fr>
Wed, 5 Sep 2007 11:27:52 +0000 (11:27 +0000)
committerDuncan Sands <baldrick@free.fr>
Wed, 5 Sep 2007 11:27:52 +0000 (11:27 +0000)
labels are generated bracketing each call (not just
invokes).  This is used to generate entries in
the exception table required by the C++ personality.
However it gets in the way of tail-merging.  This
patch solves the problem by no longer placing labels
around ordinary calls.  Instead we generate entries
in the exception table that cover every instruction
in the function that wasn't covered by an invoke
range (the range given by the labels around the invoke).
As an optimization, such entries are only generated for
parts of the function that contain a call, since for
the moment those are the only instructions that can
throw an exception [1].  As a happy consequence, we
now get a smaller exception table, since the same
region can cover many calls.  While there, I also
implemented folding of invoke ranges - successive
ranges are merged when safe to do so.  Finally, if
a selector contains only a cleanup, there's a special
shorthand for it - place a 0 in the call-site entry.
I implemented this while there.  As a result, the
exception table output (excluding filters) is now
optimal - it cannot be made smaller [2].  The
problem with throw filters is that folding them
optimally is hard, and the benefit of folding them is
minimal.

[1] I tested that having trapping instructions (eg
divide by zero) in such a region doesn't cause trouble.
[2] It could be made smaller with the help of higher
layers, eg by having branch folding reorder basic blocks
ending in invokes with the same landing pad so they
follow each other.  I don't know if this is worth doing.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41718 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/DwarfWriter.cpp
lib/CodeGen/MachineModuleInfo.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

index 232c5c4ba2ef3cd3dbb778195588fdd0c74d4fed..e9988743a5059671f6e0534bcc8fb1e006c4dc19 100644 (file)
@@ -2896,7 +2896,7 @@ private:
       O << UsedDirective << EHFrameInfo.FnName << ".eh\n\n";
   }
 
-  /// EmitExceptionTable - Emit landpads and actions.
+  /// EmitExceptionTable - Emit landing pads and actions.
   ///
   /// The general organization of the table is complex, but the basic concepts
   /// are easy.  First there is a header which describes the location and
@@ -2951,19 +2951,31 @@ private:
     static bool isPod() { return true; }
   };
 
-  struct PadSite {
-    unsigned PadIndex;
-    unsigned SiteIndex;
-  };
-
-  typedef DenseMap<unsigned, PadSite, KeyInfo> PadMapType;
-
+  /// ActionEntry - Structure describing an entry in the actions table.
   struct ActionEntry {
     int ValueForTypeID; // The value to write - may not be equal to the type id.
     int NextAction;
     struct ActionEntry *Previous;
   };
 
+  /// PadRange - Structure holding a try-range and the associated landing pad.
+  struct PadRange {
+    // The index of the landing pad.
+    unsigned PadIndex;
+    // The index of the begin and end labels in the landing pad's label lists.
+    unsigned RangeIndex;
+  };
+
+  typedef DenseMap<unsigned, PadRange, KeyInfo> RangeMapType;
+
+  /// CallSiteEntry - Structure describing an entry in the call-site table.
+  struct CallSiteEntry {
+    unsigned BeginLabel; // zero indicates the start of the function.
+    unsigned EndLabel;   // zero indicates the end of the function.
+    unsigned PadLabel;   // zero indicates that there is no landing pad.
+    unsigned Action;
+  };
+
   void EmitExceptionTable() {
     // Map all labels and get rid of any dead landing pads.
     MMI->TidyLandingPads();
@@ -2981,13 +2993,6 @@ private:
       LandingPads.push_back(&PadInfos[i]);
     std::sort(LandingPads.begin(), LandingPads.end(), PadLT);
 
-    // Gather first action index for each landing pad site.
-    SmallVector<unsigned, 64> FirstActions;
-    FirstActions.reserve(PadInfos.size());
-
-    // The actions table.
-    SmallVector<ActionEntry, 32> Actions;
-
     // Negative type ids index into FilterIds, positive type ids index into
     // TypeInfos.  The value written for a positive type id is just the type
     // id itself.  For a negative type id, however, the value written is the
@@ -3007,14 +3012,14 @@ private:
       Offset -= Asm->SizeULEB128(*I);
     }
 
-    // Compute sizes for exception table.
-    unsigned SizeSites = 0;
-    unsigned SizeActions = 0;
+    // Compute the actions table and gather the first action index for each
+    // landing pad site.
+    SmallVector<ActionEntry, 32> Actions;
+    SmallVector<unsigned, 64> FirstActions;
+    FirstActions.reserve(LandingPads.size());
 
-    // Look at each landing pad site to compute size.  We need the size of each
-    // landing pad site info and the size of the landing pad's actions.
     int FirstAction = 0;
-
+    unsigned SizeActions = 0;
     for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
       const LandingPadInfo *LP = LandingPads[i];
       const std::vector<int> &TypeIds = LP->TypeIds;
@@ -3063,14 +3068,96 @@ private:
 
       // Compute this sites contribution to size.
       SizeActions += SizeSiteActions;
-      unsigned M = LP->BeginLabels.size();
-      SizeSites += M*(sizeof(int32_t) +               // Site start.
-                      sizeof(int32_t) +               // Site length.
-                      sizeof(int32_t) +               // Landing pad.
-                      Asm->SizeULEB128(FirstAction)); // Action.
     }
-    
+
+    // Compute the call-site table.  Entries must be ordered by address.
+    SmallVector<CallSiteEntry, 64> CallSites;
+
+    RangeMapType PadMap;
+    for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
+      const LandingPadInfo *LandingPad = LandingPads[i];
+      for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
+        unsigned BeginLabel = LandingPad->BeginLabels[j];
+        assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
+        PadRange P = { i, j };
+        PadMap[BeginLabel] = P;
+      }
+    }
+
+    bool MayThrow = false;
+    unsigned LastLabel = 0;
+    const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
+    for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
+         I != E; ++I) {
+      for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
+           MI != E; ++MI) {
+        if (MI->getOpcode() != TargetInstrInfo::LABEL) {
+          MayThrow |= TII->isCall(MI->getOpcode());
+          continue;
+        }
+
+        unsigned BeginLabel = MI->getOperand(0).getImmedValue();
+        assert(BeginLabel && "Invalid label!");
+        if (BeginLabel == LastLabel) {
+          MayThrow = false;
+          continue;
+        }
+
+        RangeMapType::iterator L = PadMap.find(BeginLabel);
+
+        if (L == PadMap.end())
+          continue;
+
+        PadRange P = L->second;
+        const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
+
+        assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
+               "Inconsistent landing pad map!");
+
+        // If some instruction between the previous try-range and this one may
+        // throw, create a call-site entry with no landing pad for the region
+        // between the try-ranges.
+        if (MayThrow) {
+          CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0};
+          CallSites.push_back(Site);
+        }
+
+        LastLabel = LandingPad->EndLabels[P.RangeIndex];
+        CallSiteEntry Site = {BeginLabel, LastLabel,
+          LandingPad->LandingPadLabel, FirstActions[P.PadIndex]};
+
+        assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel &&
+               "Invalid landing pad!");
+
+        // Try to merge with the previous call-site.
+        if (CallSites.size()) {
+          CallSiteEntry &Prev = CallSites[CallSites.size()-1];
+          if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
+            // Extend the range of the previous entry.
+            Prev.EndLabel = Site.EndLabel;
+            continue;
+          }
+        }
+
+        // Otherwise, create a new call-site.
+        CallSites.push_back(Site);
+      }
+    }
+    // If some instruction between the previous try-range and the end of the
+    // function may throw, create a call-site entry with no landing pad for the
+    // region following the try-range.
+    if (MayThrow) {
+      CallSiteEntry Site = {LastLabel, 0, 0, 0};
+      CallSites.push_back(Site);
+    }
+
     // Final tallies.
+    unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start.
+                                             sizeof(int32_t) + // Site length.
+                                             sizeof(int32_t)); // Landing pad.
+    for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
+      SizeSites += Asm->SizeULEB128(CallSites[i].Action);
+
     unsigned SizeTypes = TypeInfos.size() * TAI->getAddressSize();
 
     unsigned TypeOffset = sizeof(int8_t) + // Call site format
@@ -3106,61 +3193,44 @@ private:
     Asm->EmitULEB128Bytes(SizeSites);
     Asm->EOL("Call-site table length");
 
-    // Emit the landing pad site information in order of address.
-    PadMapType PadMap;
+    // Emit the landing pad site information.
+    for (unsigned i = 0; i < CallSites.size(); ++i) {
+      CallSiteEntry &S = CallSites[i];
+      const char *BeginTag;
+      unsigned BeginNumber;
 
-    for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
-      const LandingPadInfo *LandingPad = LandingPads[i];
-      for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
-        unsigned BeginLabel = LandingPad->BeginLabels[j];
-        assert(!PadMap.count(BeginLabel) && "duplicate landing pad labels!");
-        PadSite P = { i, j };
-        PadMap[BeginLabel] = P;
+      if (!S.BeginLabel) {
+        BeginTag = "eh_func_begin";
+        BeginNumber = SubprogramCount;
+      } else {
+        BeginTag = "label";
+        BeginNumber = S.BeginLabel;
       }
-    }
 
-    for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
-         I != E; ++I) {
-      for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
-           MI != E; ++MI) {
-        if (MI->getOpcode() != TargetInstrInfo::LABEL)
-          continue;
-
-        unsigned BeginLabel = MI->getOperand(0).getImmedValue();
-        PadMapType::iterator L = PadMap.find(BeginLabel);
-
-        if (L == PadMap.end())
-          continue;
-
-        PadSite P = L->second;
-        const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
+      EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
+                        false, true);
+      Asm->EOL("Region start");
 
-        assert(BeginLabel == LandingPad->BeginLabels[P.SiteIndex] &&
-               "Inconsistent landing pad map!");
+      if (!S.EndLabel) {
+        EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber);
+      } else {
+        EmitDifference("label", S.EndLabel, BeginTag, BeginNumber);
+      }
+      Asm->EOL("Region length");
 
-        EmitSectionOffset("label", "eh_func_begin", BeginLabel, SubprogramCount,
+      if (!S.PadLabel) {
+        if (TAI->getAddressSize() == sizeof(int32_t))
+          Asm->EmitInt32(0);
+        else
+          Asm->EmitInt64(0);
+      } else {
+        EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
                           false, true);
-        Asm->EOL("Region start");
-
-        EmitDifference("label", LandingPad->EndLabels[P.SiteIndex],
-                       "label", BeginLabel);
-        Asm->EOL("Region length");
-
-        if (LandingPad->TypeIds.empty()) {
-          if (TAI->getAddressSize() == sizeof(int32_t))
-            Asm->EmitInt32(0);
-          else
-            Asm->EmitInt64(0);
-        } else {
-          EmitSectionOffset("label", "eh_func_begin",
-                            LandingPad->LandingPadLabel, SubprogramCount,
-                            false, true);
-        }
-        Asm->EOL("Landing pad");
-
-        Asm->EmitULEB128Bytes(FirstActions[P.PadIndex]);
-        Asm->EOL("Action");
       }
+      Asm->EOL("Landing pad");
+
+      Asm->EmitULEB128Bytes(S.Action);
+      Asm->EOL("Action");
     }
 
     // Emit the actions.
@@ -3183,7 +3253,7 @@ private:
         O << Asm->getGlobalLinkName(GV);
       else
         O << "0";
-      
+
       Asm->EOL("TypeInfo");
     }
 
@@ -3193,7 +3263,7 @@ private:
       Asm->EmitULEB128Bytes(TypeID);
       Asm->EOL("Filter TypeInfo index");
     }
-    
+
     Asm->EmitAlignment(2);
   }
 
index 62224fdca8487f427ad8be1ac832ec511595bc16..8360745ff167268a5c6619287b56f3ee2875e067 100644 (file)
@@ -1740,22 +1740,18 @@ void MachineModuleInfo::TidyLandingPads() {
     LandingPadInfo &LandingPad = LandingPads[i];
     LandingPad.LandingPadLabel = MappedLabel(LandingPad.LandingPadLabel);
 
-    if (!LandingPad.LandingPadBlock)
-      // Must not have cleanups if no landing pad.
-      LandingPad.TypeIds.clear();
-
     // Special case: we *should* emit LPs with null LP MBB. This indicates
     // "rethrow" case.
     if (!LandingPad.LandingPadLabel && LandingPad.LandingPadBlock) {
       LandingPads.erase(LandingPads.begin() + i);
       continue;
     }
-          
+
     for (unsigned j=0; j != LandingPads[i].BeginLabels.size(); ) {
       unsigned BeginLabel = MappedLabel(LandingPad.BeginLabels[j]);
       unsigned EndLabel = MappedLabel(LandingPad.EndLabels[j]);
-            
-          
+
+
       if (!BeginLabel || !EndLabel) {
         LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j);
         LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j);
@@ -1766,7 +1762,19 @@ void MachineModuleInfo::TidyLandingPads() {
       LandingPad.EndLabels[j] = EndLabel;
       ++j;
     }
-    
+
+    // Remove landing pads with no try-ranges.
+    if (!LandingPads[i].BeginLabels.size()) {
+      LandingPads.erase(LandingPads.begin() + i);
+      continue;
+    }
+
+    // If there is no landing pad, ensure that the list of typeids is empty.
+    // If the only typeid is a cleanup, this is the same as having no typeids.
+    if (!LandingPad.LandingPadBlock ||
+        (LandingPad.TypeIds.size() == 1 && !LandingPad.TypeIds[0]))
+      LandingPad.TypeIds.clear();
+
     ++i;
   }
 }
index 62bcc32bb4ef653b83894c5377986e1c2bc2caac..a695048a5adea6ae18eb5e804c13998954ca9b29 100644 (file)
@@ -2928,7 +2928,7 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
     Args.push_back(Entry);
   }
 
-  if (ExceptionHandling && MMI) {
+  if (ExceptionHandling && MMI && LandingPad) {
     // Insert a label before the invoke call to mark the try range.  This can be
     // used to detect deletion of the invoke via the MachineModuleInfo.
     BeginLabel = MMI->NextLabelID();
@@ -2945,7 +2945,7 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
     setValue(&I, Result.first);
   DAG.setRoot(Result.second);
 
-  if (ExceptionHandling && MMI) {
+  if (ExceptionHandling && MMI && LandingPad) {
     // Insert a label at the end of the invoke call to mark the try range.  This
     // can be used to detect deletion of the invoke via the MachineModuleInfo.
     EndLabel = MMI->NextLabelID();