[Sparc] Add support for parsing directives in SparcAsmParser.
[oota-llvm.git] / lib / Target / Sparc / AsmParser / SparcAsmParser.cpp
index 13f62666fceca803ad76dfc22d627ef0b55476c9..924e3c32c648f81307b0d4326ceee12384135545 100644 (file)
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "MCTargetDesc/SparcMCExpr.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInst.h"
@@ -53,6 +54,8 @@ class SparcAsmParser : public MCTargetAsmParser {
                         SmallVectorImpl<MCParsedAsmOperand*> &Operands);
   bool ParseDirective(AsmToken DirectiveID);
 
+  virtual unsigned validateTargetOperandClass(MCParsedAsmOperand *Op,
+                                              unsigned Kind);
 
   // Custom parse functions for Sparc specific operands.
   OperandMatchResultTy
@@ -66,9 +69,13 @@ class SparcAsmParser : public MCTargetAsmParser {
   parseSparcAsmOperand(SparcOperand *&Operand);
 
   // returns true if Tok is matched to a register and returns register in RegNo.
-  bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP,
-                         bool isQFP);
+  bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo,
+                         unsigned &RegKind);
 
+  bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc);
+  bool parseDirectiveWord(unsigned Size, SMLoc L);
+
+  bool is64Bit() const { return STI.getTargetTriple().startswith("sparcv9"); }
 public:
   SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
                 const MCInstrInfo &MII)
@@ -112,7 +119,7 @@ public:
   static unsigned QuadFPRegs[32] = {
     Sparc::Q0,  Sparc::Q1,  Sparc::Q2,  Sparc::Q3,
     Sparc::Q4,  Sparc::Q5,  Sparc::Q6,  Sparc::Q7,
-    Sparc::Q8,  Sparc::Q7,  Sparc::Q8,  Sparc::Q9,
+    Sparc::Q8,  Sparc::Q9,  Sparc::Q10, Sparc::Q11,
     Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
 
 
@@ -176,6 +183,16 @@ public:
   bool isMEMrr() const { return Kind == k_MemoryReg; }
   bool isMEMri() const { return Kind == k_MemoryImm; }
 
+  bool isFloatReg() const {
+    return (Kind == k_Register && Reg.Kind == rk_FloatReg);
+  }
+
+  bool isFloatOrDoubleReg() const {
+    return (Kind == k_Register && (Reg.Kind == rk_FloatReg
+                                   || Reg.Kind == rk_DoubleReg));
+  }
+
+
   StringRef getToken() const {
     assert(Kind == k_Token && "Invalid access!");
     return StringRef(Tok.Data, Tok.Length);
@@ -278,11 +295,11 @@ public:
   }
 
   static SparcOperand *CreateReg(unsigned RegNum,
-                                 SparcOperand::RegisterKind Kind,
+                                 unsigned Kind,
                                  SMLoc S, SMLoc E) {
     SparcOperand *Op = new SparcOperand(k_Register);
     Op->Reg.RegNum = RegNum;
-    Op->Reg.Kind   = Kind;
+    Op->Reg.Kind   = (SparcOperand::RegisterKind)Kind;
     Op->StartLoc = S;
     Op->EndLoc = E;
     return Op;
@@ -296,6 +313,40 @@ public:
     return Op;
   }
 
+  static SparcOperand *MorphToDoubleReg(SparcOperand *Op) {
+    unsigned Reg = Op->getReg();
+    assert(Op->Reg.Kind == rk_FloatReg);
+    unsigned regIdx = Reg - Sparc::F0;
+    if (regIdx % 2 || regIdx > 31)
+      return 0;
+    Op->Reg.RegNum = DoubleRegs[regIdx / 2];
+    Op->Reg.Kind = rk_DoubleReg;
+    return Op;
+  }
+
+  static SparcOperand *MorphToQuadReg(SparcOperand *Op) {
+    unsigned Reg = Op->getReg();
+    unsigned regIdx = 0;
+    switch (Op->Reg.Kind) {
+    default: assert(0 && "Unexpected register kind!");
+    case rk_FloatReg:
+      regIdx = Reg - Sparc::F0;
+      if (regIdx % 4 || regIdx > 31)
+        return 0;
+      Reg = QuadFPRegs[regIdx / 4];
+      break;
+    case rk_DoubleReg:
+      regIdx =  Reg - Sparc::D0;
+      if (regIdx % 2 || regIdx > 31)
+        return 0;
+      Reg = QuadFPRegs[regIdx / 2];
+      break;
+    }
+    Op->Reg.RegNum  = Reg;
+    Op->Reg.Kind = rk_QuadReg;
+    return Op;
+  }
+
   static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) {
     unsigned offsetReg = Op->getReg();
     Op->Kind = k_MemoryReg;
@@ -344,7 +395,7 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
 
   case Match_Success: {
     Inst.setLoc(IDLoc);
-    Out.EmitInstruction(Inst);
+    Out.EmitInstruction(Inst, STI);
     return false;
   }
 
@@ -381,7 +432,8 @@ ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc)
   if (getLexer().getKind() != AsmToken::Percent)
     return false;
   Parser.Lex();
-  if (matchRegisterName(Tok, RegNo, false, false)) {
+  unsigned regKind = SparcOperand::rk_None;
+  if (matchRegisterName(Tok, RegNo, regKind)) {
     Parser.Lex();
     return false;
   }
@@ -432,8 +484,52 @@ ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
 bool SparcAsmParser::
 ParseDirective(AsmToken DirectiveID)
 {
-  // Ignore all directives for now.
-  Parser.eatToEndOfStatement();
+  StringRef IDVal = DirectiveID.getString();
+
+  if (IDVal == ".byte")
+    return parseDirectiveWord(1, DirectiveID.getLoc());
+
+  if (IDVal == ".half")
+    return parseDirectiveWord(2, DirectiveID.getLoc());
+
+  if (IDVal == ".word")
+    return parseDirectiveWord(4, DirectiveID.getLoc());
+
+  if (IDVal == ".nword")
+    return parseDirectiveWord(is64Bit() ? 8 : 4, DirectiveID.getLoc());
+
+  if (is64Bit() && IDVal == ".xword")
+    return parseDirectiveWord(8, DirectiveID.getLoc());
+
+  if (IDVal == ".register") {
+    // For now, ignore .register directive.
+    Parser.eatToEndOfStatement();
+    return false;
+  }
+
+  // Let the MC layer to handle other directives.
+  return true;
+}
+
+bool SparcAsmParser:: parseDirectiveWord(unsigned Size, SMLoc L) {
+  if (getLexer().isNot(AsmToken::EndOfStatement)) {
+    for (;;) {
+      const MCExpr *Value;
+      if (getParser().parseExpression(Value))
+        return true;
+
+      getParser().getStreamer().EmitValue(Value, Size);
+
+      if (getLexer().is(AsmToken::EndOfStatement))
+        break;
+
+      // FIXME: Improve diagnostic.
+      if (getLexer().isNot(AsmToken::Comma))
+        return Error(L, "unexpected token in directive");
+      Parser.Lex();
+    }
+  }
+  Parser.Lex();
   return false;
 }
 
@@ -451,6 +547,7 @@ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
   switch (getLexer().getKind()) {
   default: return MatchOperand_NoMatch;
 
+  case AsmToken::Comma:
   case AsmToken::RBrac:
   case AsmToken::EndOfStatement:
     Operands.push_back(SparcOperand::CreateMEMri(BaseReg, 0, S, E));
@@ -495,7 +592,24 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
                                                  Parser.getTok().getLoc()));
     Parser.Lex(); // Eat the [
 
-    ResTy = parseMEMOperand(Operands);
+    if (Mnemonic == "cas" || Mnemonic == "casx") {
+      SMLoc S = Parser.getTok().getLoc();
+      if (getLexer().getKind() != AsmToken::Percent)
+        return MatchOperand_NoMatch;
+      Parser.Lex(); // eat %
+
+      unsigned RegNo, RegKind;
+      if (!matchRegisterName(Parser.getTok(), RegNo, RegKind))
+        return MatchOperand_NoMatch;
+
+      Parser.Lex(); // Eat the identifier token.
+      SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer()-1);
+      Operands.push_back(SparcOperand::CreateReg(RegNo, RegKind, S, E));
+      ResTy = MatchOperand_Success;
+    } else {
+      ResTy = parseMEMOperand(Operands);
+    }
+
     if (ResTy != MatchOperand_Success)
       return ResTy;
 
@@ -534,30 +648,53 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op)
   case AsmToken::Percent:
     Parser.Lex(); // Eat the '%'.
     unsigned RegNo;
-    if (matchRegisterName(Parser.getTok(), RegNo, false, false)) {
+    unsigned RegKind;
+    if (matchRegisterName(Parser.getTok(), RegNo, RegKind)) {
+      StringRef name = Parser.getTok().getString();
       Parser.Lex(); // Eat the identifier token.
-      Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
+      E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+      switch (RegNo) {
+      default:
+        Op = SparcOperand::CreateReg(RegNo, RegKind, S, E);
+        break;
+      case Sparc::Y:
+        Op = SparcOperand::CreateToken("%y", S);
+        break;
+
+      case Sparc::ICC:
+        if (name == "xcc")
+          Op = SparcOperand::CreateToken("%xcc", S);
+        else
+          Op = SparcOperand::CreateToken("%icc", S);
+        break;
+
+      case Sparc::FCC:
+        assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet");
+        Op = SparcOperand::CreateToken("%fcc0", S);
+        break;
+      }
       break;
     }
-    // FIXME: Handle modifiers like %hi, %lo etc.,
+    if (matchSparcAsmModifiers(EVal, E)) {
+      E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+      Op = SparcOperand::CreateImm(EVal, S, E);
+    }
     break;
 
   case AsmToken::Minus:
   case AsmToken::Integer:
-    if (!getParser().parseExpression(EVal))
+    if (!getParser().parseExpression(EVal, E))
       Op = SparcOperand::CreateImm(EVal, S, E);
     break;
 
   case AsmToken::Identifier: {
     StringRef Identifier;
     if (!getParser().parseIdentifier(Identifier)) {
-      SMLoc E = SMLoc::getFromPointer(Parser.getTok().
-                                      getLoc().getPointer() - 1);
+      E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
       MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier);
 
       const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
                                                   getContext());
-
       Op = SparcOperand::CreateImm(Res, S, E);
     }
     break;
@@ -568,38 +705,43 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op)
 
 bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
                                        unsigned &RegNo,
-                                       bool isDFP,
-                                       bool isQFP)
+                                       unsigned &RegKind)
 {
   int64_t intVal = 0;
   RegNo = 0;
+  RegKind = SparcOperand::rk_None;
   if (Tok.is(AsmToken::Identifier)) {
     StringRef name = Tok.getString();
 
     // %fp
     if (name.equals("fp")) {
       RegNo = Sparc::I6;
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
     // %sp
     if (name.equals("sp")) {
       RegNo = Sparc::O6;
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
 
     if (name.equals("y")) {
       RegNo = Sparc::Y;
+      RegKind = SparcOperand::rk_Y;
       return true;
     }
 
     if (name.equals("icc")) {
       RegNo = Sparc::ICC;
+      RegKind = SparcOperand::rk_CCReg;
       return true;
     }
 
     if (name.equals("xcc")) {
       // FIXME:: check 64bit.
       RegNo = Sparc::ICC;
+      RegKind = SparcOperand::rk_CCReg;
       return true;
     }
 
@@ -609,6 +751,7 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
         && intVal < 4) {
       // FIXME: check 64bit and  handle %fcc1 - %fcc3
       RegNo = Sparc::FCC;
+      RegKind = SparcOperand::rk_CCReg;
       return true;
     }
 
@@ -617,6 +760,7 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
         && !name.substr(1).getAsInteger(10, intVal)
         && intVal < 8) {
       RegNo = IntRegs[intVal];
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
     // %o0 - %o7
@@ -624,43 +768,37 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
         && !name.substr(1).getAsInteger(10, intVal)
         && intVal < 8) {
       RegNo = IntRegs[8 + intVal];
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
     if (name.substr(0, 1).equals_lower("l")
         && !name.substr(1).getAsInteger(10, intVal)
         && intVal < 8) {
       RegNo = IntRegs[16 + intVal];
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
     if (name.substr(0, 1).equals_lower("i")
         && !name.substr(1).getAsInteger(10, intVal)
         && intVal < 8) {
       RegNo = IntRegs[24 + intVal];
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
     // %f0 - %f31
     if (name.substr(0, 1).equals_lower("f")
         && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) {
-      if (isDFP && (intVal%2 == 0)) {
-        RegNo = DoubleRegs[intVal/2];
-      } else if (isQFP && (intVal%4 == 0)) {
-        RegNo = QuadFPRegs[intVal/4];
-      } else {
-        RegNo = FloatRegs[intVal];
-      }
+      RegNo = FloatRegs[intVal];
+      RegKind = SparcOperand::rk_FloatReg;
       return true;
     }
     // %f32 - %f62
     if (name.substr(0, 1).equals_lower("f")
         && !name.substr(1, 2).getAsInteger(10, intVal)
         && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) {
-      if (isDFP) {
-        RegNo = DoubleRegs[16 + intVal/2];
-      } else if (isQFP && (intVal % 4 == 0)) {
-        RegNo = QuadFPRegs[8 + intVal/4];
-      } else {
-        return false;
-      }
+      // FIXME: Check V9
+      RegNo = DoubleRegs[intVal/2];
+      RegKind = SparcOperand::rk_DoubleReg;
       return true;
     }
 
@@ -668,6 +806,7 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
     if (name.substr(0, 1).equals_lower("r")
         && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) {
       RegNo = IntRegs[intVal];
+      RegKind = SparcOperand::rk_IntReg;
       return true;
     }
   }
@@ -675,6 +814,32 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
 }
 
 
+bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal,
+                                            SMLoc &EndLoc)
+{
+  AsmToken Tok = Parser.getTok();
+  if (!Tok.is(AsmToken::Identifier))
+    return false;
+
+  StringRef name = Tok.getString();
+
+  SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name);
+
+  if (VK == SparcMCExpr::VK_Sparc_None)
+    return false;
+
+  Parser.Lex(); // Eat the identifier.
+  if (Parser.getTok().getKind() != AsmToken::LParen)
+    return false;
+
+  Parser.Lex(); // Eat the LParen token.
+  const MCExpr *subExpr;
+  if (Parser.parseParenExpression(subExpr, EndLoc))
+    return false;
+  EVal = SparcMCExpr::Create(VK, subExpr, getContext());
+  return true;
+}
+
 
 extern "C" void LLVMInitializeSparcAsmParser() {
   RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
@@ -684,3 +849,26 @@ extern "C" void LLVMInitializeSparcAsmParser() {
 #define GET_REGISTER_MATCHER
 #define GET_MATCHER_IMPLEMENTATION
 #include "SparcGenAsmMatcher.inc"
+
+
+
+unsigned SparcAsmParser::
+validateTargetOperandClass(MCParsedAsmOperand *GOp,
+                           unsigned Kind)
+{
+  SparcOperand *Op = (SparcOperand*)GOp;
+  if (Op->isFloatOrDoubleReg()) {
+    switch (Kind) {
+    default: break;
+    case MCK_DFPRegs:
+      if (!Op->isFloatReg() || SparcOperand::MorphToDoubleReg(Op))
+        return MCTargetAsmParser::Match_Success;
+      break;
+    case MCK_QFPRegs:
+      if (SparcOperand::MorphToQuadReg(Op))
+        return MCTargetAsmParser::Match_Success;
+      break;
+    }
+  }
+  return Match_InvalidOperand;
+}