Add support for the same encodings of the personality function that gnu as
supports.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122577 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp
index 5ff12bc..88c7200 100644
--- a/lib/MC/ELFObjectWriter.cpp
+++ b/lib/MC/ELFObjectWriter.cpp
@@ -1604,26 +1604,41 @@
   unsigned Type;
   if (is64Bit()) {
     if (IsPCRel) {
-      switch (Modifier) {
-      default:
-        llvm_unreachable("Unimplemented");
-      case MCSymbolRefExpr::VK_None:
-        Type = ELF::R_X86_64_PC32;
+      switch ((unsigned)Fixup.getKind()) {
+      default: llvm_unreachable("invalid fixup kind!");
+      case FK_PCRel_8:
+        assert(Modifier == MCSymbolRefExpr::VK_None);
+        Type = ELF::R_X86_64_PC64;
         break;
-      case MCSymbolRefExpr::VK_PLT:
-        Type = ELF::R_X86_64_PLT32;
+      case FK_Data_4: // FIXME?
+      case X86::reloc_riprel_4byte:
+      case FK_PCRel_4:
+        switch (Modifier) {
+        default:
+          llvm_unreachable("Unimplemented");
+        case MCSymbolRefExpr::VK_None:
+          Type = ELF::R_X86_64_PC32;
+          break;
+        case MCSymbolRefExpr::VK_PLT:
+          Type = ELF::R_X86_64_PLT32;
+          break;
+        case MCSymbolRefExpr::VK_GOTPCREL:
+          Type = ELF::R_X86_64_GOTPCREL;
+          break;
+        case MCSymbolRefExpr::VK_GOTTPOFF:
+          Type = ELF::R_X86_64_GOTTPOFF;
         break;
-      case MCSymbolRefExpr::VK_GOTPCREL:
-        Type = ELF::R_X86_64_GOTPCREL;
+        case MCSymbolRefExpr::VK_TLSGD:
+          Type = ELF::R_X86_64_TLSGD;
+          break;
+        case MCSymbolRefExpr::VK_TLSLD:
+          Type = ELF::R_X86_64_TLSLD;
+          break;
+        }
         break;
-      case MCSymbolRefExpr::VK_GOTTPOFF:
-        Type = ELF::R_X86_64_GOTTPOFF;
-        break;
-      case MCSymbolRefExpr::VK_TLSGD:
-        Type = ELF::R_X86_64_TLSGD;
-        break;
-      case MCSymbolRefExpr::VK_TLSLD:
-        Type = ELF::R_X86_64_TLSLD;
+      case FK_PCRel_2:
+        assert(Modifier == MCSymbolRefExpr::VK_None);
+        Type = ELF::R_X86_64_PC16;
         break;
       }
     } else {
@@ -1631,7 +1646,6 @@
       default: llvm_unreachable("invalid fixup kind!");
       case FK_Data_8: Type = ELF::R_X86_64_64; break;
       case X86::reloc_signed_4byte:
-      case FK_PCRel_4:
         assert(isInt<32>(Target.getConstant()));
         switch (Modifier) {
         default:
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index a171ba1..ee13429 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -189,7 +189,7 @@
   virtual bool EmitCFIDefCfaOffset(int64_t Offset);
   virtual bool EmitCFIDefCfaRegister(int64_t Register);
   virtual bool EmitCFIOffset(int64_t Register, int64_t Offset);
-  virtual bool EmitCFIPersonality(const MCSymbol *Sym);
+  virtual bool EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding);
   virtual bool EmitCFILsda(const MCSymbol *Sym);
 
   virtual void EmitInstruction(const MCInst &Inst);
@@ -758,11 +758,12 @@
   return false;
 }
 
-bool MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym) {
-  if (this->MCStreamer::EmitCFIPersonality(Sym))
+bool MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym,
+                                       unsigned Encoding) {
+  if (this->MCStreamer::EmitCFIPersonality(Sym, Encoding))
     return true;
 
-  OS << ".cfi_personality 0, " << *Sym;
+  OS << ".cfi_personality " << Encoding << ", " << *Sym;
   EmitEOL();
 
   return false;
diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp
index 75c844f..9d26bec 100644
--- a/lib/MC/MCDwarf.cpp
+++ b/lib/MC/MCDwarf.cpp
@@ -509,7 +509,8 @@
 }
 
 static const MCSymbol &EmitCIE(MCStreamer &streamer,
-                               const MCSymbol *personality) {
+                               const MCSymbol *personality,
+                               unsigned personalityEncoding) {
   MCContext &context = streamer.getContext();
   const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
   const MCSection &section = *asmInfo.getEHFrameSection();
@@ -559,9 +560,44 @@
   streamer.EmitLabel(augmentationStart);
   if (personality) {
     // Personality Encoding
-    streamer.EmitIntValue(dwarf::DW_EH_PE_absptr, 1);
+    streamer.EmitIntValue(personalityEncoding, 1);
     // Personality
-    streamer.EmitSymbolValue(personality, asmInfo.getPointerSize());
+    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;
+    }
   }
   // Encoding of the FDE pointers
   streamer.EmitIntValue(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4, 1);
@@ -620,13 +656,16 @@
   const MCContext &context = streamer.getContext();
   const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
   MCSymbol *fdeEnd = NULL;
-  DenseMap<const MCSymbol*, const MCSymbol*> Personalities;
+  typedef std::pair<const MCSymbol*, unsigned> personalityKey;
+  DenseMap<personalityKey, const MCSymbol*> personalities;
 
   for (unsigned i = 0, n = streamer.getNumFrameInfos(); i < n; ++i) {
     const MCDwarfFrameInfo &frame = streamer.getFrameInfo(i);
-    const MCSymbol *&cieStart = Personalities[frame.Personality];
+    personalityKey key(frame.Personality, frame.PersonalityEncoding);
+    const MCSymbol *&cieStart = personalities[key];
     if (!cieStart)
-      cieStart = &EmitCIE(streamer, frame.Personality);
+      cieStart = &EmitCIE(streamer, frame.Personality,
+                          frame.PersonalityEncoding);
     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 cf11ca9..450a927 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -2254,7 +2254,7 @@
   MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
 
   if (IDVal == ".cfi_personality")
-    return getStreamer().EmitCFIPersonality(Sym);
+    return getStreamer().EmitCFIPersonality(Sym, Encoding);
   else {
     assert(IDVal == ".cfi_lsda");
     return getStreamer().EmitCFILsda(Sym);
diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index 68146de..399b4ba 100644
--- a/lib/MC/MCStreamer.cpp
+++ b/lib/MC/MCStreamer.cpp
@@ -187,10 +187,12 @@
   return false;
 }
 
-bool MCStreamer::EmitCFIPersonality(const MCSymbol *Sym) {
+bool MCStreamer::EmitCFIPersonality(const MCSymbol *Sym,
+                                    unsigned Encoding) {
   EnsureValidFrame();
   MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo();
   CurFrame->Personality = Sym;
+  CurFrame->PersonalityEncoding = Encoding;
   return false;
 }
 
diff --git a/lib/MC/TargetAsmBackend.cpp b/lib/MC/TargetAsmBackend.cpp
index e0653d0..b13aa1d 100644
--- a/lib/MC/TargetAsmBackend.cpp
+++ b/lib/MC/TargetAsmBackend.cpp
@@ -27,7 +27,8 @@
     { "FK_Data_8", 0, 64, 0 },
     { "FK_PCRel_1", 0, 8, MCFixupKindInfo::FKF_IsPCRel },
     { "FK_PCRel_2", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
-    { "FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel }
+    { "FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+    { "FK_PCRel_8", 0, 64, MCFixupKindInfo::FKF_IsPCRel }
   };
   
   assert(Kind <= sizeof(Builtins) / sizeof(Builtins[0]) &&