MC: Allow modifiers in MCSymbolRefExpr, and eliminate X86MCTargetExpr.
 - Although it would be nice to allow this decoupling, the assembler needs to be able to reason about MCSymbolRefExprs in too many places to make this viable. We can use a target specific encoding of the variant if this becomes an issue.
 - This patch also extends llvm-mc to support parsing of the modifiers, as opposed to lumping them in with the symbol.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98592 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp
index 3bd6b1b..a2ed20b 100644
--- a/lib/MC/MCExpr.cpp
+++ b/lib/MC/MCExpr.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/MC/MCExpr.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/MC/MCAsmLayout.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
@@ -27,7 +28,8 @@
     return;
 
   case MCExpr::SymbolRef: {
-    const MCSymbol &Sym = cast<MCSymbolRefExpr>(*this).getSymbol();
+    const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this);
+    const MCSymbol &Sym = SRE.getSymbol();
     
     // Parenthesize names that start with $ so that they don't look like
     // absolute names.
@@ -35,6 +37,10 @@
       OS << '(' << Sym << ')';
     else
       OS << Sym;
+
+    if (SRE.getKind() != MCSymbolRefExpr::VK_None)
+      OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind());
+
     return;
   }
 
@@ -127,20 +133,60 @@
   return new (Ctx) MCConstantExpr(Value);
 }
 
+/* *** */
+
 const MCSymbolRefExpr *MCSymbolRefExpr::Create(const MCSymbol *Sym,
+                                               VariantKind Kind,
                                                MCContext &Ctx) {
-  return new (Ctx) MCSymbolRefExpr(Sym);
+  return new (Ctx) MCSymbolRefExpr(Sym, Kind);
 }
 
-const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, MCContext &Ctx) {
-  return Create(Ctx.GetOrCreateSymbol(Name), Ctx);
+const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, VariantKind Kind,
+                                               MCContext &Ctx) {
+  return Create(Ctx.GetOrCreateSymbol(Name), Kind, Ctx);
 }
 
 const MCSymbolRefExpr *MCSymbolRefExpr::CreateTemp(StringRef Name,
+                                                   VariantKind Kind,
                                                    MCContext &Ctx) {
-  return Create(Ctx.GetOrCreateTemporarySymbol(Name), Ctx);
+  return Create(Ctx.GetOrCreateTemporarySymbol(Name), Kind, Ctx);
 }
 
+StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
+  switch (Kind) {
+  default:
+  case VK_Invalid: return "<<invalid>>";
+  case VK_None: return "<<none>>";
+
+  case VK_GOT: return "GOT";
+  case VK_GOTOFF: return "GOTOFF";
+  case VK_GOTPCREL: return "GOTPCREL";
+  case VK_GOTTPOFF: return "GOTTPOFF";
+  case VK_INDNTPOFF: return "INDNTPOFF";
+  case VK_NTPOFF: return "NTPOFF";
+  case VK_PLT: return "PLT";
+  case VK_TLSGD: return "TLSGD";
+  case VK_TPOFF: return "TPOFF";
+  }
+}
+
+MCSymbolRefExpr::VariantKind
+MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
+  return StringSwitch<VariantKind>(Name)
+    .Case("GOT", VK_GOT)
+    .Case("GOTOFF", VK_GOTOFF)
+    .Case("GOTPCREL", VK_GOTPCREL)
+    .Case("GOTTPOFF", VK_GOTTPOFF)
+    .Case("INDNTPOFF", VK_INDNTPOFF)
+    .Case("NTPOFF", VK_NTPOFF)
+    .Case("PLT", VK_PLT)
+    .Case("TLSGD", VK_TLSGD)
+    .Case("TPOFF", VK_TPOFF)
+    .Default(VK_Invalid);
+}
+
+/* *** */
+
 void MCTargetExpr::Anchor() {}
 
 /* *** */
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index a241106..4ec5247 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -262,19 +262,29 @@
   case AsmToken::String:
   case AsmToken::Identifier: {
     // This is a symbol reference.
-    MCSymbol *Sym = CreateSymbol(getTok().getIdentifier());
+    std::pair<StringRef, StringRef> Split = getTok().getIdentifier().split('@');
+    MCSymbol *Sym = CreateSymbol(Split.first);
+
+    // Lookup the symbol variant if used.
+    MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+    if (Split.first.size() != getTok().getIdentifier().size())
+      Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
+
     EndLoc = Lexer.getLoc();
     Lex(); // Eat identifier.
 
     // If this is an absolute variable reference, substitute it now to preserve
     // semantics in the face of reassignment.
     if (Sym->getValue() && isa<MCConstantExpr>(Sym->getValue())) {
+      if (Variant)
+        return Error(EndLoc, "unexpected modified on variable reference");
+
       Res = Sym->getValue();
       return false;
     }
 
     // Otherwise create a symbol ref.
-    Res = MCSymbolRefExpr::Create(Sym, getContext());
+    Res = MCSymbolRefExpr::Create(Sym, Variant, getContext());
     return false;
   }
   case AsmToken::Integer: