Add support for .cfi_lsda.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122584 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index ee13429..f8c3a8a 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -190,7 +190,7 @@
   virtual bool EmitCFIDefCfaRegister(int64_t Register);
   virtual bool EmitCFIOffset(int64_t Register, int64_t Offset);
   virtual bool EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding);
-  virtual bool EmitCFILsda(const MCSymbol *Sym);
+  virtual bool EmitCFILsda(const MCSymbol *Sym, unsigned Encoding);
 
   virtual void EmitInstruction(const MCInst &Inst);
 
@@ -769,11 +769,11 @@
   return false;
 }
 
-bool MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym) {
-  if (this->MCStreamer::EmitCFILsda(Sym))
+bool MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
+  if (this->MCStreamer::EmitCFILsda(Sym, Encoding))
     return true;
 
-  OS << ".cfi_lsda 0, " << *Sym;
+  OS << ".cfi_lsda " << Encoding << ", " << *Sym;
   EmitEOL();
 
   return false;
diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp
index 9d26bec..cd51410 100644
--- a/lib/MC/MCDwarf.cpp
+++ b/lib/MC/MCDwarf.cpp
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/FoldingSet.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCAssembler.h"
@@ -508,9 +509,53 @@
   }
 }
 
+static void EmitSymbol(MCStreamer &streamer, const MCSymbol &symbol,
+                       unsigned symbolEncoding) {
+  MCContext &context = streamer.getContext();
+  const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
+  unsigned format = symbolEncoding & 0x0f;
+  unsigned application = symbolEncoding & 0xf0;
+  unsigned size;
+  switch (format) {
+  default:
+    assert(0 && "Unknown Encoding");
+    break;
+  case dwarf::DW_EH_PE_absptr:
+  case dwarf::DW_EH_PE_signed:
+    size = asmInfo.getPointerSize();
+    break;
+  case dwarf::DW_EH_PE_udata2:
+  case dwarf::DW_EH_PE_sdata2:
+    size = 2;
+    break;
+  case dwarf::DW_EH_PE_udata4:
+  case dwarf::DW_EH_PE_sdata4:
+    size = 4;
+    break;
+  case dwarf::DW_EH_PE_udata8:
+  case dwarf::DW_EH_PE_sdata8:
+    size = 8;
+    break;
+  }
+  switch (application) {
+  default:
+    assert(0 && "Unknown Encoding");
+    break;
+  case 0:
+  case dwarf::DW_EH_PE_indirect:
+    streamer.EmitSymbolValue(&symbol, size);
+    break;
+  case dwarf::DW_EH_PE_pcrel:
+    streamer.EmitPCRelSymbolValue(&symbol, size);
+    break;
+  }
+}
+
 static const MCSymbol &EmitCIE(MCStreamer &streamer,
                                const MCSymbol *personality,
-                               unsigned personalityEncoding) {
+                               unsigned personalityEncoding,
+                               const MCSymbol *lsda,
+                               unsigned lsdaEncoding) {
   MCContext &context = streamer.getContext();
   const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
   const MCSection &section = *asmInfo.getEHFrameSection();
@@ -535,6 +580,8 @@
   Augmentation += "z";
   if (personality)
     Augmentation += "P";
+  if (lsda)
+    Augmentation += "L";
   Augmentation += "R";
   streamer.EmitBytes(Augmentation.str(), 0);
   streamer.EmitIntValue(0, 1);
@@ -562,42 +609,11 @@
     // Personality Encoding
     streamer.EmitIntValue(personalityEncoding, 1);
     // Personality
-    unsigned format = personalityEncoding & 0x0f;
-    unsigned application = personalityEncoding & 0xf0;
-    unsigned size;
-    switch (format) {
-    default:
-      assert(0 && "Unknown Encoding");
-      break;
-    case dwarf::DW_EH_PE_absptr:
-    case dwarf::DW_EH_PE_signed:
-      size = asmInfo.getPointerSize();
-      break;
-    case dwarf::DW_EH_PE_udata2:
-    case dwarf::DW_EH_PE_sdata2:
-      size = 2;
-      break;
-    case dwarf::DW_EH_PE_udata4:
-    case dwarf::DW_EH_PE_sdata4:
-      size = 4;
-      break;
-    case dwarf::DW_EH_PE_udata8:
-    case dwarf::DW_EH_PE_sdata8:
-      size = 8;
-      break;
-    }
-    switch (application) {
-    default:
-      assert(0 && "Unknown Encoding");
-      break;
-    case 0:
-    case dwarf::DW_EH_PE_indirect:
-      streamer.EmitSymbolValue(personality, size);
-      break;
-    case dwarf::DW_EH_PE_pcrel:
-      streamer.EmitPCRelSymbolValue(personality, size);
-      break;
-    }
+    EmitSymbol(streamer, *personality, personalityEncoding);
+  }
+  if (lsda) {
+    // LSDA Encoding
+    streamer.EmitIntValue(lsdaEncoding, 1);
   }
   // Encoding of the FDE pointers
   streamer.EmitIntValue(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4, 1);
@@ -619,8 +635,9 @@
 static MCSymbol *EmitFDE(MCStreamer &streamer,
                          const MCSymbol &cieStart,
                          const MCDwarfFrameInfo &frame) {
-  MCSymbol *fdeStart = streamer.getContext().CreateTempSymbol();
-  MCSymbol *fdeEnd = streamer.getContext().CreateTempSymbol();
+  MCContext &context = streamer.getContext();
+  MCSymbol *fdeStart = context.CreateTempSymbol();
+  MCSymbol *fdeEnd = context.CreateTempSymbol();
 
   // Length
   const MCExpr *Length = MakeStartMinusEndExpr(streamer, *fdeStart, *fdeEnd, 0);
@@ -641,9 +658,18 @@
   streamer.EmitValue(Range, 4);
 
   // Augmentation Data Length
-  streamer.EmitULEB128IntValue(0);
+  MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol();
+  MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol();
+  const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer,
+                                                           *augmentationStart,
+                                                           *augmentationEnd, 0);
+  streamer.EmitULEB128Value(augmentationLength);
 
   // Augmentation Data
+  streamer.EmitLabel(augmentationStart);
+  if (frame.Lsda)
+    EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding);
+  streamer.EmitLabel(augmentationEnd);
   // Call Frame Instructions
 
   // Padding
@@ -652,20 +678,63 @@
   return fdeEnd;
 }
 
+struct CIEKey {
+  static const CIEKey EmptyKey;
+  static const CIEKey TombstoneKey;
+
+  CIEKey(const MCSymbol* Personality_, unsigned PersonalityEncoding_,
+         unsigned LsdaEncoding_) : Personality(Personality_),
+                                   PersonalityEncoding(PersonalityEncoding_),
+                                   LsdaEncoding(LsdaEncoding_) {
+  }
+  const MCSymbol* Personality;
+  unsigned PersonalityEncoding;
+  unsigned LsdaEncoding;
+};
+
+const CIEKey CIEKey::EmptyKey(0, 0, -1);
+const CIEKey CIEKey::TombstoneKey(0, -1, 0);
+
+namespace llvm {
+  template <>
+  struct DenseMapInfo<CIEKey> {
+    static CIEKey getEmptyKey() {
+      return CIEKey::EmptyKey;
+    }
+    static CIEKey getTombstoneKey() {
+      return CIEKey::TombstoneKey;
+    }
+    static unsigned getHashValue(const CIEKey &Key) {
+      FoldingSetNodeID ID;
+      ID.AddPointer(Key.Personality);
+      ID.AddInteger(Key.PersonalityEncoding);
+      ID.AddInteger(Key.LsdaEncoding);
+      return ID.ComputeHash();
+    }
+    static bool isEqual(const CIEKey &LHS,
+                        const CIEKey &RHS) {
+      return LHS.Personality == RHS.Personality &&
+        LHS.PersonalityEncoding == RHS.PersonalityEncoding &&
+        LHS.LsdaEncoding == RHS.LsdaEncoding;
+    }
+  };
+}
+
 void MCDwarfFrameEmitter::Emit(MCStreamer &streamer) {
   const MCContext &context = streamer.getContext();
   const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
   MCSymbol *fdeEnd = NULL;
-  typedef std::pair<const MCSymbol*, unsigned> personalityKey;
-  DenseMap<personalityKey, const MCSymbol*> personalities;
+  DenseMap<CIEKey, const MCSymbol*> CIEStarts;
 
   for (unsigned i = 0, n = streamer.getNumFrameInfos(); i < n; ++i) {
     const MCDwarfFrameInfo &frame = streamer.getFrameInfo(i);
-    personalityKey key(frame.Personality, frame.PersonalityEncoding);
-    const MCSymbol *&cieStart = personalities[key];
+    CIEKey key(frame.Personality, frame.PersonalityEncoding,
+               frame.LsdaEncoding);
+    const MCSymbol *&cieStart = CIEStarts[key];
     if (!cieStart)
       cieStart = &EmitCIE(streamer, frame.Personality,
-                          frame.PersonalityEncoding);
+                          frame.PersonalityEncoding, frame.Lsda,
+                          frame.LsdaEncoding);
     fdeEnd = EmitFDE(streamer, *cieStart, frame);
     if (i != n - 1)
       streamer.EmitLabel(fdeEnd);
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 450a927..27b2dce 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -2257,7 +2257,7 @@
     return getStreamer().EmitCFIPersonality(Sym, Encoding);
   else {
     assert(IDVal == ".cfi_lsda");
-    return getStreamer().EmitCFILsda(Sym);
+    return getStreamer().EmitCFILsda(Sym, Encoding);
   }
 }
 
diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index 399b4ba..922a40c 100644
--- a/lib/MC/MCStreamer.cpp
+++ b/lib/MC/MCStreamer.cpp
@@ -157,7 +157,7 @@
     report_fatal_error("Starting a frame before finishing the previous one!");
     return true;
   }
-  MCDwarfFrameInfo Frame = {0, 0, 0, 0};
+  MCDwarfFrameInfo Frame = {0, 0, 0, 0, 0, 0};
   Frame.Begin = getContext().CreateTempSymbol();
   EmitLabel(Frame.Begin);
   FrameInfos.push_back(Frame);
@@ -196,10 +196,11 @@
   return false;
 }
 
-bool MCStreamer::EmitCFILsda(const MCSymbol *Sym) {
+bool MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
   EnsureValidFrame();
   MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo();
   CurFrame->Lsda = Sym;
+  CurFrame->LsdaEncoding = Encoding;
   return false;
 }