SjLj based exception handling unwinding support. This patch is nasty, brutish
and short. Well, it's kinda short. Definitely nasty and brutish.

The front-end generates the register/unregister calls into the SjLj runtime,
call-site indices and landing pad dispatch. The back end fills in the LSDA
with the call-site information provided by the front end. Catch blocks are
not yet implemented.

Built on Darwin and verified no llvm-core "make check" regressions.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78625 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/AsmPrinter/DwarfException.cpp b/lib/CodeGen/AsmPrinter/DwarfException.cpp
index fec1ad7..a0cd456 100644
--- a/lib/CodeGen/AsmPrinter/DwarfException.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfException.cpp
@@ -364,6 +364,7 @@
 /// try-range address.
 void DwarfException::
 ComputeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
+                     std::map<unsigned,CallSiteEntry*> &CallSiteIndexMap,
                      const RangeMapType &PadMap,
                      const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
                      const SmallVectorImpl<unsigned> &FirstActions) {
@@ -405,10 +406,12 @@
       assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
              "Inconsistent landing pad map!");
 
+      // For Dwarf exception handling (SjLj handling doesn't use this)
       // 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 (SawPotentiallyThrowing) {
+      if (SawPotentiallyThrowing &&
+          TAI->getExceptionHandlingType() == ExceptionHandling::Dwarf) {
         CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0};
         CallSites.push_back(Site);
         PreviousIsInvoke = false;
@@ -435,6 +438,12 @@
 
         // Otherwise, create a new call-site.
         CallSites.push_back(Site);
+        // For SjLj handling, map the call site entry to its index
+        if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
+          unsigned Index =
+            MF->getLandingPadCallSiteIndex(LandingPad->LandingPadBlock);
+          CallSiteIndexMap[Index] = &CallSites.back();
+        }
         PreviousIsInvoke = true;
       } else {
         // Create a gap.
@@ -446,7 +455,8 @@
   // 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 (SawPotentiallyThrowing) {
+  if (SawPotentiallyThrowing &&
+      TAI->getExceptionHandlingType() == ExceptionHandling::Dwarf) {
     CallSiteEntry Site = {LastLabel, 0, 0, 0};
     CallSites.push_back(Site);
   }
@@ -496,7 +506,7 @@
 
   // Invokes and nounwind calls have entries in PadMap (due to being bracketed
   // by try-range labels when lowered).  Ordinary calls do not, so appropriate
-  // try-ranges for them need be deduced.
+  // try-ranges for them need be deduced when using Dwarf exception handling.
   RangeMapType PadMap;
   for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
     const LandingPadInfo *LandingPad = LandingPads[i];
@@ -510,7 +520,9 @@
 
   // Compute the call-site table.
   SmallVector<CallSiteEntry, 64> CallSites;
-  ComputeCallSiteTable(CallSites, PadMap, LandingPads, FirstActions);
+  std::map<unsigned,CallSiteEntry*> CallSiteIndexMap;
+  ComputeCallSiteTable(CallSites, CallSiteIndexMap, PadMap,
+                       LandingPads, FirstActions);
 
   // Final tallies.
 
@@ -518,12 +530,19 @@
   const unsigned SiteStartSize  = sizeof(int32_t); // DW_EH_PE_udata4
   const unsigned SiteLengthSize = sizeof(int32_t); // DW_EH_PE_udata4
   const unsigned LandingPadSize = sizeof(int32_t); // DW_EH_PE_udata4
-  unsigned SizeSites = CallSites.size() * (SiteStartSize +
-                                           SiteLengthSize +
-                                           LandingPadSize);
-  for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
+  unsigned SizeSites;
+  if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
+    SizeSites = (MF->getMaxCallSiteIndex() - CallSites.size()) *
+      TargetAsmInfo::getULEB128Size(0) * 2;
+  } else
+    SizeSites = CallSites.size() *
+      (SiteStartSize + SiteLengthSize + LandingPadSize);
+  for (unsigned i = 0, e = CallSites.size(); i < e; ++i) {
     SizeSites += TargetAsmInfo::getULEB128Size(CallSites[i].Action);
-
+    if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj)
+      SizeSites += TargetAsmInfo::getULEB128Size(i);
+      // FIXME: 'i' above should be the landing pad index
+  }
   // Type infos.
   const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr
   unsigned SizeTypes = TypeInfos.size() * TypeInfoSize;
@@ -551,6 +570,11 @@
   }
 
   EmitLabel("exception", SubprogramCount);
+  if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
+    std::string SjLjName = "_lsda_";
+    SjLjName += MF->getFunction()->getName().str();
+    EmitLabel(SjLjName.c_str(), 0);
+  }
 
   // Emit the header.
   Asm->EmitInt8(dwarf::DW_EH_PE_omit);
@@ -600,54 +624,102 @@
     Asm->EOL("TType base offset");
   }
 #else
-  Asm->EmitInt8(dwarf::DW_EH_PE_absptr);
-  Asm->EOL("TType format (DW_EH_PE_absptr)");
-  Asm->EmitULEB128Bytes(TypeOffset);
-  Asm->EOL("TType base offset");
+  // For SjLj exceptions, is there is no TypeInfo, then we just explicitly
+  // say that we're omitting that bit.
+  // FIXME: does this apply to Dwarf also? The above #if 0 implies yes?
+  if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj
+      && (TypeInfos.empty() || FilterIds.empty())) {
+    Asm->EmitInt8(dwarf::DW_EH_PE_omit);
+    Asm->EOL("TType format (DW_EH_PE_omit)");
+  } else {
+    Asm->EmitInt8(dwarf::DW_EH_PE_absptr);
+    Asm->EOL("TType format (DW_EH_PE_absptr)");
+    Asm->EmitULEB128Bytes(TypeOffset);
+    Asm->EOL("TType base offset");
+  }
 #endif
 
-  Asm->EmitInt8(dwarf::DW_EH_PE_udata4);
-  Asm->EOL("Call site format (DW_EH_PE_udata4)");
-  Asm->EmitULEB128Bytes(SizeSites);
-  Asm->EOL("Call-site table length");
+  // SjLj Exception handilng
+  if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
+    Asm->EmitInt8(dwarf::DW_EH_PE_udata4);
+    Asm->EOL("Call site format (DW_EH_PE_udata4)");
+    Asm->EmitULEB128Bytes(SizeSites);
+    Asm->EOL("Call-site table length");
 
-  // Emit the landing pad site information.
-  for (SmallVectorImpl<CallSiteEntry>::const_iterator
-         I = CallSites.begin(), E = CallSites.end(); I != E; ++I) {
-    const CallSiteEntry &S = *I;
-    const char *BeginTag;
-    unsigned BeginNumber;
 
-    if (!S.BeginLabel) {
-      BeginTag = "eh_func_begin";
-      BeginNumber = SubprogramCount;
-    } else {
-      BeginTag = "label";
-      BeginNumber = S.BeginLabel;
+    assert(MF->getCallSiteCount() == CallSites.size());
+
+    // Emit the landing pad site information.
+    // SjLj handling assigned the call site indices in the front end, so
+    // we need to make sure the table here lines up with that. That's pretty
+    // horrible, and should be fixed ASAP to do that stuff in the back end
+    // instead.
+    std::map<unsigned, CallSiteEntry*>::const_iterator I, E;
+    I = CallSiteIndexMap.begin();
+    E = CallSiteIndexMap.end();
+    for (unsigned CurrIdx = 1; I != E; ++I) {
+      // paranoia.
+      assert(CurrIdx <= I->first);
+      // Fill in any gaps in the table
+      while (CurrIdx++ < I->first) {
+        Asm->EmitULEB128Bytes(0);
+        Asm->EOL("Filler landing pad");
+        Asm->EmitULEB128Bytes(0);
+        Asm->EOL("Filler action");
+      }
+      const CallSiteEntry &S = *(I->second);
+      Asm->EmitULEB128Bytes(I->first - 1);
+      Asm->EOL("Landing pad");
+      Asm->EmitULEB128Bytes(S.Action);
+      Asm->EOL("Action");
     }
+  } else {
+    // DWARF Exception handling
+    assert(TAI->getExceptionHandlingType() == ExceptionHandling::Dwarf);
 
-    EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
-                      true, true);
-    Asm->EOL("Region start");
+    Asm->EmitInt8(dwarf::DW_EH_PE_udata4);
+    Asm->EOL("Call site format (DW_EH_PE_udata4)");
+    Asm->EmitULEB128Bytes(SizeSites);
+    Asm->EOL("Call-site table length");
 
-    if (!S.EndLabel)
-      EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber,
-                     true);
-    else
-      EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true);
+    // Emit the landing pad site information.
+    for (SmallVectorImpl<CallSiteEntry>::const_iterator
+         I = CallSites.begin(), E = CallSites.end(); I != E; ++I) {
+      const CallSiteEntry &S = *I;
+      const char *BeginTag;
+      unsigned BeginNumber;
 
-    Asm->EOL("Region length");
+      if (!S.BeginLabel) {
+        BeginTag = "eh_func_begin";
+        BeginNumber = SubprogramCount;
+      } else {
+        BeginTag = "label";
+        BeginNumber = S.BeginLabel;
+      }
 
-    if (!S.PadLabel)
-      Asm->EmitInt32(0);
-    else
-      EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
+      EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
                         true, true);
+      Asm->EOL("Region start");
 
-    Asm->EOL("Landing pad");
+      if (!S.EndLabel)
+        EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber,
+                       true);
+      else
+        EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true);
 
-    Asm->EmitULEB128Bytes(S.Action);
-    Asm->EOL("Action");
+      Asm->EOL("Region length");
+
+      if (!S.PadLabel)
+        Asm->EmitInt32(0);
+      else
+        EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
+                          true, true);
+
+      Asm->EOL("Landing pad");
+
+      Asm->EmitULEB128Bytes(S.Action);
+      Asm->EOL("Action");
+    }
   }
 
   // Emit the actions.
@@ -690,6 +762,8 @@
 /// EndModule - Emit all exception information that should come after the
 /// content.
 void DwarfException::EndModule() {
+  if (TAI->getExceptionHandlingType() != ExceptionHandling::Dwarf)
+    return;
   if (TimePassesIsEnabled)
     ExceptionTimer->startTimer();
 
diff --git a/lib/CodeGen/AsmPrinter/DwarfException.h b/lib/CodeGen/AsmPrinter/DwarfException.h
index e165df4..ee390cf 100644
--- a/lib/CodeGen/AsmPrinter/DwarfException.h
+++ b/lib/CodeGen/AsmPrinter/DwarfException.h
@@ -155,6 +155,7 @@
   /// of any entry - they form gaps in the table.  Entries must be ordered by
   /// try-range address.
   void ComputeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
+                            std::map<unsigned,CallSiteEntry*> &CallSiteIndexMap,
                             const RangeMapType &PadMap,
                             const SmallVectorImpl<const LandingPadInfo *> &LPs,
                             const SmallVectorImpl<unsigned> &FirstActions);
diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp
index 8249501..c60f9c7 100644
--- a/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/lib/CodeGen/LLVMTargetMachine.cpp
@@ -229,10 +229,17 @@
 
   // Turn exception handling constructs into something the code generators can
   // handle.
-  if (!getTargetAsmInfo()->doesSupportExceptionHandling())
-    PM.add(createLowerInvokePass(getTargetLowering()));
-  else
+  switch (getTargetAsmInfo()->getExceptionHandlingType())
+  {
+  // SjLj piggy-backs on dwarf for this bit
+  case ExceptionHandling::SjLj:
+  case ExceptionHandling::Dwarf:
     PM.add(createDwarfEHPass(getTargetLowering(), OptLevel==CodeGenOpt::None));
+    break;
+  case ExceptionHandling::None:
+    PM.add(createLowerInvokePass(getTargetLowering()));
+    break;
+  }
 
   PM.add(createGCLoweringPass());
 
diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp
index 2e9303a..ab037c2 100644
--- a/lib/CodeGen/MachineFunction.cpp
+++ b/lib/CodeGen/MachineFunction.cpp
@@ -93,6 +93,9 @@
                      MachineConstantPool(TM.getTargetData());
   Alignment = TM.getTargetLowering()->getFunctionAlignment(F);
 
+  CallSiteIndex = 0;
+  MaxCallSiteIndex = 0;
+
   // Set up jump table.
   const TargetData &TD = *TM.getTargetData();
   bool IsPic = TM.getRelocationModel() == Reloc::PIC_;
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 712feda..7297d60 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5198,6 +5198,7 @@
   case ISD::FRAMEADDR: return "FRAMEADDR";
   case ISD::FRAME_TO_ARGS_OFFSET: return "FRAME_TO_ARGS_OFFSET";
   case ISD::EXCEPTIONADDR: return "EXCEPTIONADDR";
+  case ISD::LSDAADDR: return "LSDAADDR";
   case ISD::EHSELECTION: return "EHSELECTION";
   case ISD::EH_RETURN: return "EH_RETURN";
   case ISD::ConstantPool:  return "ConstantPool";
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
index 0180069..1d02bff 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
@@ -4087,7 +4087,11 @@
                              Offset));
     return 0;
   }
-
+  case Intrinsic::eh_sjlj_callsite: {
+    MachineFunction &MF = DAG.getMachineFunction();
+    MF.setCallSiteIndex(cast<ConstantSDNode>(getValue(I.getOperand(1)))->getZExtValue());
+    return 0;
+  }
   case Intrinsic::convertff:
   case Intrinsic::convertfsi:
   case Intrinsic::convertfui:
@@ -4451,9 +4455,14 @@
   }
 
   if (LandingPad && MMI) {
+    MachineFunction &MF = DAG.getMachineFunction();
     // 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();
+
+    // Map this landing pad to the current call site entry
+    MF.setLandingPadCallSiteIndex(LandingPad, MF.getCallSiteIndex());
+
     // Both PendingLoads and PendingExports must be flushed here;
     // this call might not return.
     (void)getRoot();