diff options
Diffstat (limited to 'lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r-- | lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 273 |
1 files changed, 145 insertions, 128 deletions
diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 911a119043..86fd386967 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -29,6 +29,8 @@ using namespace llvm; +#define DEBUG_TYPE "mips-asm-parser" + namespace llvm { class MCInstrInfo; } @@ -73,10 +75,10 @@ class MipsAsmParser : public MCTargetAsmParser { bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SmallVectorImpl<MCParsedAsmOperand *> &Operands, MCStreamer &Out, unsigned &ErrorInfo, - bool MatchingInlineAsm); + bool MatchingInlineAsm) override; /// Parse a register as used in CFI directives - bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; bool ParseParenSuffix(StringRef Name, SmallVectorImpl<MCParsedAsmOperand *> &Operands); @@ -84,11 +86,11 @@ class MipsAsmParser : public MCTargetAsmParser { bool ParseBracketSuffix(StringRef Name, SmallVectorImpl<MCParsedAsmOperand *> &Operands); - bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, - SMLoc NameLoc, - SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool + ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand *> &Operands) override; - bool ParseDirective(AsmToken DirectiveID); + bool ParseDirective(AsmToken DirectiveID) override; MipsAsmParser::OperandMatchResultTy parseMemOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands); @@ -135,6 +137,7 @@ class MipsAsmParser : public MCTargetAsmParser { SmallVectorImpl<MCInst> &Instructions, bool isLoad, bool isImmOpnd); bool reportParseError(StringRef ErrorMsg); + bool reportParseError(SMLoc Loc, StringRef ErrorMsg); bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); bool parseRelocOperand(const MCExpr *&Res); @@ -143,7 +146,9 @@ class MipsAsmParser : public MCTargetAsmParser { bool isEvaluated(const MCExpr *Expr); bool parseSetFeature(uint64_t Feature); + bool parseDirectiveCPLoad(SMLoc Loc); bool parseDirectiveCPSetup(); + bool parseDirectiveNaN(); bool parseDirectiveSet(); bool parseDirectiveOption(); @@ -212,21 +217,22 @@ class MipsAsmParser : public MCTargetAsmParser { void setFeatureBits(unsigned Feature, StringRef FeatureString) { if (!(STI.getFeatureBits() & Feature)) { - setAvailableFeatures(ComputeAvailableFeatures( - STI.ToggleFeature(FeatureString))); + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } } void clearFeatureBits(unsigned Feature, StringRef FeatureString) { if (STI.getFeatureBits() & Feature) { - setAvailableFeatures(ComputeAvailableFeatures( - STI.ToggleFeature(FeatureString))); + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } } public: MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, - const MCInstrInfo &MII) + const MCInstrInfo &MII, + const MCTargetOptions &Options) : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); @@ -266,11 +272,12 @@ public: /// context). RegKind_CCR = 128, /// CCR RegKind_HWRegs = 256, /// HWRegs + RegKind_COP3 = 512, /// COP3 /// Potentially any (e.g. $1) RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 | RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC | - RegKind_CCR | RegKind_HWRegs + RegKind_CCR | RegKind_HWRegs | RegKind_COP3 }; private: @@ -422,6 +429,14 @@ private: return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } + /// Coerce the register to COP3 and return the real register for the + /// current target. + unsigned getCOP3Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP3) && "Invalid access!"); + unsigned ClassID = Mips::COP3RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + /// Coerce the register to ACC64DSP and return the real register for the /// current target. unsigned getACC64DSPReg() const { @@ -465,7 +480,7 @@ private: public: void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediate when possible. Null MCExpr = 0. - if (Expr == 0) + if (!Expr) Inst.addOperand(MCOperand::CreateImm(0)); else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) Inst.addOperand(MCOperand::CreateImm(CE->getValue())); @@ -533,6 +548,11 @@ public: Inst.addOperand(MCOperand::CreateReg(getCOP2Reg())); } + void addCOP3AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCOP3Reg())); + } + void addACC64DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getACC64DSPReg())); @@ -573,7 +593,7 @@ public: addExpr(Inst, Expr); } - bool isReg() const { + bool isReg() const override { // As a special case until we sort out the definition of div/divu, pretend // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. if (isGPRAsmReg() && RegIdx.Index == 0) @@ -582,16 +602,16 @@ public: return Kind == k_PhysRegister; } bool isRegIdx() const { return Kind == k_RegisterIndex; } - bool isImm() const { return Kind == k_Immediate; } + bool isImm() const override { return Kind == k_Immediate; } bool isConstantImm() const { return isImm() && dyn_cast<MCConstantExpr>(getImm()); } - bool isToken() const { + bool isToken() const override { // Note: It's not possible to pretend that other operand kinds are tokens. // The matcher emitter checks tokens first. return Kind == k_Token; } - bool isMem() const { return Kind == k_Memory; } + bool isMem() const override { return Kind == k_Memory; } bool isInvNum() const { return Kind == k_Immediate; } bool isLSAImm() const { if (!isConstantImm()) @@ -605,7 +625,7 @@ public: return StringRef(Tok.Data, Tok.Length); } - unsigned getReg() const { + unsigned getReg() const override { // As a special case until we sort out the definition of div/divu, pretend // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. if (Kind == k_RegisterIndex && RegIdx.Index == 0 && @@ -744,6 +764,9 @@ public: bool isCOP2AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP2 && RegIdx.Index <= 31; } + bool isCOP3AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP3 && RegIdx.Index <= 31; + } bool isMSA128AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_MSA128 && RegIdx.Index <= 31; } @@ -752,11 +775,25 @@ public: } /// getStartLoc - Get the location of the first token of this operand. - SMLoc getStartLoc() const { return StartLoc; } + SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. - SMLoc getEndLoc() const { return EndLoc; } + SMLoc getEndLoc() const override { return EndLoc; } - virtual void print(raw_ostream &OS) const { + virtual ~MipsOperand() { + switch (Kind) { + case k_Immediate: + break; + case k_Memory: + delete Mem.Base; + break; + case k_PhysRegister: + case k_RegisterIndex: + case k_Token: + break; + } + } + + void print(raw_ostream &OS) const override { switch (Kind) { case k_Immediate: OS << "Imm<"; @@ -906,10 +943,6 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) { 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; @@ -925,30 +958,6 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, 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; } } @@ -1586,6 +1595,8 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, RegNo = isGP64() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); } + delete &Operand; + return (RegNo == (unsigned)-1); } @@ -1624,7 +1635,7 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( SmallVectorImpl<MCParsedAsmOperand *> &Operands) { DEBUG(dbgs() << "parseMemOperand\n"); - const MCExpr *IdVal = 0; + const MCExpr *IdVal = nullptr; SMLoc S; bool isParenExpr = false; MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; @@ -1654,6 +1665,7 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); // Zero register assumed, add a memory operand with ZERO as its base. + // "Base" will be managed by k_Memory. MipsOperand *Base = MipsOperand::CreateGPRReg( 0, getContext().getRegisterInfo(), S, E, *this); Operands.push_back(MipsOperand::CreateMem(Base, IdVal, S, E, *this)); @@ -1679,12 +1691,13 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( Parser.Lex(); // Eat the ')' token. - if (IdVal == 0) + if (!IdVal) IdVal = MCConstantExpr::Create(0, getContext()); // Replace the register operand with the memory operand. MipsOperand *op = static_cast<MipsOperand *>(Operands.back()); // Remove the register from the operands. + // "op" will be managed by k_Memory. Operands.pop_back(); // Add the memory operand. if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(IdVal)) { @@ -1969,9 +1982,11 @@ MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { .Case("call_lo", MCSymbolRefExpr::VK_Mips_CALL_LO16) .Case("higher", MCSymbolRefExpr::VK_Mips_HIGHER) .Case("highest", MCSymbolRefExpr::VK_Mips_HIGHEST) + .Case("pcrel_hi", MCSymbolRefExpr::VK_Mips_PCREL_HI16) + .Case("pcrel_lo", MCSymbolRefExpr::VK_Mips_PCREL_LO16) .Default(MCSymbolRefExpr::VK_None); - assert (VK != MCSymbolRefExpr::VK_None); + assert(VK != MCSymbolRefExpr::VK_None); return VK; } @@ -2089,6 +2104,10 @@ bool MipsAsmParser::reportParseError(StringRef ErrorMsg) { return Error(Loc, ErrorMsg); } +bool MipsAsmParser::reportParseError(SMLoc Loc, StringRef ErrorMsg) { + return Error(Loc, ErrorMsg); +} + bool MipsAsmParser::parseSetNoAtDirective() { // Line should look like: ".set noat". // set at reg to 0. @@ -2248,29 +2267,30 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) { 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(); + switch (Feature) { + default: + llvm_unreachable("Unimplemented feature"); + case Mips::FeatureDSP: + setFeatureBits(Mips::FeatureDSP, "dsp"); + getTargetStreamer().emitDirectiveSetDsp(); break; - case Mips::FeatureMicroMips: - getTargetStreamer().emitDirectiveSetMicroMips(); + case Mips::FeatureMicroMips: + getTargetStreamer().emitDirectiveSetMicroMips(); break; - case Mips::FeatureMips16: - getTargetStreamer().emitDirectiveSetMips16(); + case Mips::FeatureMips16: + getTargetStreamer().emitDirectiveSetMips16(); break; - case Mips::FeatureMips32r2: - setFeatureBits(Mips::FeatureMips32r2, "mips32r2"); - getTargetStreamer().emitDirectiveSetMips32R2(); + case Mips::FeatureMips32r2: + setFeatureBits(Mips::FeatureMips32r2, "mips32r2"); + getTargetStreamer().emitDirectiveSetMips32R2(); break; - case Mips::FeatureMips64: - setFeatureBits(Mips::FeatureMips64, "mips64"); - getTargetStreamer().emitDirectiveSetMips64(); + case Mips::FeatureMips64: + setFeatureBits(Mips::FeatureMips64, "mips64"); + getTargetStreamer().emitDirectiveSetMips64(); break; - case Mips::FeatureMips64r2: - setFeatureBits(Mips::FeatureMips64r2, "mips64r2"); - getTargetStreamer().emitDirectiveSetMips64R2(); + case Mips::FeatureMips64r2: + setFeatureBits(Mips::FeatureMips64r2, "mips64r2"); + getTargetStreamer().emitDirectiveSetMips64R2(); break; } return false; @@ -2302,10 +2322,34 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) { return Error(Loc, ErrorStr); } - Parser.Lex(); // Eat the comma. + Parser.Lex(); // Eat the comma. return true; } +bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { + if (Options.isReorder()) + Warning(Loc, ".cpload in reorder section"); + + // FIXME: Warn if cpload is used in Mips16 mode. + + SmallVector<MCParsedAsmOperand *, 1> Reg; + OperandMatchResultTy ResTy = ParseAnyRegister(Reg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected register containing function address"); + return false; + } + + MipsOperand *RegOpnd = static_cast<MipsOperand *>(Reg[0]); + if (!RegOpnd->isGPRAsmReg()) { + reportParseError(RegOpnd->getStartLoc(), "invalid register"); + return false; + } + + getTargetStreamer().emitDirectiveCpload(RegOpnd->getGPR32Reg()); + delete RegOpnd; + return false; +} + bool MipsAsmParser::parseDirectiveCPSetup() { unsigned FuncReg; unsigned Save; @@ -2336,60 +2380,28 @@ bool MipsAsmParser::parseDirectiveCPSetup() { if (Parser.parseIdentifier(Name)) reportParseError("expected identifier"); MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); - unsigned GPReg = getGPR(matchCPURegisterName("gp")); - // FIXME: The code below this point should be in the TargetStreamers. - // Only N32 and N64 emit anything for .cpsetup - // FIXME: We should only emit something for PIC mode too. - if (!isN32() && !isN64()) - return false; + getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, *Sym, SaveIsReg); + return false; +} - MCStreamer &TS = getStreamer(); - MCInst Inst; - // Either store the old $gp in a register or on the stack - if (SaveIsReg) { - // move $save, $gpreg - Inst.setOpcode(Mips::DADDu); - Inst.addOperand(MCOperand::CreateReg(Save)); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateReg(getGPR(0))); - } else { - // sd $gpreg, offset($sp) - Inst.setOpcode(Mips::SD); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateReg(getGPR(matchCPURegisterName("sp")))); - Inst.addOperand(MCOperand::CreateImm(Save)); - } - TS.EmitInstruction(Inst, STI); - Inst.clear(); - - const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( - Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, - getContext()); - const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( - Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, - getContext()); - // lui $gp, %hi(%neg(%gp_rel(funcSym))) - Inst.setOpcode(Mips::LUi); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateExpr(HiExpr)); - TS.EmitInstruction(Inst, STI); - Inst.clear(); - - // addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym))) - Inst.setOpcode(Mips::ADDiu); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateExpr(LoExpr)); - TS.EmitInstruction(Inst, STI); - Inst.clear(); - - // daddu $gp, $gp, $funcreg - Inst.setOpcode(Mips::DADDu); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateReg(GPReg)); - Inst.addOperand(MCOperand::CreateReg(FuncReg)); - TS.EmitInstruction(Inst, STI); +bool MipsAsmParser::parseDirectiveNaN() { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "2008") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaN2008(); + return false; + } else if (Tok.getString() == "legacy") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaNLegacy(); + return false; + } + } + // If we don't recognize the option passed to the .nan + // directive (e.g. no option or unknown option), emit an error. + reportParseError("invalid option in .nan directive"); return false; } @@ -2419,15 +2431,15 @@ bool MipsAsmParser::parseDirectiveSet() { Parser.eatToEndOfStatement(); return false; } else if (Tok.getString() == "micromips") { - return parseSetFeature(Mips::FeatureMicroMips); + return parseSetFeature(Mips::FeatureMicroMips); } else if (Tok.getString() == "mips32r2") { - return parseSetFeature(Mips::FeatureMips32r2); + return parseSetFeature(Mips::FeatureMips32r2); } else if (Tok.getString() == "mips64") { - return parseSetFeature(Mips::FeatureMips64); + return parseSetFeature(Mips::FeatureMips64); } else if (Tok.getString() == "mips64r2") { - return parseSetFeature(Mips::FeatureMips64r2); + return parseSetFeature(Mips::FeatureMips64r2); } else if (Tok.getString() == "dsp") { - return parseSetFeature(Mips::FeatureDSP); + return parseSetFeature(Mips::FeatureDSP); } else { // It is just an identifier, look for an assignment. parseSetAssignment(); @@ -2537,6 +2549,8 @@ bool MipsAsmParser::parseDirectiveOption() { bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); + if (IDVal == ".cpload") + return parseDirectiveCPLoad(DirectiveID.getLoc()); if (IDVal == ".dword") { parseDataDirective(8, DirectiveID.getLoc()); return false; @@ -2576,6 +2590,9 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } + if (IDVal == ".nan") + return parseDirectiveNaN(); + if (IDVal == ".gpword") { parseDirectiveGpWord(); return false; |