[llvm] 1bfc5e7 - [SPARC][MC] Support more relocation types

Brad Smith via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 5 11:09:53 PDT 2022


Author: LemonBoy
Date: 2022-06-05T14:09:39-04:00
New Revision: 1bfc5e720cadecb3aaa9fed8bec77f0533c8398b

URL: https://github.com/llvm/llvm-project/commit/1bfc5e720cadecb3aaa9fed8bec77f0533c8398b
DIFF: https://github.com/llvm/llvm-project/commit/1bfc5e720cadecb3aaa9fed8bec77f0533c8398b.diff

LOG: [SPARC][MC] Support more relocation types

This patch introduces support for %hix, %lox, %gdop_hix22, %gdop_lox10 and %gdop.

An extra test is introduced to make sure the fixups are correctly applied.

Reviewed By: dcederman

Differential Revision: https://reviews.llvm.org/D102575

Added: 
    llvm/test/MC/Sparc/sparc-fixups.s

Modified: 
    llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
    llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
    llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
    llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
    llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
    llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
    llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
    llvm/lib/Target/Sparc/SparcISelLowering.cpp
    llvm/lib/Target/Sparc/SparcISelLowering.h
    llvm/lib/Target/Sparc/SparcInstr64Bit.td
    llvm/lib/Target/Sparc/SparcInstrInfo.td
    llvm/test/MC/Sparc/sparc-relocations.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index 9252db61c7c5..bb494ce144f8 100644
--- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -55,6 +55,8 @@ class SparcOperand;
 class SparcAsmParser : public MCTargetAsmParser {
   MCAsmParser &Parser;
 
+  enum class TailRelocKind { Load_GOT, Add_TLS, Load_TLS, Call_TLS };
+
   /// @name Auto-generated Match Functions
   /// {
 
@@ -83,6 +85,9 @@ class SparcAsmParser : public MCTargetAsmParser {
 
   OperandMatchResultTy parseMembarTag(OperandVector &Operands);
 
+  template <TailRelocKind Kind>
+  OperandMatchResultTy parseTailRelocSym(OperandVector &Operands);
+
   template <unsigned N>
   OperandMatchResultTy parseShiftAmtImm(OperandVector &Operands);
 
@@ -113,6 +118,8 @@ class SparcAsmParser : public MCTargetAsmParser {
   bool expandSET(MCInst &Inst, SMLoc IDLoc,
                  SmallVectorImpl<MCInst> &Instructions);
 
+  SMLoc getLoc() const { return getParser().getTok().getLoc(); }
+
 public:
   SparcAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser,
                 const MCInstrInfo &MII,
@@ -267,6 +274,7 @@ class SparcOperand : public MCParsedAsmOperand {
   bool isMEMrr() const { return Kind == k_MemoryReg; }
   bool isMEMri() const { return Kind == k_MemoryImm; }
   bool isMembarTag() const { return Kind == k_Immediate; }
+  bool isTailRelocSym() const { return Kind == k_Immediate; }
 
   bool isCallTarget() const {
     if (!isImm())
@@ -427,6 +435,11 @@ class SparcOperand : public MCParsedAsmOperand {
     addExpr(Inst, getImm());
   }
 
+  void addTailRelocSymOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    addExpr(Inst, getImm());
+  }
+
   static std::unique_ptr<SparcOperand> CreateToken(StringRef Str, SMLoc S) {
     auto Op = std::make_unique<SparcOperand>(k_Token);
     Op->Tok.Data = Str.data();
@@ -850,6 +863,98 @@ OperandMatchResultTy SparcAsmParser::parseShiftAmtImm(OperandVector &Operands) {
   return MatchOperand_Success;
 }
 
+template <SparcAsmParser::TailRelocKind Kind>
+OperandMatchResultTy
+SparcAsmParser::parseTailRelocSym(OperandVector &Operands) {
+  SMLoc S = getLoc();
+  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
+
+  auto MatchesKind = [](SparcMCExpr::VariantKind VK) -> bool {
+    switch (Kind) {
+    case TailRelocKind::Load_GOT:
+      // Non-TLS relocations on ld (or ldx).
+      // ld [%rr + %rr], %rr, %rel(sym)
+      return VK == SparcMCExpr::VK_Sparc_GOTDATA_OP;
+    case TailRelocKind::Add_TLS:
+      // TLS relocations on add.
+      // add %rr, %rr, %rr, %rel(sym)
+      switch (VK) {
+      case SparcMCExpr::VK_Sparc_TLS_GD_ADD:
+      case SparcMCExpr::VK_Sparc_TLS_IE_ADD:
+      case SparcMCExpr::VK_Sparc_TLS_LDM_ADD:
+      case SparcMCExpr::VK_Sparc_TLS_LDO_ADD:
+        return true;
+      default:
+        return false;
+      }
+    case TailRelocKind::Load_TLS:
+      // TLS relocations on ld (or ldx).
+      // ld[x] %addr, %rr, %rel(sym)
+      switch (VK) {
+      case SparcMCExpr::VK_Sparc_TLS_IE_LD:
+      case SparcMCExpr::VK_Sparc_TLS_IE_LDX:
+        return true;
+      default:
+        return false;
+      }
+    case TailRelocKind::Call_TLS:
+      // TLS relocations on call.
+      // call sym, %rel(sym)
+      switch (VK) {
+      case SparcMCExpr::VK_Sparc_TLS_GD_CALL:
+      case SparcMCExpr::VK_Sparc_TLS_LDM_CALL:
+        return true;
+      default:
+        return false;
+      }
+    default:
+      llvm_unreachable("Unexpected kind parameter");
+    }
+  };
+
+  if (getLexer().getKind() != AsmToken::Percent) {
+    Error(getLoc(), "expected '%' for operand modifier");
+    return MatchOperand_ParseFail;
+  }
+
+  const AsmToken Tok = Parser.getTok();
+  getParser().Lex(); // Eat '%'
+
+  if (getLexer().getKind() != AsmToken::Identifier) {
+    Error(getLoc(), "expected valid identifier for operand modifier");
+    return MatchOperand_ParseFail;
+  }
+
+  StringRef Name = getParser().getTok().getIdentifier();
+  SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(Name);
+  if (VK == SparcMCExpr::VK_Sparc_None) {
+    Error(getLoc(), "invalid operand modifier");
+    return MatchOperand_ParseFail;
+  }
+
+  if (!MatchesKind(VK)) {
+    // Did not match the specified set of relocation types, put '%' back.
+    getLexer().UnLex(Tok);
+    return MatchOperand_NoMatch;
+  }
+
+  Parser.Lex(); // Eat the identifier.
+  if (getLexer().getKind() != AsmToken::LParen) {
+    Error(getLoc(), "expected '('");
+    return MatchOperand_ParseFail;
+  }
+
+  getParser().Lex(); // Eat '('
+  const MCExpr *SubExpr;
+  if (getParser().parseParenExpression(SubExpr, E)) {
+    return MatchOperand_ParseFail;
+  }
+
+  const MCExpr *Val = adjustPICRelocation(VK, SubExpr);
+  Operands.push_back(SparcOperand::CreateImm(Val, S, E));
+  return MatchOperand_Success;
+}
+
 OperandMatchResultTy SparcAsmParser::parseMembarTag(OperandVector &Operands) {
   SMLoc S = Parser.getTok().getLoc();
   const MCExpr *EVal;
@@ -1409,10 +1514,27 @@ bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal,
   StringRef name = Tok.getString();
 
   SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name);
+  switch (VK) {
+  case SparcMCExpr::VK_Sparc_None:
+    Error(getLoc(), "invalid operand modifier");
+    return false;
 
-  if (VK == SparcMCExpr::VK_Sparc_None)
+  case SparcMCExpr::VK_Sparc_GOTDATA_OP:
+  case SparcMCExpr::VK_Sparc_TLS_GD_ADD:
+  case SparcMCExpr::VK_Sparc_TLS_GD_CALL:
+  case SparcMCExpr::VK_Sparc_TLS_IE_ADD:
+  case SparcMCExpr::VK_Sparc_TLS_IE_LD:
+  case SparcMCExpr::VK_Sparc_TLS_IE_LDX:
+  case SparcMCExpr::VK_Sparc_TLS_LDM_ADD:
+  case SparcMCExpr::VK_Sparc_TLS_LDM_CALL:
+  case SparcMCExpr::VK_Sparc_TLS_LDO_ADD:
+    // These are special-cased at tablegen level.
     return false;
 
+  default:
+    break;
+  }
+
   Parser.Lex(); // Eat the identifier.
   if (Parser.getTok().getKind() != AsmToken::LParen)
     return false;

diff  --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
index 4d69040a4508..7b2d8afd3605 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -47,6 +47,9 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
   case Sparc::fixup_sparc_br16_14:
     return (Value >> 2) & 0x3fff;
 
+  case Sparc::fixup_sparc_hix22:
+    return (~Value >> 10) & 0x3fffff;
+
   case Sparc::fixup_sparc_pc22:
   case Sparc::fixup_sparc_got22:
   case Sparc::fixup_sparc_tls_gd_hi22:
@@ -60,6 +63,9 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
   case Sparc::fixup_sparc_13:
     return Value & 0x1fff;
 
+  case Sparc::fixup_sparc_lox10:
+    return (Value & 0x3ff) | 0x1c00;
+
   case Sparc::fixup_sparc_pc10:
   case Sparc::fixup_sparc_got10:
   case Sparc::fixup_sparc_tls_gd_lo10:
@@ -98,6 +104,9 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
   case Sparc::fixup_sparc_tls_ie_ld:
   case Sparc::fixup_sparc_tls_ie_ldx:
   case Sparc::fixup_sparc_tls_ie_add:
+  case Sparc::fixup_sparc_gotdata_lox10:
+  case Sparc::fixup_sparc_gotdata_hix22:
+  case Sparc::fixup_sparc_gotdata_op:
     return 0;
   }
 }
@@ -189,7 +198,12 @@ namespace {
         { "fixup_sparc_tls_ie_ldx",     0,  0,  0 },
         { "fixup_sparc_tls_ie_add",     0,  0,  0 },
         { "fixup_sparc_tls_le_hix22",   0,  0,  0 },
-        { "fixup_sparc_tls_le_lox10",   0,  0,  0 }
+        { "fixup_sparc_tls_le_lox10",   0,  0,  0 },
+        { "fixup_sparc_hix22",         10, 22,  0 },
+        { "fixup_sparc_lox10",         19, 13,  0 },
+        { "fixup_sparc_gotdata_hix22",  0,  0,  0 },
+        { "fixup_sparc_gotdata_lox10",  0,  0,  0 },
+        { "fixup_sparc_gotdata_op",     0,  0,  0 },
       };
 
       const static MCFixupKindInfo InfosLE[Sparc::NumTargetFixupKinds] = {
@@ -231,7 +245,12 @@ namespace {
         { "fixup_sparc_tls_ie_ldx",     0,  0,  0 },
         { "fixup_sparc_tls_ie_add",     0,  0,  0 },
         { "fixup_sparc_tls_le_hix22",   0,  0,  0 },
-        { "fixup_sparc_tls_le_lox10",   0,  0,  0 }
+        { "fixup_sparc_tls_le_lox10",   0,  0,  0 },
+        { "fixup_sparc_hix22",          0, 22,  0 },
+        { "fixup_sparc_lox10",          0, 13,  0 },
+        { "fixup_sparc_gotdata_hix22",  0,  0,  0 },
+        { "fixup_sparc_gotdata_lox10",  0,  0,  0 },
+        { "fixup_sparc_gotdata_op",     0,  0,  0 },
       };
 
       // Fixup kinds from .reloc directive are like R_SPARC_NONE. They do

diff  --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
index dc01cba8d191..9c50c41f6bf2 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -112,6 +112,11 @@ unsigned SparcELFObjectWriter::getRelocType(MCContext &Ctx,
   case Sparc::fixup_sparc_tls_ie_add:    return ELF::R_SPARC_TLS_IE_ADD;
   case Sparc::fixup_sparc_tls_le_hix22:  return ELF::R_SPARC_TLS_LE_HIX22;
   case Sparc::fixup_sparc_tls_le_lox10:  return ELF::R_SPARC_TLS_LE_LOX10;
+  case Sparc::fixup_sparc_hix22:         return ELF::R_SPARC_HIX22;
+  case Sparc::fixup_sparc_lox10:         return ELF::R_SPARC_LOX10;
+  case Sparc::fixup_sparc_gotdata_hix22: return ELF::R_SPARC_GOTDATA_HIX22;
+  case Sparc::fixup_sparc_gotdata_lox10: return ELF::R_SPARC_GOTDATA_LOX10;
+  case Sparc::fixup_sparc_gotdata_op:    return ELF::R_SPARC_GOTDATA_OP;
   }
 
   return ELF::R_SPARC_NONE;

diff  --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
index e0a43095ec0b..701d8513e657 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -95,6 +95,18 @@ namespace llvm {
       fixup_sparc_tls_le_hix22,
       fixup_sparc_tls_le_lox10,
 
+      /// 22-bit fixup corresponding to %hix(foo)
+      fixup_sparc_hix22,
+      /// 13-bit fixup corresponding to %lox(foo)
+      fixup_sparc_lox10,
+
+      /// 22-bit fixup corresponding to %gdop_hix22(foo)
+      fixup_sparc_gotdata_hix22,
+      /// 13-bit fixup corresponding to %gdop_lox10(foo)
+      fixup_sparc_gotdata_lox10,
+      /// 32-bit fixup corresponding to %gdop(foo)
+      fixup_sparc_gotdata_op,
+
       // Marker
       LastTargetFixupKind,
       NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind

diff  --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
index 0a7e4bdaa0a6..d75d41b35838 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -104,17 +104,21 @@ void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
   support::endian::write(OS, Bits,
                          Ctx.getAsmInfo()->isLittleEndian() ? support::little
                                                             : support::big);
-  unsigned tlsOpNo = 0;
+
+  // Some instructions have phantom operands that only contribute a fixup entry.
+  unsigned SymOpNo = 0;
   switch (MI.getOpcode()) {
   default: break;
-  case SP::TLS_CALL:   tlsOpNo = 1; break;
+  case SP::TLS_CALL:   SymOpNo = 1; break;
+  case SP::GDOP_LDrr:
+  case SP::GDOP_LDXrr:
   case SP::TLS_ADDrr:
   case SP::TLS_ADDXrr:
   case SP::TLS_LDrr:
-  case SP::TLS_LDXrr:  tlsOpNo = 3; break;
+  case SP::TLS_LDXrr:  SymOpNo = 3; break;
   }
-  if (tlsOpNo != 0) {
-    const MCOperand &MO = MI.getOperand(tlsOpNo);
+  if (SymOpNo != 0) {
+    const MCOperand &MO = MI.getOperand(SymOpNo);
     uint64_t op = getMachineOpValue(MI, MO, Fixups, STI);
     assert(op == 0 && "Unexpected operand value!");
     (void)op; // suppress warning.

diff  --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
index 7f64032c5a48..cc73ea7e6120 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -81,6 +81,11 @@ bool SparcMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind)
   case VK_Sparc_TLS_IE_ADD:    OS << "%tie_add(";    return true;
   case VK_Sparc_TLS_LE_HIX22:  OS << "%tle_hix22(";  return true;
   case VK_Sparc_TLS_LE_LOX10:  OS << "%tle_lox10(";  return true;
+  case VK_Sparc_HIX22:         OS << "%hix(";        return true;
+  case VK_Sparc_LOX10:         OS << "%lox(";        return true;
+  case VK_Sparc_GOTDATA_HIX22: OS << "%gdop_hix22("; return true;
+  case VK_Sparc_GOTDATA_LOX10: OS << "%gdop_lox10("; return true;
+  case VK_Sparc_GOTDATA_OP:    OS << "%gdop(";       return true;
   }
   llvm_unreachable("Unhandled SparcMCExpr::VariantKind");
 }
@@ -120,6 +125,11 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name)
     .Case("tie_add",    VK_Sparc_TLS_IE_ADD)
     .Case("tle_hix22",  VK_Sparc_TLS_LE_HIX22)
     .Case("tle_lox10",  VK_Sparc_TLS_LE_LOX10)
+    .Case("hix",        VK_Sparc_HIX22)
+    .Case("lox",        VK_Sparc_LOX10)
+    .Case("gdop_hix22", VK_Sparc_GOTDATA_HIX22)
+    .Case("gdop_lox10", VK_Sparc_GOTDATA_LOX10)
+    .Case("gdop",       VK_Sparc_GOTDATA_OP)
     .Default(VK_Sparc_None);
 }
 
@@ -160,6 +170,11 @@ Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExpr::VariantKind Kind) {
   case VK_Sparc_TLS_IE_ADD:    return Sparc::fixup_sparc_tls_ie_add;
   case VK_Sparc_TLS_LE_HIX22:  return Sparc::fixup_sparc_tls_le_hix22;
   case VK_Sparc_TLS_LE_LOX10:  return Sparc::fixup_sparc_tls_le_lox10;
+  case VK_Sparc_HIX22:         return Sparc::fixup_sparc_hix22;
+  case VK_Sparc_LOX10:         return Sparc::fixup_sparc_lox10;
+  case VK_Sparc_GOTDATA_HIX22: return Sparc::fixup_sparc_gotdata_hix22;
+  case VK_Sparc_GOTDATA_LOX10: return Sparc::fixup_sparc_gotdata_lox10;
+  case VK_Sparc_GOTDATA_OP:    return Sparc::fixup_sparc_gotdata_op;
   }
 }
 

diff  --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
index 504e959194f5..d98ad26c96a9 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -58,7 +58,12 @@ class SparcMCExpr : public MCTargetExpr {
     VK_Sparc_TLS_IE_LDX,
     VK_Sparc_TLS_IE_ADD,
     VK_Sparc_TLS_LE_HIX22,
-    VK_Sparc_TLS_LE_LOX10
+    VK_Sparc_TLS_LE_LOX10,
+    VK_Sparc_HIX22,
+    VK_Sparc_LOX10,
+    VK_Sparc_GOTDATA_HIX22,
+    VK_Sparc_GOTDATA_LOX10,
+    VK_Sparc_GOTDATA_OP,
   };
 
 private:

diff  --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 06d278dfa981..2cb74e7709c7 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1900,6 +1900,7 @@ const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const {
   case SPISD::TLS_LD:          return "SPISD::TLS_LD";
   case SPISD::TLS_CALL:        return "SPISD::TLS_CALL";
   case SPISD::TAIL_CALL:       return "SPISD::TAIL_CALL";
+  case SPISD::LOAD_GDOP:       return "SPISD::LOAD_GDOP";
   }
   return nullptr;
 }

diff  --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h
index 94a5141d95b2..2768bb20566a 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.h
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.h
@@ -48,7 +48,9 @@ namespace llvm {
 
       TLS_ADD,     // For Thread Local Storage (TLS).
       TLS_LD,
-      TLS_CALL
+      TLS_CALL,
+
+      LOAD_GDOP,   // Load operation w/ gdop relocation.
     };
   }
 

diff  --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
index dc60f563ae87..a471d65201c3 100644
--- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td
+++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
@@ -163,7 +163,7 @@ defm ADDX    : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>;
 defm SUBX    : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>;
 
 def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd),
-                   (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym),
+                   (ins I64Regs:$rs1, I64Regs:$rs2, TailRelocSymTLSAdd:$sym),
                    "add $rs1, $rs2, $rd, $sym",
                    [(set i64:$rd,
                        (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>;
@@ -238,12 +238,20 @@ let Predicates = [Is64Bit] in {
 let DecoderMethod = "DecodeLoadInt" in
   defm LDX   : Load<"ldx", 0b001011, load, I64Regs, i64>;
 
-let mayLoad = 1, isAsmParserOnly = 1 in
+let mayLoad = 1, isAsmParserOnly = 1 in {
   def TLS_LDXrr : F3_1<3, 0b001011,
-                       (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
+                       (outs IntRegs:$dst),
+                       (ins MEMrr:$addr, TailRelocSymTLSLoad:$sym),
                        "ldx [$addr], $dst, $sym",
                        [(set i64:$dst,
                            (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>;
+  def GDOP_LDXrr : F3_1<3, 0b001011,
+                       (outs I64Regs:$dst),
+                       (ins MEMrr:$addr, TailRelocSymGOTLoad:$sym),
+                       "ldx [$addr], $dst, $sym",
+                       [(set i64:$dst,
+                           (load_gdop ADDRrr:$addr, tglobaladdr:$sym))]>;
+}
 
 // Extending loads to i64.
 def : Pat<(i64 (zextloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;

diff  --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index 34444246019f..481bd7d2f7fa 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -147,7 +147,29 @@ def MEMri : Operand<iPTR> {
   let ParserMatchClass = SparcMEMriAsmOperand;
 }
 
-def TLSSym : Operand<iPTR>;
+// Represents a tail relocation operand for instructions such as add, ld, call.
+class SparcTailRelocSymAsmOperand<string Kind> : AsmOperandClass {
+  let Name = "TailRelocSym" # Kind;
+  let RenderMethod = "addTailRelocSymOperands";
+  let PredicateMethod = "isTailRelocSym";
+  let ParserMethod = "parseTailRelocSym<TailRelocKind::" # Kind # ">";
+}
+
+def TailRelocSymGOTLoad : Operand<iPTR> {
+  let ParserMatchClass = SparcTailRelocSymAsmOperand<"Load_GOT">;
+}
+
+def TailRelocSymTLSAdd : Operand<iPTR> {
+  let ParserMatchClass = SparcTailRelocSymAsmOperand<"Add_TLS">;
+}
+
+def TailRelocSymTLSLoad : Operand<iPTR> {
+  let ParserMatchClass = SparcTailRelocSymAsmOperand<"Load_TLS">;
+}
+
+def TailRelocSymTLSCall : Operand<iPTR> {
+  let ParserMatchClass = SparcTailRelocSymAsmOperand<"Call_TLS">;
+}
 
 def SparcMembarTagAsmOperand : AsmOperandClass {
   let Name = "MembarTag";
@@ -214,6 +236,9 @@ SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>;
 def SDTSPtlsld :
 SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>;
 
+def SDTSPloadgdop :
+SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>;
+
 def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>;
 def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>;
 def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
@@ -265,6 +290,8 @@ def tlscall       : SDNode<"SPISD::TLS_CALL", SDT_SPCall,
                             [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
                              SDNPVariadic]>;
 
+def load_gdop : SDNode<"SPISD::LOAD_GDOP",  SDTSPloadgdop>;
+
 def getPCX        : Operand<iPTR> {
   let PrintMethod = "printGetPCX";
 }
@@ -587,6 +614,15 @@ let DecoderMethod = "DecodeLoadFP" in
     }
   }
 
+let mayLoad = 1, isAsmParserOnly = 1 in {
+  def GDOP_LDrr : F3_1<3, 0b000000,
+                      (outs IntRegs:$dst),
+                      (ins MEMrr:$addr, TailRelocSymGOTLoad:$sym),
+                      "ld [$addr], $dst, $sym",
+                      [(set i32:$dst,
+                          (load_gdop ADDRrr:$addr, tglobaladdr:$sym))]>;
+}
+
 // Section B.4 - Store Integer Instructions, p. 95
 let DecoderMethod = "DecodeStoreInt" in {
   defm STB   : StoreA<"stb", 0b000101, 0b010101, truncstorei8,  IntRegs, i32>;
@@ -1369,21 +1405,24 @@ let Defs = [FCC0], rd = 0, isCodeGenOnly = 1 in {
 let isAsmParserOnly = 1 in {
 def TLS_ADDrr : F3_1<2, 0b000000,
                     (outs IntRegs:$rd),
-                    (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym),
+                    (ins IntRegs:$rs1, IntRegs:$rs2, TailRelocSymTLSAdd:$sym),
                     "add $rs1, $rs2, $rd, $sym",
                     [(set i32:$rd,
                         (tlsadd i32:$rs1, i32:$rs2, tglobaltlsaddr:$sym))]>;
 
-let mayLoad = 1 in
+let mayLoad = 1 in {
   def TLS_LDrr : F3_1<3, 0b000000,
-                      (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
+                      (outs IntRegs:$dst),
+                      (ins MEMrr:$addr, TailRelocSymTLSLoad:$sym),
                       "ld [$addr], $dst, $sym",
                       [(set i32:$dst,
                           (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>;
+}
 
 let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
   def TLS_CALL : InstSP<(outs),
-                        (ins calltarget:$disp, TLSSym:$sym, variable_ops),
+                        (ins calltarget:$disp, TailRelocSymTLSCall:$sym,
+                         variable_ops),
                         "call $disp, $sym",
                         [(tlscall texternalsym:$disp, tglobaltlsaddr:$sym)],
                         IIC_jmp_or_call> {

diff  --git a/llvm/test/MC/Sparc/sparc-fixups.s b/llvm/test/MC/Sparc/sparc-fixups.s
new file mode 100644
index 000000000000..cdf006e7cff5
--- /dev/null
+++ b/llvm/test/MC/Sparc/sparc-fixups.s
@@ -0,0 +1,30 @@
+! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-objdump -dr - | FileCheck %s
+.text
+
+! Check that fixups are correctly applied.
+
+.set sym, 0xfedcba98
+
+! CHECK: sethi 4175662, %o0
+sethi %hi(sym), %o0
+! CHECK: xor %o0, 664, %o0
+xor %o0, %lo(sym), %o0
+
+! CHECK: sethi 1019, %o0
+sethi %h44(sym), %o0
+! CHECK: or %o0, 459, %o0
+or %o0, %m44(sym), %o0
+! CHECK: ld [%o0+2712], %o0
+ld [%o0 + %l44(sym)], %o0
+
+! CHECK: sethi 0, %o0
+sethi %hh(sym), %o0
+! CHECK: sethi 4175662, %o0
+sethi %lm(sym), %o0
+! CHECK: or %o0, 0, %o0
+or %o0, %hm(sym), %o0
+
+! CHECK: sethi 18641, %o0
+sethi %hix(sym), %o0
+! CHECK: xor %o0, -360, %o0
+xor %o0, %lox(sym), %o0

diff  --git a/llvm/test/MC/Sparc/sparc-relocations.s b/llvm/test/MC/Sparc/sparc-relocations.s
index 9acb1b34954a..f812105f503b 100644
--- a/llvm/test/MC/Sparc/sparc-relocations.s
+++ b/llvm/test/MC/Sparc/sparc-relocations.s
@@ -2,18 +2,24 @@
 ! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-readobj -r - | FileCheck %s --check-prefix=CHECK-OBJ
 
         ! CHECK-OBJ: Format: elf64-sparc
-        ! CHECK-OBJ: Relocations [
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 foo
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_LO10 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HI22 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_H44 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_M44 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_LM22 sym
-        ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_13 sym
-        ! CHECK-ELF: ]
+        ! CHECK-OBJ: .rela.text {
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 foo
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LO10 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HI22 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_H44 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_M44 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LM22 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_13 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_13 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HIX22 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LOX10 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOTDATA_HIX22 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOTDATA_LOX10 sym
+        ! CHECK-OBJ-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOTDATA_OP sym
+        ! CHECK-OBJ-NEXT: }
 
         ! CHECK: call foo     ! encoding: [0b01AAAAAA,A,A,A]
         ! CHECK:              !   fixup A - offset: 0, value: foo, kind: fixup_sparc_call30
@@ -59,6 +65,26 @@
         ! CHECK-NEXT:                  ! fixup A - offset: 0, value: sym+4, kind: fixup_sparc_13
         or %g1, (sym+4), %g3
 
+        ! CHECK: sethi %hix(sym), %g1 ! encoding: [0x03,0b00AAAAAA,A,A]
+        ! CHECK-NEXT:                 ! fixup A - offset: 0, value: %hix(sym), kind: fixup_sparc_hix22
+        sethi %hix(sym), %g1
+
+        ! CHECK: xor %g1, %lox(sym), %g1 ! encoding: [0x82,0x18,0b011AAAAA,A]
+        ! CHECK-NEXT:                    ! fixup A - offset: 0, value: %lox(sym), kind: fixup_sparc_lox10
+        xor %g1, %lox(sym), %g1
+
+        ! CHECK: sethi %gdop_hix22(sym), %l1 ! encoding: [0x23,0x00,0x00,0x00]
+        ! CHECK-NEXT:                        ! fixup A - offset: 0, value: %gdop_hix22(sym), kind: fixup_sparc_gotdata_hix22
+        sethi %gdop_hix22(sym), %l1
+
+        ! CHECK: or %l1, %gdop_lox10(sym), %l1 ! encoding: [0xa2,0x14,0x60,0x00]
+        ! CHECK-NEXT:                          ! fixup A - offset: 0, value: %gdop_lox10(sym), kind: fixup_sparc_gotdata_lox10
+        or %l1, %gdop_lox10(sym), %l1
+
+        ! CHECK: ldx [%l7+%l1], %l2, %gdop(sym) ! encoding: [0xe4,0x5d,0xc0,0x11]
+        ! CHECK-NEXT:                           ! fixup A - offset: 0, value: %gdop(sym), kind: fixup_sparc_gotdata_op
+        ldx [%l7 + %l1], %l2, %gdop(sym)
+
         ! This test needs to placed last in the file
         ! CHECK: .half	a-.Ltmp0
         .half a - .


        


More information about the llvm-commits mailing list