[mips] Add support to '.set mips64r2'.
[oota-llvm.git] / lib / Target / Mips / AsmParser / MipsAsmParser.cpp
index e99de130779955427abeea6d67992935a3737ec7..2244e3dec646c8d0101816fe8e6c00dc2bfe48c5 100644 (file)
@@ -16,6 +16,7 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCParser/MCAsmLexer.h"
 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
 #include "llvm/MC/MCStreamer.h"
@@ -194,6 +195,7 @@ class MipsAsmParser : public MCTargetAsmParser {
   const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr);
 
   bool isEvaluated(const MCExpr *Expr);
+  bool parseSetFeature(uint64_t Feature);
   bool parseDirectiveSet();
   bool parseDirectiveOption();
 
@@ -203,7 +205,6 @@ class MipsAsmParser : public MCTargetAsmParser {
   bool parseSetNoMacroDirective();
   bool parseSetReorderDirective();
   bool parseSetNoReorderDirective();
-  bool parseSetMips16Directive();
   bool parseSetNoMips16Directive();
 
   bool parseSetAssignment();
@@ -221,6 +222,7 @@ class MipsAsmParser : public MCTargetAsmParser {
     return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0;
   }
 
+  bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
   bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; }
 
   bool isMicroMips() const {
@@ -249,6 +251,9 @@ class MipsAsmParser : public MCTargetAsmParser {
 
   int getATReg();
 
+  // Warn if RegNo is the current assembler temporary.
+  void warnIfAssemblerTemporary(int RegNo);
+
   bool processInstruction(MCInst &Inst, SMLoc IDLoc,
                           SmallVectorImpl<MCInst> &Instructions);
 
@@ -257,6 +262,20 @@ class MipsAsmParser : public MCTargetAsmParser {
   // Example: INSERT.B $w0[n], $1 => 16 > n >= 0
   bool validateMSAIndex(int Val, int RegKind);
 
+  void setFeatureBits(unsigned Feature, StringRef FeatureString) {
+    if (!(STI.getFeatureBits() & Feature)) {
+      setAvailableFeatures(ComputeAvailableFeatures(
+                           STI.ToggleFeature(FeatureString)));
+    }
+  }
+
+  void clearFeatureBits(unsigned Feature, StringRef FeatureString) {
+    if (STI.getFeatureBits() & Feature) {
+     setAvailableFeatures(ComputeAvailableFeatures(
+                           STI.ToggleFeature(FeatureString)));
+    }
+  }
+
 public:
   MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
                 const MCInstrInfo &MII)
@@ -264,6 +283,12 @@ public:
         hasConsumedDollar(false) {
     // Initialize the set of available features.
     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+
+    // Assert exactly one ABI was chosen.
+    assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) +
+            ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) +
+            ((STI.getFeatureBits() & Mips::FeatureN32) != 0) +
+            ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1);
   }
 
   MCAsmParser &getParser() const { return Parser; }
@@ -569,6 +594,7 @@ static const MCInstrDesc &getInstDesc(unsigned Opcode) {
 bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
                                        SmallVectorImpl<MCInst> &Instructions) {
   const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+
   Inst.setLoc(IDLoc);
 
   if (MCID.isBranch() || MCID.isCall()) {
@@ -670,6 +696,10 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) {
   case Mips::LoadImm32Reg:
   case Mips::LoadAddr32Imm:
   case Mips::LoadAddr32Reg:
+  case Mips::SUBi:
+  case Mips::SUBiu:
+  case Mips::DSUBi:
+  case Mips::DSUBiu:
     return true;
   default:
     return false;
@@ -685,6 +715,30 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc,
     return expandLoadAddressImm(Inst, IDLoc, Instructions);
   case Mips::LoadAddr32Reg:
     return expandLoadAddressReg(Inst, IDLoc, Instructions);
+  case Mips::SUBi:
+    Instructions.push_back(MCInstBuilder(Mips::ADDi)
+                               .addReg(Inst.getOperand(0).getReg())
+                               .addReg(Inst.getOperand(1).getReg())
+                               .addImm(-Inst.getOperand(2).getImm()));
+    return;
+  case Mips::SUBiu:
+    Instructions.push_back(MCInstBuilder(Mips::ADDiu)
+                               .addReg(Inst.getOperand(0).getReg())
+                               .addReg(Inst.getOperand(1).getReg())
+                               .addImm(-Inst.getOperand(2).getImm()));
+    return;
+  case Mips::DSUBi:
+    Instructions.push_back(MCInstBuilder(Mips::DADDi)
+                               .addReg(Inst.getOperand(0).getReg())
+                               .addReg(Inst.getOperand(1).getReg())
+                               .addImm(-Inst.getOperand(2).getImm()));
+    return;
+  case Mips::DSUBiu:
+    Instructions.push_back(MCInstBuilder(Mips::DADDiu)
+                               .addReg(Inst.getOperand(0).getReg())
+                               .addReg(Inst.getOperand(1).getReg())
+                               .addImm(-Inst.getOperand(2).getImm()));
+    return;
   }
 }
 
@@ -932,14 +986,23 @@ bool MipsAsmParser::MatchAndEmitInstruction(
   return true;
 }
 
+void MipsAsmParser::warnIfAssemblerTemporary(int RegNo) {
+  if ((RegNo != 0) && ((int)Options.getATRegNum() == RegNo)) {
+    if (RegNo == 1)
+      Warning(getLexer().getLoc(), "Used $at without \".set noat\"");
+    else
+      Warning(getLexer().getLoc(), Twine("Used $") + Twine(RegNo) +
+                                       " with \".set at=$" + Twine(RegNo) +
+                                       "\"");
+  }
+}
+
 int MipsAsmParser::matchCPURegisterName(StringRef Name) {
   int CC;
 
-  if (Name == "at")
-    return getATReg();
-
   CC = StringSwitch<unsigned>(Name)
            .Case("zero", 0)
+           .Case("at", 1)
            .Case("a0", 4)
            .Case("a1", 5)
            .Case("a2", 6)
@@ -956,9 +1019,10 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) {
            .Case("s7", 23)
            .Case("k0", 26)
            .Case("k1", 27)
+           .Case("gp", 28)
            .Case("sp", 29)
            .Case("fp", 30)
-           .Case("gp", 28)
+           .Case("s8", 30)
            .Case("ra", 31)
            .Case("t0", 8)
            .Case("t1", 9)
@@ -972,22 +1036,25 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) {
            .Case("t9", 25)
            .Default(-1);
 
-  // Although SGI documentation just cuts out t0-t3 for n32/n64,
-  // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7
-  // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7.
-  if (isMips64() && 8 <= CC && CC <= 11)
-    CC += 4;
-
-  if (CC == -1 && isMips64())
-    CC = StringSwitch<unsigned>(Name)
-             .Case("a4", 8)
-             .Case("a5", 9)
-             .Case("a6", 10)
-             .Case("a7", 11)
-             .Case("kt0", 26)
-             .Case("kt1", 27)
-             .Case("s8", 30)
-             .Default(-1);
+  if (isN32() || isN64()) {
+    // Although SGI documentation just cuts out t0-t3 for n32/n64,
+    // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7
+    // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7.
+    if (8 <= CC && CC <= 11)
+      CC += 4;
+
+    if (CC == -1)
+      CC = StringSwitch<unsigned>(Name)
+               .Case("a4", 8)
+               .Case("a5", 9)
+               .Case("a6", 10)
+               .Case("a7", 11)
+               .Case("kt0", 26)
+               .Case("kt1", 27)
+               .Default(-1);
+  }
+
+  warnIfAssemblerTemporary(CC);
 
   return CC;
 }
@@ -1124,7 +1191,12 @@ bool MipsAssemblerOptions::setATReg(unsigned Reg) {
   return true;
 }
 
-int MipsAsmParser::getATReg() { return Options.getATRegNum(); }
+int MipsAsmParser::getATReg() {
+  int AT = Options.getATRegNum();
+  if (AT == 0)
+    TokError("Pseudo instruction requires $at, which is not available");
+  return AT;
+}
 
 unsigned MipsAsmParser::getReg(int RC, int RegNo) {
   return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo);
@@ -1135,6 +1207,9 @@ int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) {
       getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs())
     return -1;
 
+  if (RegClass == Mips::GPR32RegClassID || RegClass == Mips::GPR64RegClassID)
+    warnIfAssemblerTemporary(RegNum);
+
   return getReg(RegClass, RegNum);
 }
 
@@ -2280,7 +2355,7 @@ bool MipsAsmParser::parseSetAtDirective() {
       return false;
     }
 
-    if (AtRegNo < 1 || AtRegNo > 31) {
+    if (AtRegNo < 0 || AtRegNo > 31) {
       reportParseError("unexpected token in statement");
       return false;
     }
@@ -2311,6 +2386,7 @@ bool MipsAsmParser::parseSetReorderDirective() {
     return false;
   }
   Options.setReorder();
+  getTargetStreamer().emitDirectiveSetReorder();
   Parser.Lex(); // Consume the EndOfStatement.
   return false;
 }
@@ -2356,18 +2432,6 @@ bool MipsAsmParser::parseSetNoMacroDirective() {
   return false;
 }
 
-bool MipsAsmParser::parseSetMips16Directive() {
-  Parser.Lex();
-  // If this is not the end of the statement, report an error.
-  if (getLexer().isNot(AsmToken::EndOfStatement)) {
-    reportParseError("unexpected token in statement");
-    return false;
-  }
-  getTargetStreamer().emitDirectiveSetMips16();
-  Parser.Lex(); // Consume the EndOfStatement.
-  return false;
-}
-
 bool MipsAsmParser::parseSetNoMips16Directive() {
   Parser.Lex();
   // If this is not the end of the statement, report an error.
@@ -2404,6 +2468,35 @@ bool MipsAsmParser::parseSetAssignment() {
   return false;
 }
 
+bool MipsAsmParser::parseSetFeature(uint64_t Feature) {
+  Parser.Lex();
+  if (getLexer().isNot(AsmToken::EndOfStatement))
+    return reportParseError("unexpected token in .set directive");
+
+  switch(Feature) {
+    default: llvm_unreachable("Unimplemented feature");
+    case Mips::FeatureDSP:
+      setFeatureBits(Mips::FeatureDSP, "dsp");
+      getTargetStreamer().emitDirectiveSetDsp();
+    break;
+    case Mips::FeatureMicroMips:
+      getTargetStreamer().emitDirectiveSetMicroMips();
+    break;
+    case Mips::FeatureMips16:
+      getTargetStreamer().emitDirectiveSetMips16();
+    break;
+    case Mips::FeatureMips32r2:
+      setFeatureBits(Mips::FeatureMips32r2, "mips32r2");
+      getTargetStreamer().emitDirectiveSetMips32R2();
+    break;
+    case Mips::FeatureMips64r2:
+      setFeatureBits(Mips::FeatureMips64r2, "mips64r2");
+      getTargetStreamer().emitDirectiveSetMips64R2();
+    break;
+  }
+  return false;
+}
+
 bool MipsAsmParser::parseDirectiveSet() {
 
   // Get the next token.
@@ -2422,7 +2515,7 @@ bool MipsAsmParser::parseDirectiveSet() {
   } else if (Tok.getString() == "nomacro") {
     return parseSetNoMacroDirective();
   } else if (Tok.getString() == "mips16") {
-    return parseSetMips16Directive();
+    return parseSetFeature(Mips::FeatureMips16);
   } else if (Tok.getString() == "nomips16") {
     return parseSetNoMips16Directive();
   } else if (Tok.getString() == "nomicromips") {
@@ -2430,9 +2523,13 @@ bool MipsAsmParser::parseDirectiveSet() {
     Parser.eatToEndOfStatement();
     return false;
   } else if (Tok.getString() == "micromips") {
-    getTargetStreamer().emitDirectiveSetMicroMips();
-    Parser.eatToEndOfStatement();
-    return false;
+      return parseSetFeature(Mips::FeatureMicroMips);
+  } else if (Tok.getString() == "mips32r2") {
+      return parseSetFeature(Mips::FeatureMips32r2);
+  } else if (Tok.getString() == "mips64r2") {
+      return parseSetFeature(Mips::FeatureMips64r2);
+  } else if (Tok.getString() == "dsp") {
+      return parseSetFeature(Mips::FeatureDSP);
   } else {
     // It is just an identifier, look for an assignment.
     parseSetAssignment();
@@ -2506,6 +2603,17 @@ bool MipsAsmParser::parseDirectiveOption() {
     return false;
   }
 
+  if (Option == "pic2") {
+    getTargetStreamer().emitDirectiveOptionPic2();
+    Parser.Lex();
+    if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
+      Error(Parser.getTok().getLoc(),
+            "unexpected token in .option pic2 directive");
+      Parser.eatToEndOfStatement();
+    }
+    return false;
+  }
+
   // Unknown option.
   Warning(Parser.getTok().getLoc(), "unknown option in .option directive");
   Parser.eatToEndOfStatement();