summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
diff options
context:
space:
mode:
authorVladimir Medic <Vladimir.Medic@imgtec.com>2014-07-08 08:59:22 +0000
committerVladimir Medic <Vladimir.Medic@imgtec.com>2014-07-08 08:59:22 +0000
commitfb8a2a95cd5af1e0202513a559568df8d2882a16 (patch)
tree3fc626daa0ab3eba67eedfb47baae3165416f0a2 /llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
parentcc02abbb20df1b12ebe5609b9575e9f62b27baf9 (diff)
downloadbcm5719-llvm-fb8a2a95cd5af1e0202513a559568df8d2882a16.tar.gz
bcm5719-llvm-fb8a2a95cd5af1e0202513a559568df8d2882a16.zip
Mips.abiflags is a new implicitly generated section that will be present on all new modules. The section contains a versioned data structure which represents essentially information to allow a program loader to determine the requirements of the application. This patch implements mips.abiflags section and provides test cases for it.
llvm-svn: 212519
Diffstat (limited to 'llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp233
1 files changed, 189 insertions, 44 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index dc9ed2feeb9..4a0059d55a3 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -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;
}
OpenPOWER on IntegriCloud