Mips.abiflags is a new implicitly generated section that will be present on all...
authorVladimir Medic <Vladimir.Medic@imgtec.com>
Tue, 8 Jul 2014 08:59:22 +0000 (08:59 +0000)
committerVladimir Medic <Vladimir.Medic@imgtec.com>
Tue, 8 Jul 2014 08:59:22 +0000 (08:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212519 91177308-0d34-0410-b5e6-96231b3b80d8

18 files changed:
include/llvm/Support/ELF.h
lib/MC/ELFObjectWriter.cpp
lib/Target/Mips/AsmParser/MipsAsmParser.cpp
lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
lib/Target/Mips/MipsAsmPrinter.cpp
lib/Target/Mips/MipsSubtarget.h
lib/Target/Mips/MipsTargetStreamer.h
test/CodeGen/Mips/abiflags-xx.ll [new file with mode: 0644]
test/CodeGen/Mips/abiflags32.ll [new file with mode: 0644]
test/MC/Mips/mips-abi-bad.s [new file with mode: 0644]
test/MC/Mips/mips-data-directives.s
test/MC/Mips/mips32/abiflags.s [new file with mode: 0644]
test/MC/Mips/mips32r2/abiflags.s [new file with mode: 0644]
test/MC/Mips/mips64/abiflags.s [new file with mode: 0644]
test/MC/Mips/mips64r2/abi-bad.s [new file with mode: 0644]
test/MC/Mips/mips64r2/abiflags.s [new file with mode: 0644]
test/MC/Mips/mips_abi_flags_xx.s [new file with mode: 0644]
test/MC/Mips/mips_abi_flags_xx_set.s [new file with mode: 0644]

index 31b34ffa703e40f79b0ea93780031b2b0e995492..67cc651f88be8245388f3fa4a7dcea174587533c 100644 (file)
@@ -1299,6 +1299,7 @@ enum : unsigned {
 
   SHT_MIPS_REGINFO        = 0x70000006, // Register usage information
   SHT_MIPS_OPTIONS        = 0x7000000d, // General options
+  SHT_MIPS_ABIFLAGS       = 0x7000002a, // ABI information.
 
   SHT_HIPROC        = 0x7fffffff, // Highest processor arch-specific type.
   SHT_LOUSER        = 0x80000000, // Lowest type reserved for applications.
@@ -1616,7 +1617,8 @@ enum {
   // MIPS program header types.
   PT_MIPS_REGINFO  = 0x70000000,  // Register usage information.
   PT_MIPS_RTPROC   = 0x70000001,  // Runtime procedure table.
-  PT_MIPS_OPTIONS  = 0x70000002   // Options segment.
+  PT_MIPS_OPTIONS  = 0x70000002,  // Options segment.
+  PT_MIPS_ABIFLAGS = 0x70000003   // Abiflags segment.
 };
 
 // Segment flag bits.
index ead05351458c7ce25fd11fbb63f5f945adc93496..7fb9fae54a768074fe002d5c92b3d0a15a92982f 100644 (file)
@@ -1565,6 +1565,7 @@ void ELFObjectWriter::WriteSection(MCAssembler &Asm,
   case ELF::SHT_X86_64_UNWIND:
   case ELF::SHT_MIPS_REGINFO:
   case ELF::SHT_MIPS_OPTIONS:
+  case ELF::SHT_MIPS_ABIFLAGS:
     // Nothing to do.
     break;
 
index dc9ed2feeb9c04d50b9b9f8d4e0fd8a8398d84f5..4a0059d55a3fab8c5030f0be4d5dabfc41f35e3f 100644 (file)
@@ -38,7 +38,7 @@ class MCInstrInfo;
 namespace {
 class MipsAssemblerOptions {
 public:
-  MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true) {}
+  MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true), fpAbiMode(0) {}
 
   unsigned getATRegNum() { return aTReg; }
   bool setATReg(unsigned Reg);
@@ -46,15 +46,18 @@ 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;
 };
 }
 
@@ -156,39 +159,17 @@ class MipsAsmParser : public MCTargetAsmParser {
   bool parseSetReorderDirective();
   bool parseSetNoReorderDirective();
   bool parseSetNoMips16Directive();
+  bool parseSetFpDirective();
 
   bool parseSetAssignment();
 
   bool parseDataDirective(unsigned Size, SMLoc L);
   bool parseDirectiveGpWord();
   bool parseDirectiveGpDWord();
+  bool parseDirectiveModule();
 
   MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol);
 
-  bool isGP64() const {
-    return (STI.getFeatureBits() & Mips::FeatureGP64Bit) != 0;
-  }
-
-  bool isFP64() const {
-    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 {
-    return STI.getFeatureBits() & Mips::FeatureMicroMips;
-  }
-
-  bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; }
-  bool hasMips32() const { return STI.getFeatureBits() & Mips::FeatureMips32; }
-  bool hasMips32r6() const {
-    return STI.getFeatureBits() & Mips::FeatureMips32r6;
-  }
-  bool hasMips64r6() const {
-    return STI.getFeatureBits() & Mips::FeatureMips64r6;
-  }
-
   bool eatComma(StringRef ErrorStr);
 
   int matchCPURegisterName(StringRef Symbol);
@@ -243,12 +224,13 @@ public:
   };
 
   MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
-                const MCInstrInfo &MII,
-                const MCTargetOptions &Options)
+                const MCInstrInfo &MII, const MCTargetOptions &Options)
       : MCTargetAsmParser(), STI(sti), Parser(parser) {
     // Initialize the set of available features.
     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
 
+    getTargetStreamer().updateABIInfo(*this);
+
     // Assert exactly one ABI was chosen.
     assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) +
             ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) +
@@ -262,6 +244,49 @@ public:
   /// True if all of $fcc0 - $fcc7 exist for the current ISA.
   bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); }
 
+  bool isGP64bit() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; }
+  bool isFP64bit() const { return STI.getFeatureBits() & Mips::FeatureFP64Bit; }
+  bool isABI_N32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
+  bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; }
+  bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
+  bool isABI_FPXX() const { return false; } // TODO: add check for FeatureXX
+
+  bool inMicroMipsMode() const {
+    return STI.getFeatureBits() & Mips::FeatureMicroMips;
+  }
+  bool hasMips1() const { return STI.getFeatureBits() & Mips::FeatureMips1; }
+  bool hasMips2() const { return STI.getFeatureBits() & Mips::FeatureMips2; }
+  bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; }
+  bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; }
+  bool hasMips5() const { return STI.getFeatureBits() & Mips::FeatureMips5; }
+  bool hasMips32() const {
+    return (STI.getFeatureBits() & Mips::FeatureMips32);
+  }
+  bool hasMips64() const {
+    return (STI.getFeatureBits() & Mips::FeatureMips64);
+  }
+  bool hasMips32r2() const {
+    return (STI.getFeatureBits() & Mips::FeatureMips32r2);
+  }
+  bool hasMips64r2() const {
+    return (STI.getFeatureBits() & Mips::FeatureMips64r2);
+  }
+  bool hasMips32r6() const {
+    return (STI.getFeatureBits() & Mips::FeatureMips32r6);
+  }
+  bool hasMips64r6() const {
+    return (STI.getFeatureBits() & Mips::FeatureMips64r6);
+  }
+  bool hasDSP() const { return (STI.getFeatureBits() & Mips::FeatureDSP); }
+  bool hasDSPR2() const { return (STI.getFeatureBits() & Mips::FeatureDSPR2); }
+  bool hasMSA() const { return (STI.getFeatureBits() & Mips::FeatureMSA); }
+
+  bool inMips16Mode() const {
+    return STI.getFeatureBits() & Mips::FeatureMips16;
+  }
+  // TODO: see how can we get this info.
+  bool mipsSEUsesSoftFloat() const { return false; }
+
   /// Warn if RegNo is the current assembler temporary.
   void WarnIfAssemblerTemporary(int RegNo, SMLoc Loc);
 };
@@ -276,9 +301,9 @@ public:
   /// Broad categories of register classes
   /// The exact class is finalized by the render method.
   enum RegKind {
-    RegKind_GPR = 1,      /// GPR32 and GPR64 (depending on isGP64())
+    RegKind_GPR = 1,      /// GPR32 and GPR64 (depending on isGP64bit())
     RegKind_FGR = 2,      /// FGR32, FGR64, AFGR64 (depending on context and
-                          /// isFP64())
+                          /// isFP64bit())
     RegKind_FCC = 4,      /// FCC
     RegKind_MSA128 = 8,   /// MSA128[BHWD] (makes no difference which)
     RegKind_MSACtrl = 16, /// MSA control registers
@@ -882,9 +907,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
       Offset = Inst.getOperand(2);
       if (!Offset.isImm())
         break; // We'll deal with this situation later on when applying fixups.
-      if (!isIntN(isMicroMips() ? 17 : 18, Offset.getImm()))
+      if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm()))
         return Error(IDLoc, "branch target out of range");
-      if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2)))
+      if (OffsetToAlignment(Offset.getImm(),
+                            1LL << (inMicroMipsMode() ? 1 : 2)))
         return Error(IDLoc, "branch to misaligned address");
       break;
     case Mips::BGEZ:
@@ -907,9 +933,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
       Offset = Inst.getOperand(1);
       if (!Offset.isImm())
         break; // We'll deal with this situation later on when applying fixups.
-      if (!isIntN(isMicroMips() ? 17 : 18, Offset.getImm()))
+      if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm()))
         return Error(IDLoc, "branch target out of range");
-      if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2)))
+      if (OffsetToAlignment(Offset.getImm(),
+                            1LL << (inMicroMipsMode() ? 1 : 2)))
         return Error(IDLoc, "branch to misaligned address");
       break;
     }
@@ -994,12 +1021,13 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) {
 bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc,
                                       SmallVectorImpl<MCInst> &Instructions) {
   switch (Inst.getOpcode()) {
-  default: assert(0 && "unimplemented expansion");
+  default:
+    assert(0 && "unimplemented expansion");
     return true;
   case Mips::LoadImm32Reg:
     return expandLoadImm(Inst, IDLoc, Instructions);
   case Mips::LoadImm64Reg:
-    if (!isGP64()) {
+    if (!isGP64bit()) {
       Error(IDLoc, "instruction requires a CPU feature not currently enabled");
       return true;
     }
@@ -1074,8 +1102,8 @@ bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc,
     Instructions.push_back(tmpInst);
     createShiftOr<0, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions);
   } else if ((ImmValue & (0xffffLL << 48)) == 0) {
-    if (!isGP64()) {
-      Error (IDLoc, "instruction requires a CPU feature not currently enabled");
+    if (!isGP64bit()) {
+      Error(IDLoc, "instruction requires a CPU feature not currently enabled");
       return true;
     }
 
@@ -1101,8 +1129,8 @@ bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc,
     createShiftOr<16, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions);
     createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions);
   } else {
-    if (!isGP64()) {
-      Error (IDLoc, "instruction requires a CPU feature not currently enabled");
+    if (!isGP64bit()) {
+      Error(IDLoc, "instruction requires a CPU feature not currently enabled");
       return true;
     }
 
@@ -1274,8 +1302,8 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc,
     // not available.
     if (!AT)
       return;
-    TmpRegNum =
-        getReg((isGP64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT);
+    TmpRegNum = getReg(
+        (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT);
   }
 
   TempInst.setOpcode(Mips::LUi);
@@ -1433,7 +1461,7 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) {
            .Case("t9", 25)
            .Default(-1);
 
-  if (isN32() || isN64()) {
+  if (isABI_N32() || isABI_N64()) {
     // 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.
@@ -1546,7 +1574,7 @@ unsigned MipsAsmParser::getReg(int RC, int RegNo) {
 }
 
 unsigned MipsAsmParser::getGPR(int RegNo) {
-  return getReg(isGP64() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID,
+  return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID,
                 RegNo);
 }
 
@@ -1771,7 +1799,7 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
     // register is a parse error.
     if (Operand.isGPRAsmReg()) {
       // Resolve to GPR32 or GPR64 appropriately.
-      RegNo = isGP64() ? Operand.getGPR64Reg() : Operand.getGPR32Reg();
+      RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg();
     }
 
     return (RegNo == (unsigned)-1);
@@ -2227,6 +2255,9 @@ bool MipsAsmParser::ParseBracketSuffix(StringRef Name,
 bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
                                      SMLoc NameLoc, OperandVector &Operands) {
   DEBUG(dbgs() << "ParseInstruction\n");
+  // We have reached first instruction, module directive after
+  // this is forbidden.
+  getTargetStreamer().setCanHaveModuleDir(false);
   // Check if we have valid mnemonic
   if (!mnemonicIsValid(Name, 0)) {
     Parser.eatToEndOfStatement();
@@ -2413,6 +2444,60 @@ bool MipsAsmParser::parseSetNoMips16Directive() {
   return false;
 }
 
+bool MipsAsmParser::parseSetFpDirective() {
+  int FpAbiMode;
+  // Line can be: .set fp=32
+  //              .set fp=xx
+  //              .set fp=64
+  Parser.Lex(); // Eat fp token
+  AsmToken Tok = Parser.getTok();
+  if (Tok.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;
+    }
+    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 (getLexer().isNot(AsmToken::EndOfStatement)) {
+    reportParseError("unexpected token in statement");
+    return false;
+  }
+  Options.setFpAbiMode(FpAbiMode);
+  getTargetStreamer().emitDirectiveSetFp(FpAbiMode, isABI_O32());
+  Parser.Lex(); // Consume the EndOfStatement.
+  return false;
+}
+
 bool MipsAsmParser::parseSetAssignment() {
   StringRef Name;
   const MCExpr *Value;
@@ -2594,6 +2679,8 @@ bool MipsAsmParser::parseDirectiveSet() {
     return parseSetNoAtDirective();
   } else if (Tok.getString() == "at") {
     return parseSetAtDirective();
+  } else if (Tok.getString() == "fp") {
+    return parseSetFpDirective();
   } else if (Tok.getString() == "reorder") {
     return parseSetReorderDirective();
   } else if (Tok.getString() == "noreorder") {
@@ -2726,6 +2813,61 @@ bool MipsAsmParser::parseDirectiveOption() {
   return false;
 }
 
+bool MipsAsmParser::parseDirectiveModule() {
+  // Line can be: .module fp=32
+  //              .module fp=xx
+  //              .module fp=64
+  unsigned FpAbiVal = 0;
+  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;
+  }
+  Parser.Lex(); // Eat fp token
+  Tok = Parser.getTok();
+  if (Tok.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.
+  if (getLexer().isNot(AsmToken::EndOfStatement)) {
+    reportParseError("unexpected token in statement");
+    return false;
+  }
+  // Emit appropriate flags.
+  getTargetStreamer().emitDirectiveModule(FpAbiVal, isABI_O32());
+  getTargetStreamer().setFpABI(FpAbiVal);
+  Parser.Lex(); // Consume the EndOfStatement.
+  return false;
+}
 bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
   StringRef IDVal = DirectiveID.getString();
 
@@ -2804,6 +2946,9 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
   if (IDVal == ".cpsetup")
     return parseDirectiveCPSetup();
 
+  if (IDVal == ".module")
+    return parseDirectiveModule();
+
   return true;
 }
 
index 1b03024924071b34549c568d4c4070292e8d358a..a81849e2a38ce832a3b7ba1b94e64e2f134871f3 100644 (file)
@@ -27,7 +27,8 @@
 
 using namespace llvm;
 
-MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
+MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S)
+    : MCTargetStreamer(S), canHaveModuleDirective(true) {}
 void MipsTargetStreamer::emitDirectiveSetMicroMips() {}
 void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {}
 void MipsTargetStreamer::emitDirectiveSetMips16() {}
@@ -65,42 +66,52 @@ MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S,
 
 void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() {
   OS << "\t.set\tmicromips\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() {
   OS << "\t.set\tnomicromips\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetMips16() {
   OS << "\t.set\tmips16\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() {
   OS << "\t.set\tnomips16\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetReorder() {
   OS << "\t.set\treorder\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() {
   OS << "\t.set\tnoreorder\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetMacro() {
   OS << "\t.set\tmacro\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() {
   OS << "\t.set\tnomacro\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetAt() {
   OS << "\t.set\tat\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetNoAt() {
   OS << "\t.set\tnoat\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) {
@@ -137,24 +148,28 @@ void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize,
 
 void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() {
   OS << "\t.set\tmips32r2\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetMips64() {
   OS << "\t.set\tmips64\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() {
   OS << "\t.set\tmips64r2\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveSetDsp() {
   OS << "\t.set\tdsp\n";
+  setCanHaveModuleDir(false);
 }
 // Print a 32 bit hex number with all numbers.
 static void printHex32(unsigned Value, raw_ostream &OS) {
   OS << "0x";
   for (int i = 7; i >= 0; i--)
-    OS.write_hex((Value & (0xF << (i*4))) >> (i*4));
+    OS.write_hex((Value & (0xF << (i * 4))) >> (i * 4));
 }
 
 void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask,
@@ -174,6 +189,7 @@ void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask,
 void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) {
   OS << "\t.cpload\t$"
      << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n";
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
@@ -192,6 +208,57 @@ void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
   OS << ", ";
 
   OS << Sym.getName() << "\n";
+  setCanHaveModuleDir(false);
+}
+
+void MipsTargetAsmStreamer::emitDirectiveModule(unsigned Value,
+                                                bool is32BitAbi) {
+  StringRef ModuleValue;
+  OS << "\t.module\tfp=";
+  switch (Value) {
+  case Val_GNU_MIPS_ABI_FP_XX:
+    ModuleValue = "xx";
+    break;
+  case Val_GNU_MIPS_ABI_FP_64:
+    ModuleValue = "64";
+    break;
+  case Val_GNU_MIPS_ABI_FP_DOUBLE:
+    if (is32BitAbi)
+      ModuleValue = "32";
+    else
+      ModuleValue = "64";
+    break;
+  default:
+    llvm_unreachable("unsupported .module value");
+  }
+  OS << ModuleValue << "\n";
+}
+
+void MipsTargetAsmStreamer::emitDirectiveSetFp(unsigned Value,
+                                               bool is32BitAbi) {
+  StringRef ModuleValue;
+  OS << "\t.set\tfp=";
+  switch (Value) {
+  case Val_GNU_MIPS_ABI_FP_XX:
+    ModuleValue = "xx";
+    break;
+  case Val_GNU_MIPS_ABI_FP_64:
+    ModuleValue = "64";
+    break;
+  case Val_GNU_MIPS_ABI_FP_DOUBLE:
+    if (is32BitAbi)
+      ModuleValue = "32";
+    else
+      ModuleValue = "64";
+    break;
+  default:
+    llvm_unreachable("unsupported .set fp value");
+  }
+  OS << ModuleValue << "\n";
+}
+
+void MipsTargetAsmStreamer::emitMipsAbiFlags() {
+  // No action required for text output.
 }
 
 // This part is for ELF object output.
@@ -201,7 +268,7 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
   MCAssembler &MCA = getStreamer().getAssembler();
   uint64_t Features = STI.getFeatureBits();
   Triple T(STI.getTargetTriple());
-  Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() ==  Reloc::PIC_)
+  Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_)
             ? true
             : false;
 
@@ -283,17 +350,17 @@ void MipsTargetELFStreamer::finish() {
         ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata());
     OS.SwitchSection(Sec);
 
-    OS.EmitIntValue(1, 1); // kind
+    OS.EmitIntValue(1, 1);  // kind
     OS.EmitIntValue(40, 1); // size
-    OS.EmitIntValue(0, 2); // section
-    OS.EmitIntValue(0, 4); // info
-    OS.EmitIntValue(0, 4); // ri_gprmask
-    OS.EmitIntValue(0, 4); // pad
-    OS.EmitIntValue(0, 4); // ri_cpr[0]mask
-    OS.EmitIntValue(0, 4); // ri_cpr[1]mask
-    OS.EmitIntValue(0, 4); // ri_cpr[2]mask
-    OS.EmitIntValue(0, 4); // ri_cpr[3]mask
-    OS.EmitIntValue(0, 8); // ri_gp_value
+    OS.EmitIntValue(0, 2);  // section
+    OS.EmitIntValue(0, 4);  // info
+    OS.EmitIntValue(0, 4);  // ri_gprmask
+    OS.EmitIntValue(0, 4);  // pad
+    OS.EmitIntValue(0, 4);  // ri_cpr[0]mask
+    OS.EmitIntValue(0, 4);  // ri_cpr[1]mask
+    OS.EmitIntValue(0, 4);  // ri_cpr[2]mask
+    OS.EmitIntValue(0, 4);  // ri_cpr[3]mask
+    OS.EmitIntValue(0, 8);  // ri_gp_value
   } else {
     const MCSectionELF *Sec =
         Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC,
@@ -307,6 +374,7 @@ void MipsTargetELFStreamer::finish() {
     OS.EmitIntValue(0, 4); // ri_cpr[3]mask
     OS.EmitIntValue(0, 4); // ri_gp_value
   }
+  emitMipsAbiFlags();
 }
 
 void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol,
@@ -315,11 +383,11 @@ void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol,
   if (Value->getKind() != MCExpr::SymbolRef)
     return;
   const MCSymbol &RhsSym =
-    static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
+      static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
   MCSymbolData &Data = getStreamer().getOrCreateSymbolData(&RhsSym);
   uint8_t Type = MCELF::GetType(Data);
-  if ((Type != ELF::STT_FUNC)
-      || !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2)))
+  if ((Type != ELF::STT_FUNC) ||
+      !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2)))
     return;
 
   MCSymbolData &SymbolData = getStreamer().getOrCreateSymbolData(Symbol);
@@ -344,6 +412,7 @@ void MipsTargetELFStreamer::emitDirectiveSetMicroMips() {
 
 void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() {
   MicroMipsEnabled = false;
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetMips16() {
@@ -351,14 +420,17 @@ void MipsTargetELFStreamer::emitDirectiveSetMips16() {
   unsigned Flags = MCA.getELFHeaderEFlags();
   Flags |= ELF::EF_MIPS_ARCH_ASE_M16;
   MCA.setELFHeaderEFlags(Flags);
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetNoMips16() {
   // FIXME: implement.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetReorder() {
   // FIXME: implement.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetNoReorder() {
@@ -366,22 +438,27 @@ void MipsTargetELFStreamer::emitDirectiveSetNoReorder() {
   unsigned Flags = MCA.getELFHeaderEFlags();
   Flags |= ELF::EF_MIPS_NOREORDER;
   MCA.setELFHeaderEFlags(Flags);
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetMacro() {
   // FIXME: implement.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetNoMacro() {
   // FIXME: implement.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetAt() {
   // FIXME: implement.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetNoAt() {
   // FIXME: implement.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) {
@@ -450,19 +527,19 @@ void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask,
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetMips32R2() {
-  // No action required for ELF output.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetMips64() {
-  // No action required for ELF output.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetMips64R2() {
-  // No action required for ELF output.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveSetDsp() {
-  // No action required for ELF output.
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) {
@@ -512,6 +589,8 @@ void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) {
   TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
   TmpInst.addOperand(MCOperand::CreateReg(RegNo));
   getStreamer().EmitInstruction(TmpInst, STI);
+
+  setCanHaveModuleDir(false);
 }
 
 void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
@@ -567,4 +646,30 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
   Inst.addOperand(MCOperand::CreateReg(Mips::GP));
   Inst.addOperand(MCOperand::CreateReg(RegNo));
   getStreamer().EmitInstruction(Inst, STI);
+
+  setCanHaveModuleDir(false);
+}
+
+void MipsTargetELFStreamer::emitMipsAbiFlags() {
+  MCAssembler &MCA = getStreamer().getAssembler();
+  MCContext &Context = MCA.getContext();
+  MCStreamer &OS = getStreamer();
+  const MCSectionELF *Sec =
+      Context.getELFSection(".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS,
+                            ELF::SHF_ALLOC, SectionKind::getMetadata());
+  MCSectionData &ABIShndxSD = MCA.getOrCreateSectionData(*Sec);
+  ABIShndxSD.setAlignment(8);
+  OS.SwitchSection(Sec);
+
+  OS.EmitIntValue(MipsABIFlags.version, 2);   // version
+  OS.EmitIntValue(MipsABIFlags.isa_level, 1); // isa_level
+  OS.EmitIntValue(MipsABIFlags.isa_rev, 1);   // isa_rev
+  OS.EmitIntValue(MipsABIFlags.gpr_size, 1);  // gpr_size
+  OS.EmitIntValue(MipsABIFlags.cpr1_size, 1); // cpr1_size
+  OS.EmitIntValue(MipsABIFlags.cpr2_size, 1); // cpr2_size
+  OS.EmitIntValue(MipsABIFlags.fp_abi, 1);    // fp_abi
+  OS.EmitIntValue(MipsABIFlags.isa_ext, 4);   // isa_ext
+  OS.EmitIntValue(MipsABIFlags.ases, 4);      // ases
+  OS.EmitIntValue(MipsABIFlags.flags1, 4);    // flags1
+  OS.EmitIntValue(MipsABIFlags.flags2, 4);    // flags2
 }
index 6df90aa75a114dd715bf22ea1bec669efb5816c8..6070932b5cd0fcc31f104aca5d31c8b0df1edcf2 100644 (file)
@@ -92,6 +92,8 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
 #include "MipsGenMCPseudoLowering.inc"
 
 void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
+  MipsTargetStreamer &TS = getTargetStreamer();
+  TS.setCanHaveModuleDir(false);
   if (MI->isDebugValue()) {
     SmallString<128> Str;
     raw_svector_ostream OS(Str);
@@ -657,6 +659,19 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
           OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0,
                                    SectionKind::getDataRel()));
   }
+  getTargetStreamer().updateABIInfo(*Subtarget);
+  unsigned FpAbiVal;
+  if (Subtarget->isABI_N32() || Subtarget->isABI_N64())
+    FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
+  else if(Subtarget->isABI_O32()) {
+    if (Subtarget->isFP64bit())
+      FpAbiVal = Val_GNU_MIPS_ABI_FP_64;
+    else if(Subtarget->isABI_FPXX())
+      FpAbiVal = Val_GNU_MIPS_ABI_FP_XX;
+    else
+      FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
+  }
+  getTargetStreamer().emitDirectiveModule(FpAbiVal, Subtarget->isABI_O32());
 }
 
 void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) {
@@ -852,7 +867,7 @@ void MipsAsmPrinter::EmitFPCallStub(
   TS.emitDirectiveSetNoMicroMips();
   //
   // .ent __call_stub_fp_xxxx
-  // .type     __call_stub_fp_xxxx,@function
+  // .type  __call_stub_fp_xxxx,@function
   //  __call_stub_fp_xxxx:
   //
   std::string x = "__call_stub_fp_" + std::string(Symbol);
index f8c4e3ba32f68a4c472a050d5ea77bbbbc9735b6..1d94bbaafb773d90261e2d9bff7cb079eb725013 100644 (file)
@@ -162,6 +162,7 @@ public:
   bool isABI_N64() const { return MipsABI == N64; }
   bool isABI_N32() const { return MipsABI == N32; }
   bool isABI_O32() const { return MipsABI == O32; }
+  bool isABI_FPXX() const { return false; } // TODO: add check for FPXX
   unsigned getTargetABI() const { return MipsABI; }
 
   /// This constructor initializes the data members to match that
@@ -174,8 +175,11 @@ public:
   /// subtarget options.  Definition of function is auto generated by tblgen.
   void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
 
+  bool hasMips1() const { return MipsArchVersion >= Mips1; }
   bool hasMips2() const { return MipsArchVersion >= Mips2; }
   bool hasMips3() const { return MipsArchVersion >= Mips3; }
+  bool hasMips4() const { return MipsArchVersion >= Mips4; }
+  bool hasMips5() const { return MipsArchVersion >= Mips5; }
   bool hasMips4_32() const { return HasMips4_32; }
   bool hasMips4_32r2() const { return HasMips4_32r2; }
   bool hasMips32() const {
index 2ae61382cd5ed09bcc584211d8d5a1ac4d516bdf..a0edc6f85d8164f9ae9f6a863652cd41cdc3e162 100644 (file)
 #include "llvm/MC/MCStreamer.h"
 
 namespace llvm {
+struct Elf_Internal_ABIFlags_v0 {
+  // Version of flags structure.
+  uint16_t version;
+  // The level of the ISA: 1-5, 32, 64.
+  uint8_t isa_level;
+  // The revision of ISA: 0 for MIPS V and below, 1-n otherwise.
+  uint8_t isa_rev;
+  // The size of general purpose registers.
+  uint8_t gpr_size;
+  // The size of co-processor 1 registers.
+  uint8_t cpr1_size;
+  // The size of co-processor 2 registers.
+  uint8_t cpr2_size;
+  // The floating-point ABI.
+  uint8_t fp_abi;
+  // Processor-specific extension.
+  uint32_t isa_ext;
+  // Mask of ASEs used.
+  uint32_t ases;
+  // Mask of general flags.
+  uint32_t flags1;
+  uint32_t flags2;
+
+  Elf_Internal_ABIFlags_v0()
+      : version(0), isa_level(0), isa_rev(0), gpr_size(0), cpr1_size(0),
+        cpr2_size(0), fp_abi(0), isa_ext(0), ases(0), flags1(0), flags2(0) {}
+};
+
+// Values for the xxx_size bytes of an ABI flags structure.
+enum {
+  AFL_REG_NONE = 0x00, // No registers.
+  AFL_REG_32 = 0x01,   // 32-bit registers.
+  AFL_REG_64 = 0x02,   // 64-bit registers.
+  AFL_REG_128 = 0x03   // 128-bit registers.
+};
+
+// Masks for the ases word of an ABI flags structure.
+enum {
+  AFL_ASE_DSP = 0x00000001,       // DSP ASE.
+  AFL_ASE_DSPR2 = 0x00000002,     // DSP R2 ASE.
+  AFL_ASE_EVA = 0x00000004,       // Enhanced VA Scheme.
+  AFL_ASE_MCU = 0x00000008,       // MCU (MicroController) ASE.
+  AFL_ASE_MDMX = 0x00000010,      // MDMX ASE.
+  AFL_ASE_MIPS3D = 0x00000020,    // MIPS-3D ASE.
+  AFL_ASE_MT = 0x00000040,        // MT ASE.
+  AFL_ASE_SMARTMIPS = 0x00000080, // SmartMIPS ASE.
+  AFL_ASE_VIRT = 0x00000100,      // VZ ASE.
+  AFL_ASE_MSA = 0x00000200,       // MSA ASE.
+  AFL_ASE_MIPS16 = 0x00000400,    // MIPS16 ASE.
+  AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE.
+  AFL_ASE_XPA = 0x00001000        // XPA ASE.
+};
+
+// Values for the isa_ext word of an ABI flags structure.
+enum {
+  AFL_EXT_XLR = 1,          // RMI Xlr instruction.
+  AFL_EXT_OCTEON2 = 2,      // Cavium Networks Octeon2.
+  AFL_EXT_OCTEONP = 3,      // Cavium Networks OcteonP.
+  AFL_EXT_LOONGSON_3A = 4,  // Loongson 3A.
+  AFL_EXT_OCTEON = 5,       // Cavium Networks Octeon.
+  AFL_EXT_5900 = 6,         // MIPS R5900 instruction.
+  AFL_EXT_4650 = 7,         // MIPS R4650 instruction.
+  AFL_EXT_4010 = 8,         // LSI R4010 instruction.
+  AFL_EXT_4100 = 9,         // NEC VR4100 instruction.
+  AFL_EXT_3900 = 10,        // Toshiba R3900 instruction.
+  AFL_EXT_10000 = 11,       // MIPS R10000 instruction.
+  AFL_EXT_SB1 = 12,         // Broadcom SB-1 instruction.
+  AFL_EXT_4111 = 13,        // NEC VR4111/VR4181 instruction.
+  AFL_EXT_4120 = 14,        // NEC VR4120 instruction.
+  AFL_EXT_5400 = 15,        // NEC VR5400 instruction.
+  AFL_EXT_5500 = 16,        // NEC VR5500 instruction.
+  AFL_EXT_LOONGSON_2E = 17, // ST Microelectronics Loongson 2E.
+  AFL_EXT_LOONGSON_2F = 18  // ST Microelectronics Loongson 2F.
+};
+
+// Values for the fp_abi word of an ABI flags structure.
+enum {
+  Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+  Val_GNU_MIPS_ABI_FP_XX = 5,
+  Val_GNU_MIPS_ABI_FP_64 = 6
+};
+
 class MipsTargetStreamer : public MCTargetStreamer {
 public:
   MipsTargetStreamer(MCStreamer &S);
@@ -50,6 +132,109 @@ public:
   virtual void emitDirectiveCpload(unsigned RegNo);
   virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
                                     const MCSymbol &Sym, bool IsReg);
+  // ABI Flags
+  virtual void emitDirectiveModule(unsigned Value, bool is32BitAbi){};
+  virtual void emitDirectiveSetFp(unsigned Value, bool is32BitAbi){};
+  virtual void emitMipsAbiFlags(){};
+  void setCanHaveModuleDir(bool Can) { canHaveModuleDirective = Can; }
+  bool getCanHaveModuleDir() { return canHaveModuleDirective; }
+
+  void setVersion(uint16_t Version) { MipsABIFlags.version = Version; }
+  void setISALevel(uint8_t Level) { MipsABIFlags.isa_level = Level; }
+  void setISARev(uint8_t Rev) { MipsABIFlags.isa_rev = Rev; }
+  void setGprSize(uint8_t Size) { MipsABIFlags.gpr_size = Size; }
+  void setCpr1Size(uint8_t Size) { MipsABIFlags.cpr1_size = Size; }
+  void setCpr2Size(uint8_t Size) { MipsABIFlags.cpr2_size = Size; }
+  void setFpABI(uint8_t Abi) { MipsABIFlags.fp_abi = Abi; }
+  void setIsaExt(uint32_t IsaExt) { MipsABIFlags.isa_ext = IsaExt; }
+  void setASEs(uint32_t Ases) { MipsABIFlags.ases = Ases; }
+  void setFlags1(uint32_t Flags) { MipsABIFlags.flags1 = Flags; }
+  void setFlags2(uint32_t Flags) { MipsABIFlags.flags2 = Flags; }
+
+  uint8_t getFPAbi() { return MipsABIFlags.fp_abi; }
+  // This method enables template classes to set internal abi flags
+  // structure values.
+  template <class PredicateLibrary>
+  void updateABIInfo(const PredicateLibrary &P) {
+    setVersion(0); // Version, default value is 0.
+
+    if (P.hasMips64()) { // isa_level
+      setISALevel(64);
+      if (P.hasMips64r6())
+        setISARev(6);
+      else if (P.hasMips64r2())
+        setISARev(2);
+      else
+        setISARev(1);
+    } else if (P.hasMips32()) {
+      setISALevel(32);
+      if (P.hasMips32r6())
+        setISARev(6);
+      else if (P.hasMips32r2())
+        setISARev(2);
+      else
+        setISARev(1);
+    } else {
+      setISARev(0);
+      if (P.hasMips5())
+        setISALevel(5);
+      else if (P.hasMips4())
+        setISALevel(4);
+      else if (P.hasMips3())
+        setISALevel(3);
+      else if (P.hasMips2())
+        setISALevel(2);
+      else if (P.hasMips1())
+        setISALevel(1);
+      else
+        llvm_unreachable("Unknown ISA level!");
+    }
+
+    if (P.isGP64bit()) // GPR size.
+      setGprSize(AFL_REG_64);
+    else
+      setGprSize(AFL_REG_32);
+
+    // TODO: check for MSA128 value.
+    if (P.mipsSEUsesSoftFloat())
+      setCpr1Size(AFL_REG_NONE);
+    else if (P.isFP64bit())
+      setCpr1Size(AFL_REG_64);
+    else
+      setCpr1Size(AFL_REG_32);
+    setCpr2Size(AFL_REG_NONE); // Default value.
+
+    // Set ASE.
+    unsigned AseFlags = 0;
+    if (P.hasDSP())
+      AseFlags |= AFL_ASE_DSP;
+    if (P.hasDSPR2())
+      AseFlags |= AFL_ASE_DSPR2;
+    if (P.hasMSA())
+      AseFlags |= AFL_ASE_MSA;
+    if (P.inMicroMipsMode())
+      AseFlags |= AFL_ASE_MICROMIPS;
+    if (P.inMips16Mode())
+      AseFlags |= AFL_ASE_MIPS16;
+
+    if (P.isABI_N32() || P.isABI_N64())
+      setFpABI(Val_GNU_MIPS_ABI_FP_DOUBLE);
+    else if (P.isABI_O32()) {
+      if (P.isFP64bit())
+        setFpABI(Val_GNU_MIPS_ABI_FP_64);
+      else if (P.isABI_FPXX())
+        setFpABI(Val_GNU_MIPS_ABI_FP_XX);
+      else
+        setFpABI(Val_GNU_MIPS_ABI_FP_DOUBLE);
+    } else
+      setFpABI(0); // Default value.
+  }
+
+protected:
+  Elf_Internal_ABIFlags_v0 MipsABIFlags;
+
+private:
+  bool canHaveModuleDirective;
 };
 
 // This part is for ascii assembly output
@@ -91,6 +276,11 @@ public:
   virtual void emitDirectiveCpload(unsigned RegNo);
   void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
                             const MCSymbol &Sym, bool IsReg) override;
+
+  // ABI Flags
+  void emitDirectiveModule(unsigned Value, bool is32BitAbi) override;
+  void emitDirectiveSetFp(unsigned Value, bool is32BitAbi) override;
+  void emitMipsAbiFlags() override;
 };
 
 // This part is for ELF object output
@@ -142,6 +332,9 @@ public:
   void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
                             const MCSymbol &Sym, bool IsReg) override;
 
+  // ABI Flags
+  void emitMipsAbiFlags() override;
+
 protected:
   bool isO32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
   bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
diff --git a/test/CodeGen/Mips/abiflags-xx.ll b/test/CodeGen/Mips/abiflags-xx.ll
new file mode 100644 (file)
index 0000000..b8aa071
--- /dev/null
@@ -0,0 +1,6 @@
+; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 -mattr=fpxx %s -o - | FileCheck %s
+; XFAIL: *
+
+; CHECK: .nan    legacy
+; CHECK: .module fp=xx
+
diff --git a/test/CodeGen/Mips/abiflags32.ll b/test/CodeGen/Mips/abiflags32.ll
new file mode 100644 (file)
index 0000000..093964f
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 %s -o - | FileCheck %s
+; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 -mattr=fp64 %s -o - | FileCheck  -check-prefix=CHECK-64 %s
+; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips64 -mattr=-n64,n32 %s -o - | FileCheck  -check-prefix=CHECK-64n %s
+
+; CHECK: .nan    legacy
+; CHECK: .module fp=32
+
+; CHECK-64: .nan    legacy
+; CHECK-64: .module fp=64
+
+; CHECK-64n: .nan    legacy
+; CHECK-64n: .module fp=64
diff --git a/test/MC/Mips/mips-abi-bad.s b/test/MC/Mips/mips-abi-bad.s
new file mode 100644 (file)
index 0000000..c4653cf
--- /dev/null
@@ -0,0 +1,20 @@
+# Error checking for malformed abi related directives
+# RUN: not llvm-mc -triple mips-unknown-unknown %s 2>&1 | FileCheck %s
+# CHECK: .text
+    .module fp=3
+# CHECK      : mips-abi-bad.s:4:16: error: unsupported option
+# CHECK-NEXT : .module fp=3
+# CHECK-NEXT :           ^
+
+    .set fp=xx,6
+# CHECK      :mips-abi-bad.s:5:15: error: unexpected token in statement
+# CHECK-NEXT :    .set fp=xx,6
+# CHECK-NEXT :              ^
+
+# CHECK       :.set mips16
+    .set mips16
+    .module fp=32
+
+# CHECK      :mips-abi-bad.s:14:13: error: .module directive must come before any code
+# CHECK-NEXT :    .module fp=32
+# CHECK-NEXT :            ^
index 630a807ca7bff9eda62cc3fee99cd4dd8646744c..8b3e0b3aa19a22d0d2aba5555089393cefca6c28 100644 (file)
@@ -12,7 +12,7 @@
 
 # Checking if the data and reloations were correctly emitted
 # CHECK-OBJ:  Section {
-# CHECK-OBJ:    Name: .data (51)
+# CHECK-OBJ:    Name: .data (66)
 # CHECK-OBJ:    SectionData (
 # CHECK-OBJ:      0000: DEADC0DE DEADC0DE DEADBEEF 00000000
 # CHECK-OBJ:      0010: 00000000 00000000
@@ -20,7 +20,7 @@
 # CHECK-OBJ:  }
 
 # CHECK-OBJ:  Section {
-# CHECK-OBJ:    Name: .rel.data (47)
+# CHECK-OBJ:    Name: .rel.data (62)
 # CHECK-OBJ:    Relocations [
 # CHECK-OBJ:      0xC R_MIPS_32 .data 0x0
 # CHECK-OBJ:      0x10 R_MIPS_64 .data 0x0
diff --git a/test/MC/Mips/mips32/abiflags.s b/test/MC/Mips/mips32/abiflags.s
new file mode 100644 (file)
index 0000000..896dd84
--- /dev/null
@@ -0,0 +1,37 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -filetype=obj -o - | \
+# RUN:   llvm-readobj -sections -section-data -section-relocations - | \
+# RUN:     FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module fp=32
+
+# Checking if the Mips.abiflags were correctly emitted.
+# CHECK-OBJ:  Section {
+# CHECK-OBJ:    Index: 5
+# CHECK-OBJ:    Name: .MIPS.abiflags (12)
+# CHECK-OBJ:    Type:  (0x7000002A)
+# CHECK-OBJ:     Flags [ (0x2)
+# CHECK-OBJ:      SHF_ALLOC (0x2)
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    Address: 0x0
+# CHECK-OBJ:    Offset: 0x50
+# CHECK-OBJ:    Size: 24
+# CHECK-OBJ:    Link: 0
+# CHECK-OBJ:    Info: 0
+# CHECK-OBJ:    AddressAlignment: 8
+# CHECK-OBJ:    EntrySize: 0
+# CHECK-OBJ:    Relocations [
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    SectionData (
+# CHECK-OBJ:      0000: 00002001 01010001 00000000 00000000  |.. .............|
+# CHECK-OBJ:      0010: 00000000 00000000                    |........|
+# CHECK-OBJ:    )
+# CHECK-OBJ:  }
+
+        .module fp=32
+
+# FIXME: Test should include gnu_attributes directive when implemented.
+#        An explicit .gnu_attribute must be checked against the effective
+#        command line options and any inconsistencies reported via a warning.
diff --git a/test/MC/Mips/mips32r2/abiflags.s b/test/MC/Mips/mips32r2/abiflags.s
new file mode 100644 (file)
index 0000000..41a809a
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -filetype=obj -o - | \
+# RUN:   llvm-readobj -sections -section-data -section-relocations - | \
+# RUN:     FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module fp=32
+# CHECK-ASM: .set fp=64
+
+# Checking if the Mips.abiflags were correctly emitted.
+# CHECK-OBJ:  Section {
+# CHECK-OBJ:    Index: 5
+# CHECK-OBJ:    Name: .MIPS.abiflags (12)
+# CHECK-OBJ:    Type:  (0x7000002A)
+# CHECK-OBJ:     Flags [ (0x2)
+# CHECK-OBJ:      SHF_ALLOC (0x2)
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    Address: 0x0
+# CHECK-OBJ:    Offset: 0x50
+# CHECK-OBJ:    Size: 24
+# CHECK-OBJ:    Link: 0
+# CHECK-OBJ:    Info: 0
+# CHECK-OBJ:    AddressAlignment: 8
+# CHECK-OBJ:    EntrySize: 0
+# CHECK-OBJ:    Relocations [
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    SectionData (
+# CHECK-OBJ:      0000: 00002002 01010001 00000000 00000000  |.. .............|
+# CHECK-OBJ:      0010: 00000000 00000000                    |........|
+# CHECK-OBJ:    )
+# CHECK-OBJ:  }
+
+        .module fp=32
+        .set fp=64
+# FIXME: Test should include gnu_attributes directive when implemented.
+#        An explicit .gnu_attribute must be checked against the effective
+#        command line options and any inconsistencies reported via a warning.
diff --git a/test/MC/Mips/mips64/abiflags.s b/test/MC/Mips/mips64/abiflags.s
new file mode 100644 (file)
index 0000000..557e32a
--- /dev/null
@@ -0,0 +1,37 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips64 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -filetype=obj -o - | \
+# RUN:   llvm-readobj -sections -section-data -section-relocations - | \
+# RUN:     FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module fp=64
+
+# Checking if the Mips.abiflags were correctly emitted.
+# CHECK-OBJ:  Section {
+# CHECK-OBJ:    Index: 5
+# CHECK-OBJ:    Name: .MIPS.abiflags (12)
+# CHECK-OBJ:    Type:  (0x7000002A)
+# CHECK-OBJ:     Flags [ (0x2)
+# CHECK-OBJ:      SHF_ALLOC (0x2)
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    Address: 0x0
+# CHECK-OBJ:    Offset: 0x50
+# CHECK-OBJ:    Size: 24
+# CHECK-OBJ:    Link: 0
+# CHECK-OBJ:    Info: 0
+# CHECK-OBJ:    AddressAlignment: 8
+# CHECK-OBJ:    EntrySize: 0
+# CHECK-OBJ:    Relocations [
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    SectionData (
+# CHECK-OBJ:      0000: 00004001 02020001 00000000 00000000  |..@.............|
+# CHECK-OBJ:      0010: 00000000 00000000                    |........|
+# CHECK-OBJ:    )
+# CHECK-OBJ:  }
+
+        .module fp=64
+
+# FIXME: Test should include gnu_attributes directive when implemented.
+#        An explicit .gnu_attribute must be checked against the effective
+#        command line options and any inconsistencies reported via a warning.
diff --git a/test/MC/Mips/mips64r2/abi-bad.s b/test/MC/Mips/mips64r2/abi-bad.s
new file mode 100644 (file)
index 0000000..31d13ab
--- /dev/null
@@ -0,0 +1,9 @@
+# RUN: not llvm-mc %s -triple mips-unknown-unknown -mcpu=mips64r2 2>&1 | FileCheck %s
+# CHECK: .text
+
+
+
+        .set fp=xx
+# CHECK     : error: 'set fp=xx'option requires O32 ABI
+# CHECK     : .set fp=xx
+# CHECK     :          ^
diff --git a/test/MC/Mips/mips64r2/abiflags.s b/test/MC/Mips/mips64r2/abiflags.s
new file mode 100644 (file)
index 0000000..aa76dee
--- /dev/null
@@ -0,0 +1,37 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips64r2 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips64r2 -filetype=obj -o - | \
+# RUN:   llvm-readobj -sections -section-data -section-relocations - | \
+# RUN:     FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module fp=64
+
+# Checking if the Mips.abiflags were correctly emitted.
+# CHECK-OBJ:  Section {
+# CHECK-OBJ:    Index: 5
+# CHECK-OBJ:    Name: .MIPS.abiflags (12)
+# CHECK-OBJ:    Type:  (0x7000002A)
+# CHECK-OBJ:     Flags [ (0x2)
+# CHECK-OBJ:      SHF_ALLOC (0x2)
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    Address: 0x0
+# CHECK-OBJ:    Offset: 0x50
+# CHECK-OBJ:    Size: 24
+# CHECK-OBJ:    Link: 0
+# CHECK-OBJ:    Info: 0
+# CHECK-OBJ:    AddressAlignment: 8
+# CHECK-OBJ:    EntrySize: 0
+# CHECK-OBJ:    Relocations [
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    SectionData (
+# CHECK-OBJ:      0000: 00004002 02020001 00000000 00000000  |..@.............|
+# CHECK-OBJ:      0010: 00000000 00000000                    |........|
+# CHECK-OBJ:    )
+# CHECK-OBJ:  }
+
+        .module fp=64
+
+# FIXME: Test should include gnu_attributes directive when implemented.
+#        An explicit .gnu_attribute must be checked against the effective
+#        command line options and any inconsistencies reported via a warning.
diff --git a/test/MC/Mips/mips_abi_flags_xx.s b/test/MC/Mips/mips_abi_flags_xx.s
new file mode 100644 (file)
index 0000000..1d65e99
--- /dev/null
@@ -0,0 +1,37 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -filetype=obj -o - | \
+# RUN:   llvm-readobj -sections -section-data -section-relocations - | \
+# RUN:     FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module fp=xx
+
+# Checking if the Mips.abiflags were correctly emitted.
+# CHECK-OBJ:  Section {
+# CHECK-OBJ:    Index: 5
+# CHECK-OBJ:    Name: .MIPS.abiflags (12)
+# CHECK-OBJ:    Type:  (0x7000002A)
+# CHECK-OBJ:     Flags [ (0x2)
+# CHECK-OBJ:      SHF_ALLOC (0x2)
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    Address: 0x0
+# CHECK-OBJ:    Offset: 0x50
+# CHECK-OBJ:    Size: 24
+# CHECK-OBJ:    Link: 0
+# CHECK-OBJ:    Info: 0
+# CHECK-OBJ:    AddressAlignment: 8
+# CHECK-OBJ:    EntrySize: 0
+# CHECK-OBJ:    Relocations [
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    SectionData (
+# CHECK-OBJ:      0000: 00002001 01010005 00000000 00000000  |.. .............|
+# CHECK-OBJ:      0010: 00000000 00000000                    |........|
+# CHECK-OBJ:    )
+# CHECK-OBJ:  }
+
+        .module fp=xx
+
+# FIXME: Test should include gnu_attributes directive when implemented.
+#        An explicit .gnu_attribute must be checked against the effective
+#        command line options and any inconsistencies reported via a warning.
diff --git a/test/MC/Mips/mips_abi_flags_xx_set.s b/test/MC/Mips/mips_abi_flags_xx_set.s
new file mode 100644 (file)
index 0000000..56f19d3
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -filetype=obj -o - | \
+# RUN:   llvm-readobj -sections -section-data -section-relocations - | \
+# RUN:     FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module fp=xx
+# CHECK-ASM: .set    fp=64
+
+# Checking if the Mips.abiflags were correctly emitted.
+# CHECK-OBJ:  Section {
+# CHECK-OBJ:    Index: 5
+# CHECK-OBJ:    Name: .MIPS.abiflags (12)
+# CHECK-OBJ:    Type:  (0x7000002A)
+# CHECK-OBJ:     Flags [ (0x2)
+# CHECK-OBJ:      SHF_ALLOC (0x2)
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    Address: 0x0
+# CHECK-OBJ:    Offset: 0x50
+# CHECK-OBJ:    Size: 24
+# CHECK-OBJ:    Link: 0
+# CHECK-OBJ:    Info: 0
+# CHECK-OBJ:    AddressAlignment: 8
+# CHECK-OBJ:    EntrySize: 0
+# CHECK-OBJ:    Relocations [
+# CHECK-OBJ:    ]
+# CHECK-OBJ:    SectionData (
+# CHECK-OBJ:      0000: 00002001 01010005 00000000 00000000  |.. .............|
+# CHECK-OBJ:      0010: 00000000 00000000                    |........|
+# CHECK-OBJ:    )
+# CHECK-OBJ:  }
+
+        .module fp=xx
+        .set    fp=64
+# FIXME: Test should include gnu_attributes directive when implemented.
+#        An explicit .gnu_attribute must be checked against the effective
+#        command line options and any inconsistencies reported via a warning.