aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r--lib/Target/Mips/AsmParser/MipsAsmParser.cpp208
1 files changed, 84 insertions, 124 deletions
diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index ce7db657f5e9..d2fed6861477 100644
--- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -39,6 +39,7 @@
#include "llvm/MC/MCValue.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@@ -64,6 +65,11 @@ class MCInstrInfo;
} // end namespace llvm
+static cl::opt<bool>
+EmitJalrReloc("mips-jalr-reloc", cl::Hidden,
+ cl::desc("MIPS: Emit R_{MICRO}MIPS_JALR relocation with jalr"),
+ cl::init(true));
+
namespace {
class MipsAssemblerOptions {
@@ -195,7 +201,6 @@ class MipsAsmParser : public MCTargetAsmParser {
OperandMatchResultTy parseImm(OperandVector &Operands);
OperandMatchResultTy parseJumpTarget(OperandVector &Operands);
OperandMatchResultTy parseInvNum(OperandVector &Operands);
- OperandMatchResultTy parseMovePRegPair(OperandVector &Operands);
OperandMatchResultTy parseRegisterList(OperandVector &Operands);
bool searchSymbolAlias(OperandVector &Operands);
@@ -760,7 +765,6 @@ private:
k_RegisterIndex, /// A register index in one or more RegKind.
k_Token, /// A simple token
k_RegList, /// A physical register list
- k_RegPair /// A pair of physical register
} Kind;
public:
@@ -769,16 +773,15 @@ public:
~MipsOperand() override {
switch (Kind) {
- case k_Immediate:
- break;
case k_Memory:
delete Mem.Base;
break;
case k_RegList:
delete RegList.List;
+ break;
+ case k_Immediate:
case k_RegisterIndex:
case k_Token:
- case k_RegPair:
break;
}
}
@@ -1038,6 +1041,17 @@ public:
Inst.addOperand(MCOperand::createReg(getGPRMM16Reg()));
}
+ void addGPRMM16AsmRegMovePPairFirstOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getGPRMM16Reg()));
+ }
+
+ void addGPRMM16AsmRegMovePPairSecondOperands(MCInst &Inst,
+ unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getGPRMM16Reg()));
+ }
+
/// Render the operand to an MCInst as a GPR64
/// Asserts if the wrong number of operands are requested, or the operand
/// is not a k_RegisterIndex compatible with RegKind_GPR
@@ -1217,29 +1231,6 @@ public:
Inst.addOperand(MCOperand::createReg(RegNo));
}
- void addRegPairOperands(MCInst &Inst, unsigned N) const {
- assert(N == 2 && "Invalid number of operands!");
- assert((RegIdx.Kind & RegKind_GPR) && "Invalid access!");
- unsigned RegNo = getRegPair();
- AsmParser.warnIfRegIndexIsAT(RegNo, StartLoc);
- Inst.addOperand(MCOperand::createReg(
- RegIdx.RegInfo->getRegClass(
- AsmParser.getABI().AreGprs64bit()
- ? Mips::GPR64RegClassID
- : Mips::GPR32RegClassID).getRegister(RegNo++)));
- Inst.addOperand(MCOperand::createReg(
- RegIdx.RegInfo->getRegClass(
- AsmParser.getABI().AreGprs64bit()
- ? Mips::GPR64RegClassID
- : Mips::GPR32RegClassID).getRegister(RegNo)));
- }
-
- void addMovePRegPairOperands(MCInst &Inst, unsigned N) const {
- assert(N == 2 && "Invalid number of operands!");
- for (auto RegNo : getRegList())
- Inst.addOperand(MCOperand::createReg(RegNo));
- }
-
bool isReg() const override {
// As a special case until we sort out the definition of div/divu, accept
// $0/$zero here so that MCK_ZERO works correctly.
@@ -1406,34 +1397,6 @@ public:
bool isRegList() const { return Kind == k_RegList; }
- bool isMovePRegPair() const {
- if (Kind != k_RegList || RegList.List->size() != 2)
- return false;
-
- unsigned R0 = RegList.List->front();
- unsigned R1 = RegList.List->back();
-
- if ((R0 == Mips::A1 && R1 == Mips::A2) ||
- (R0 == Mips::A1 && R1 == Mips::A3) ||
- (R0 == Mips::A2 && R1 == Mips::A3) ||
- (R0 == Mips::A0 && R1 == Mips::S5) ||
- (R0 == Mips::A0 && R1 == Mips::S6) ||
- (R0 == Mips::A0 && R1 == Mips::A1) ||
- (R0 == Mips::A0 && R1 == Mips::A2) ||
- (R0 == Mips::A0 && R1 == Mips::A3) ||
- (R0 == Mips::A1_64 && R1 == Mips::A2_64) ||
- (R0 == Mips::A1_64 && R1 == Mips::A3_64) ||
- (R0 == Mips::A2_64 && R1 == Mips::A3_64) ||
- (R0 == Mips::A0_64 && R1 == Mips::S5_64) ||
- (R0 == Mips::A0_64 && R1 == Mips::S6_64) ||
- (R0 == Mips::A0_64 && R1 == Mips::A1_64) ||
- (R0 == Mips::A0_64 && R1 == Mips::A2_64) ||
- (R0 == Mips::A0_64 && R1 == Mips::A3_64))
- return true;
-
- return false;
- }
-
StringRef getToken() const {
assert(Kind == k_Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
@@ -1481,11 +1444,6 @@ public:
return *(RegList.List);
}
- unsigned getRegPair() const {
- assert((Kind == k_RegPair) && "Invalid access!");
- return RegIdx.Index;
- }
-
static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S,
MipsAsmParser &Parser) {
auto Op = llvm::make_unique<MipsOperand>(k_Token, Parser);
@@ -1593,18 +1551,6 @@ public:
return Op;
}
- static std::unique_ptr<MipsOperand> CreateRegPair(const MipsOperand &MOP,
- SMLoc S, SMLoc E,
- MipsAsmParser &Parser) {
- auto Op = llvm::make_unique<MipsOperand>(k_RegPair, Parser);
- Op->RegIdx.Index = MOP.RegIdx.Index;
- Op->RegIdx.RegInfo = MOP.RegIdx.RegInfo;
- Op->RegIdx.Kind = MOP.RegIdx.Kind;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
bool isGPRZeroAsmReg() const {
return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index == 0;
}
@@ -1640,6 +1586,19 @@ public:
(RegIdx.Index >= 16 && RegIdx.Index <= 20));
}
+ bool isMM16AsmRegMovePPairFirst() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return RegIdx.Index >= 4 && RegIdx.Index <= 6;
+ }
+
+ bool isMM16AsmRegMovePPairSecond() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return (RegIdx.Index == 21 || RegIdx.Index == 22 ||
+ (RegIdx.Index >= 5 && RegIdx.Index <= 7));
+ }
+
bool isFGRAsmReg() const {
// AFGR64 is $0-$15 but we handle this in getAFGR64()
return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31;
@@ -1720,9 +1679,6 @@ public:
OS << Reg << " ";
OS << ">";
break;
- case k_RegPair:
- OS << "RegPair<" << RegIdx.Index << "," << RegIdx.Index + 1 << ">";
- break;
}
}
@@ -1755,14 +1711,23 @@ static const MCInstrDesc &getInstDesc(unsigned Opcode) {
return MipsInsts[Opcode];
}
-static bool hasShortDelaySlot(unsigned Opcode) {
- switch (Opcode) {
+static bool hasShortDelaySlot(MCInst &Inst) {
+ switch (Inst.getOpcode()) {
+ case Mips::BEQ_MM:
+ case Mips::BNE_MM:
+ case Mips::BLTZ_MM:
+ case Mips::BGEZ_MM:
+ case Mips::BLEZ_MM:
+ case Mips::BGTZ_MM:
+ case Mips::JRC16_MM:
case Mips::JALS_MM:
case Mips::JALRS_MM:
case Mips::JALRS16_MM:
case Mips::BGEZALS_MM:
case Mips::BLTZALS_MM:
return true;
+ case Mips::J_MM:
+ return !Inst.getOperand(0).isReg();
default:
return false;
}
@@ -2115,9 +2080,21 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
JalrInst.addOperand(MCOperand::createReg(Mips::RA));
JalrInst.addOperand(MCOperand::createReg(Mips::T9));
- // FIXME: Add an R_(MICRO)MIPS_JALR relocation after the JALR.
- // This relocation is supposed to be an optimization hint for the linker
- // and is not necessary for correctness.
+ if (EmitJalrReloc) {
+ // As an optimization hint for the linker, before the JALR we add:
+ // .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
+ // tmplabel:
+ MCSymbol *TmpLabel = getContext().createTempSymbol();
+ const MCExpr *TmpExpr = MCSymbolRefExpr::create(TmpLabel, getContext());
+ const MCExpr *RelocJalrExpr =
+ MCSymbolRefExpr::create(JalSym, MCSymbolRefExpr::VK_None,
+ getContext(), IDLoc);
+
+ TOut.getStreamer().EmitRelocDirective(*TmpExpr,
+ inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
+ RelocJalrExpr, IDLoc, *STI);
+ TOut.getStreamer().EmitLabel(TmpLabel);
+ }
Inst = JalrInst;
ExpandedJalSym = true;
@@ -2288,6 +2265,22 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (Inst.getOperand(0).getReg() == Mips::RA)
return Error(IDLoc, "invalid operand for instruction");
break;
+ case Mips::MOVEP_MM:
+ case Mips::MOVEP_MMR6: {
+ unsigned R0 = Inst.getOperand(0).getReg();
+ unsigned R1 = Inst.getOperand(1).getReg();
+ bool RegPair = ((R0 == Mips::A1 && R1 == Mips::A2) ||
+ (R0 == Mips::A1 && R1 == Mips::A3) ||
+ (R0 == Mips::A2 && R1 == Mips::A3) ||
+ (R0 == Mips::A0 && R1 == Mips::S5) ||
+ (R0 == Mips::A0 && R1 == Mips::S6) ||
+ (R0 == Mips::A0 && R1 == Mips::A1) ||
+ (R0 == Mips::A0 && R1 == Mips::A2) ||
+ (R0 == Mips::A0 && R1 == Mips::A3));
+ if (!RegPair)
+ return Error(IDLoc, "invalid operand for instruction");
+ break;
+ }
}
}
@@ -2318,7 +2311,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// If this instruction has a delay slot and .set reorder is active,
// emit a NOP after it.
if (FillDelaySlot) {
- TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst.getOpcode()), IDLoc, STI);
+ TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, STI);
TOut.emitDirectiveSetReorder();
}
@@ -2330,7 +2323,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// If .set reorder has been used, we've already emitted a NOP.
// If .set noreorder has been used, we need to emit a NOP at this point.
if (!AssemblerOptions.back()->isReorder())
- TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst.getOpcode()), IDLoc,
+ TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc,
STI);
// Load the $gp from the stack.
@@ -2617,7 +2610,7 @@ bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc,
// emit a NOP after it.
const MCInstrDesc &MCID = getInstDesc(JalrInst.getOpcode());
if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder())
- TOut.emitEmptyDelaySlot(hasShortDelaySlot(JalrInst.getOpcode()), IDLoc,
+ TOut.emitEmptyDelaySlot(hasShortDelaySlot(JalrInst), IDLoc,
STI);
return false;
@@ -6278,45 +6271,6 @@ MipsAsmParser::parseRegisterList(OperandVector &Operands) {
return MatchOperand_Success;
}
-OperandMatchResultTy
-MipsAsmParser::parseMovePRegPair(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands;
- SmallVector<unsigned, 10> Regs;
-
- if (Parser.getTok().isNot(AsmToken::Dollar))
- return MatchOperand_ParseFail;
-
- SMLoc S = Parser.getTok().getLoc();
-
- if (parseAnyRegister(TmpOperands) != MatchOperand_Success)
- return MatchOperand_ParseFail;
-
- MipsOperand *Reg = &static_cast<MipsOperand &>(*TmpOperands.back());
- unsigned RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg();
- Regs.push_back(RegNo);
-
- SMLoc E = Parser.getTok().getLoc();
- if (Parser.getTok().isNot(AsmToken::Comma)) {
- Error(E, "',' expected");
- return MatchOperand_ParseFail;
- }
-
- // Remove comma.
- Parser.Lex();
-
- if (parseAnyRegister(TmpOperands) != MatchOperand_Success)
- return MatchOperand_ParseFail;
-
- Reg = &static_cast<MipsOperand &>(*TmpOperands.back());
- RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg();
- Regs.push_back(RegNo);
-
- Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this));
-
- return MatchOperand_Success;
-}
-
/// Sometimes (i.e. load/stores) the operand may be followed immediately by
/// either this.
/// ::= '(', register, ')'
@@ -6371,6 +6325,9 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name,
return false;
}
+static std::string MipsMnemonicSpellCheck(StringRef S, uint64_t FBS,
+ unsigned VariantID = 0);
+
bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) {
MCAsmParser &Parser = getParser();
@@ -6381,7 +6338,9 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Check if we have valid mnemonic
if (!mnemonicIsValid(Name, 0)) {
- return Error(NameLoc, "unknown instruction");
+ uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
+ std::string Suggestion = MipsMnemonicSpellCheck(Name, FBS);
+ return Error(NameLoc, "unknown instruction" + Suggestion);
}
// First operand in MCInst is instruction mnemonic.
Operands.push_back(MipsOperand::CreateToken(Name, NameLoc, *this));
@@ -8257,6 +8216,7 @@ extern "C" void LLVMInitializeMipsAsmParser() {
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
+#define GET_MNEMONIC_SPELL_CHECKER
#include "MipsGenAsmMatcher.inc"
bool MipsAsmParser::mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {