#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"
const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr);
bool isEvaluated(const MCExpr *Expr);
+ bool parseSetFeature(uint64_t Feature);
bool parseDirectiveSet();
bool parseDirectiveOption();
bool parseSetNoMacroDirective();
bool parseSetReorderDirective();
bool parseSetNoReorderDirective();
- bool parseSetMips16Directive();
bool parseSetNoMips16Directive();
bool parseSetAssignment();
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 {
int getATReg();
+ // Warn if RegNo is the current assembler temporary.
+ void warnIfAssemblerTemporary(int RegNo);
+
bool processInstruction(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
// 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)
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; }
bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+
Inst.setLoc(IDLoc);
if (MCID.isBranch() || MCID.isCall()) {
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;
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;
}
}
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)
.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)
.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;
}
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);
getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs())
return -1;
+ if (RegClass == Mips::GPR32RegClassID || RegClass == Mips::GPR64RegClassID)
+ warnIfAssemblerTemporary(RegNum);
+
return getReg(RegClass, RegNum);
}
return false;
}
- if (AtRegNo < 1 || AtRegNo > 31) {
+ if (AtRegNo < 0 || AtRegNo > 31) {
reportParseError("unexpected token in statement");
return false;
}
return false;
}
Options.setReorder();
+ getTargetStreamer().emitDirectiveSetReorder();
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
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.
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.
} 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") {
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();
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();