[mips] Correct the AFL_FLAGS1_ODDSPREG flag in .MIPS.abiflags when no '.module oddspr...
[oota-llvm.git] / lib / Target / Mips / AsmParser / MipsAsmParser.cpp
index 4a0059d55a3fab8c5030f0be4d5dabfc41f35e3f..765ac02df13b45080b0c795814ef76559553cce2 100644 (file)
@@ -38,7 +38,7 @@ class MCInstrInfo;
 namespace {
 class MipsAssemblerOptions {
 public:
-  MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true), fpAbiMode(0) {}
+  MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true) {}
 
   unsigned getATRegNum() { return aTReg; }
   bool setATReg(unsigned Reg);
@@ -46,18 +46,15 @@ public:
   bool isReorder() { return reorder; }
   void setReorder() { reorder = true; }
   void setNoreorder() { reorder = false; }
-  void setFpAbiMode(int Mode) { fpAbiMode = Mode; }
 
   bool isMacro() { return macro; }
   void setMacro() { macro = true; }
   void setNomacro() { macro = false; }
-  int getFpAbiMode() { return fpAbiMode; }
 
 private:
   unsigned aTReg;
   bool reorder;
   bool macro;
-  int fpAbiMode;
 };
 }
 
@@ -136,8 +133,8 @@ class MipsAsmParser : public MCTargetAsmParser {
   void expandMemInst(MCInst &Inst, SMLoc IDLoc,
                      SmallVectorImpl<MCInst> &Instructions, bool isLoad,
                      bool isImmOpnd);
-  bool reportParseError(StringRef ErrorMsg);
-  bool reportParseError(SMLoc Loc, StringRef ErrorMsg);
+  bool reportParseError(Twine ErrorMsg);
+  bool reportParseError(SMLoc Loc, Twine ErrorMsg);
 
   bool parseMemOffset(const MCExpr *&Res, bool isParenExpr);
   bool parseRelocOperand(const MCExpr *&Res);
@@ -167,6 +164,9 @@ class MipsAsmParser : public MCTargetAsmParser {
   bool parseDirectiveGpWord();
   bool parseDirectiveGpDWord();
   bool parseDirectiveModule();
+  bool parseDirectiveModuleFP();
+  bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI,
+                       StringRef Directive);
 
   MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol);
 
@@ -236,6 +236,9 @@ public:
             ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) +
             ((STI.getFeatureBits() & Mips::FeatureN32) != 0) +
             ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1);
+
+    if (!isABI_O32() && !useOddSPReg() != 0)
+      report_fatal_error("-mno-odd-spreg requires the O32 ABI");
   }
 
   MCAsmParser &getParser() const { return Parser; }
@@ -251,6 +254,10 @@ public:
   bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
   bool isABI_FPXX() const { return false; } // TODO: add check for FeatureXX
 
+  bool useOddSPReg() const {
+    return !(STI.getFeatureBits() & Mips::FeatureNoOddSPReg);
+  }
+
   bool inMicroMipsMode() const {
     return STI.getFeatureBits() & Mips::FeatureMicroMips;
   }
@@ -564,6 +571,10 @@ public:
   void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     Inst.addOperand(MCOperand::CreateReg(getFGR32Reg()));
+    // FIXME: We ought to do this for -integrated-as without -via-file-asm too.
+    if (!AsmParser.useOddSPReg() && RegIdx.Index & 1)
+      AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU "
+                                "registers");
   }
 
   void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const {
@@ -2304,13 +2315,13 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
   return false;
 }
 
-bool MipsAsmParser::reportParseError(StringRef ErrorMsg) {
+bool MipsAsmParser::reportParseError(Twine ErrorMsg) {
   SMLoc Loc = getLexer().getLoc();
   Parser.eatToEndOfStatement();
   return Error(Loc, ErrorMsg);
 }
 
-bool MipsAsmParser::reportParseError(SMLoc Loc, StringRef ErrorMsg) {
+bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) {
   return Error(Loc, ErrorMsg);
 }
 
@@ -2445,7 +2456,7 @@ bool MipsAsmParser::parseSetNoMips16Directive() {
 }
 
 bool MipsAsmParser::parseSetFpDirective() {
-  int FpAbiMode;
+  MipsABIFlagsSection::FpABIKind FpAbiVal;
   // Line can be: .set fp=32
   //              .set fp=xx
   //              .set fp=64
@@ -2457,43 +2468,15 @@ bool MipsAsmParser::parseSetFpDirective() {
   }
   Parser.Lex(); // Eat '=' token.
   Tok = Parser.getTok();
-  if (Tok.is(AsmToken::Identifier)) {
-    StringRef XX = Tok.getString();
-    if (XX != "xx") {
-      reportParseError("unsupported option");
-      return false;
-    }
-    if (!isABI_O32()) {
-      reportParseError("'set fp=xx'option requires O32 ABI");
-      return false;
-    }
-    FpAbiMode = Val_GNU_MIPS_ABI_FP_XX;
-  } else if (Tok.is(AsmToken::Integer)) {
-    unsigned Value = Tok.getIntVal();
-    if (Value != 32 && Value != 64) {
-      reportParseError("unsupported option");
-      return false;
-    }
-    if (Value == 32) {
-      if (!isABI_O32()) {
-        reportParseError("'set fp=32'option requires O32 ABI");
-        return false;
-      }
-      FpAbiMode = Val_GNU_MIPS_ABI_FP_DOUBLE;
-    } else {
-      if (isABI_N32() || isABI_N64())
-        FpAbiMode = Val_GNU_MIPS_ABI_FP_DOUBLE;
-      else if (isABI_O32())
-        FpAbiMode = Val_GNU_MIPS_ABI_FP_64;
-    }
-  }
-  Parser.Lex(); // Eat option token.
+
+  if (!parseFpABIValue(FpAbiVal, ".set"))
+    return false;
+
   if (getLexer().isNot(AsmToken::EndOfStatement)) {
     reportParseError("unexpected token in statement");
     return false;
   }
-  Options.setFpAbiMode(FpAbiMode);
-  getTargetStreamer().emitDirectiveSetFp(FpAbiMode, isABI_O32());
+  getTargetStreamer().emitDirectiveSetFp(FpAbiVal);
   Parser.Lex(); // Consume the EndOfStatement.
   return false;
 }
@@ -2813,61 +2796,134 @@ bool MipsAsmParser::parseDirectiveOption() {
   return false;
 }
 
+/// parseDirectiveModule
+///  ::= .module oddspreg
+///  ::= .module nooddspreg
+///  ::= .module fp=value
 bool MipsAsmParser::parseDirectiveModule() {
-  // Line can be: .module fp=32
-  //              .module fp=xx
-  //              .module fp=64
-  unsigned FpAbiVal = 0;
+  MCAsmLexer &Lexer = getLexer();
+  SMLoc L = Lexer.getLoc();
+
   if (!getTargetStreamer().getCanHaveModuleDir()) {
     // TODO : get a better message.
     reportParseError(".module directive must appear before any code");
     return false;
   }
-  AsmToken Tok = Parser.getTok();
-  if (Tok.isNot(AsmToken::Identifier) && Tok.getString() != "fp") {
-    reportParseError("unexpected token in .module directive, 'fp' expected");
-    return false;
+
+  if (Lexer.is(AsmToken::Identifier)) {
+    StringRef Option = Parser.getTok().getString();
+    Parser.Lex();
+
+    if (Option == "oddspreg") {
+      getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32());
+      clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
+
+      if (getLexer().isNot(AsmToken::EndOfStatement)) {
+        reportParseError("Expected end of statement");
+        return false;
+      }
+
+      return false;
+    } else if (Option == "nooddspreg") {
+      if (!isABI_O32()) {
+        Error(L, "'.module nooddspreg' requires the O32 ABI");
+        return false;
+      }
+
+      getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32());
+      setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
+
+      if (getLexer().isNot(AsmToken::EndOfStatement)) {
+        reportParseError("Expected end of statement");
+        return false;
+      }
+
+      return false;
+    } else if (Option == "fp") {
+      return parseDirectiveModuleFP();
+    }
+
+    return Error(L, "'" + Twine(Option) + "' is not a valid .module option.");
   }
-  Parser.Lex(); // Eat fp token
-  Tok = Parser.getTok();
-  if (Tok.isNot(AsmToken::Equal)) {
+
+  return false;
+}
+
+/// parseDirectiveModuleFP
+///  ::= =32
+///  ::= =xx
+///  ::= =64
+bool MipsAsmParser::parseDirectiveModuleFP() {
+  MCAsmLexer &Lexer = getLexer();
+
+  if (Lexer.isNot(AsmToken::Equal)) {
     reportParseError("unexpected token in statement");
     return false;
   }
   Parser.Lex(); // Eat '=' token.
-  Tok = Parser.getTok();
-  if (Tok.is(AsmToken::Identifier)) {
-    StringRef XX = Tok.getString();
-    if (XX != "xx") {
-      reportParseError("unsupported option");
-      return false;
-    }
-    FpAbiVal = Val_GNU_MIPS_ABI_FP_XX;
-  } else if (Tok.is(AsmToken::Integer)) {
-    unsigned Value = Tok.getIntVal();
-    if (Value != 32 && Value != 64) {
-      reportParseError("unsupported value, expected 32 or 64");
-      return false;
-    }
-    if (Value == 64) {
-      if (isABI_N32() || isABI_N64())
-        FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
-      else if (isABI_O32())
-        FpAbiVal = Val_GNU_MIPS_ABI_FP_64;
-    } else if (isABI_O32())
-      FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
-  }
-  Parser.Lex(); // Eat option token.
+
+  MipsABIFlagsSection::FpABIKind FpABI;
+  if (!parseFpABIValue(FpABI, ".module"))
+    return false;
+
   if (getLexer().isNot(AsmToken::EndOfStatement)) {
     reportParseError("unexpected token in statement");
     return false;
   }
+
   // Emit appropriate flags.
-  getTargetStreamer().emitDirectiveModule(FpAbiVal, isABI_O32());
-  getTargetStreamer().setFpABI(FpAbiVal);
+  getTargetStreamer().emitDirectiveModuleFP(FpABI, isABI_O32());
   Parser.Lex(); // Consume the EndOfStatement.
   return false;
 }
+
+bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI,
+                                    StringRef Directive) {
+  MCAsmLexer &Lexer = getLexer();
+
+  if (Lexer.is(AsmToken::Identifier)) {
+    StringRef Value = Parser.getTok().getString();
+    Parser.Lex();
+
+    if (Value != "xx") {
+      reportParseError("unsupported value, expected 'xx', '32' or '64'");
+      return false;
+    }
+
+    if (!isABI_O32()) {
+      reportParseError("'" + Directive + " fp=xx' requires the O32 ABI");
+      return false;
+    }
+
+    FpABI = MipsABIFlagsSection::FpABIKind::XX;
+    return true;
+  }
+
+  if (Lexer.is(AsmToken::Integer)) {
+    unsigned Value = Parser.getTok().getIntVal();
+    Parser.Lex();
+
+    if (Value != 32 && Value != 64) {
+      reportParseError("unsupported value, expected 'xx', '32' or '64'");
+      return false;
+    }
+
+    if (Value == 32) {
+      if (!isABI_O32()) {
+        reportParseError("'" + Directive + " fp=32' requires the O32 ABI");
+        return false;
+      }
+
+      FpABI = MipsABIFlagsSection::FpABIKind::S32;
+    } else
+      FpABI = MipsABIFlagsSection::FpABIKind::S64;
+
+    return true;
+  }
+
+  return false;
+}
+
 bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
   StringRef IDVal = DirectiveID.getString();