diff options
Diffstat (limited to 'llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp')
-rw-r--r-- | llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 584 |
1 files changed, 573 insertions, 11 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 53562f42a1847..407f980bd35e8 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -10,10 +10,13 @@ #include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "MCTargetDesc/RISCVTargetStreamer.h" +#include "RISCVInstrInfo.h" #include "TargetInfo/RISCVTargetInfo.h" #include "Utils/RISCVBaseInfo.h" #include "Utils/RISCVMatInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" @@ -32,6 +35,7 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Casting.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/RISCVAttributes.h" #include "llvm/Support/TargetRegistry.h" #include <limits> @@ -50,9 +54,16 @@ STATISTIC(RISCVNumInstrsCompressed, namespace { struct RISCVOperand; +struct ParserOptionsSet { + bool IsPicEnabled; +}; + class RISCVAsmParser : public MCTargetAsmParser { SmallVector<FeatureBitset, 4> FeatureBitStack; + SmallVector<ParserOptionsSet, 4> ParserOptionsStack; + ParserOptionsSet ParserOptions; + SMLoc getLoc() const { return getParser().getTok().getLoc(); } bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); } bool isRV32E() const { return getSTI().hasFeature(RISCV::FeatureRV32E); } @@ -74,6 +85,8 @@ class RISCVAsmParser : public MCTargetAsmParser { bool MatchingInlineAsm) override; bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; @@ -118,6 +131,9 @@ class RISCVAsmParser : public MCTargetAsmParser { // 'add' is an overloaded mnemonic. bool checkPseudoAddTPRel(MCInst &Inst, OperandVector &Operands); + // Check instruction constraints. + bool validateInstruction(MCInst &Inst, OperandVector &Operands); + /// Helper for processing MC instructions that have been successfully matched /// by MatchAndEmitInstruction. Modifications to the emitted instructions, /// like the expansion of pseudo instructions (e.g., "li"), can be performed @@ -138,11 +154,15 @@ class RISCVAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); OperandMatchResultTy parseBareSymbol(OperandVector &Operands); OperandMatchResultTy parseCallSymbol(OperandVector &Operands); + OperandMatchResultTy parsePseudoJumpSymbol(OperandVector &Operands); OperandMatchResultTy parseJALOffset(OperandVector &Operands); + OperandMatchResultTy parseVTypeI(OperandVector &Operands); + OperandMatchResultTy parseMaskReg(OperandVector &Operands); bool parseOperand(OperandVector &Operands, StringRef Mnemonic); bool parseDirectiveOption(); + bool parseDirectiveAttribute(); void setFeatureBits(uint64_t Feature, StringRef FeatureString) { if (!(getSTI().getFeatureBits()[Feature])) { @@ -152,6 +172,10 @@ class RISCVAsmParser : public MCTargetAsmParser { } } + bool getFeatureBits(uint64_t Feature) { + return getSTI().getFeatureBits()[Feature]; + } + void clearFeatureBits(uint64_t Feature, StringRef FeatureString) { if (getSTI().getFeatureBits()[Feature]) { MCSubtargetInfo &STI = copySTI(); @@ -161,10 +185,15 @@ class RISCVAsmParser : public MCTargetAsmParser { } void pushFeatureBits() { + assert(FeatureBitStack.size() == ParserOptionsStack.size() && + "These two stacks must be kept synchronized"); FeatureBitStack.push_back(getSTI().getFeatureBits()); + ParserOptionsStack.push_back(ParserOptions); } bool popFeatureBits() { + assert(FeatureBitStack.size() == ParserOptionsStack.size() && + "These two stacks must be kept synchronized"); if (FeatureBitStack.empty()) return true; @@ -172,8 +201,13 @@ class RISCVAsmParser : public MCTargetAsmParser { copySTI().setFeatureBits(FeatureBits); setAvailableFeatures(ComputeAvailableFeatures(FeatureBits)); + ParserOptions = ParserOptionsStack.pop_back_val(); + return false; } + + std::unique_ptr<RISCVOperand> defaultMaskRegOp() const; + public: enum RISCVMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, @@ -195,17 +229,21 @@ public: Parser.addAliasForDirective(".dword", ".8byte"); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); - if (Options.ABIName.back() == 'f' && + auto ABIName = StringRef(Options.ABIName); + if (ABIName.endswith("f") && !getSTI().getFeatureBits()[RISCV::FeatureStdExtF]) { errs() << "Hard-float 'f' ABI can't be used for a target that " "doesn't support the F instruction set extension (ignoring " "target-abi)\n"; - } else if (Options.ABIName.back() == 'd' && + } else if (ABIName.endswith("d") && !getSTI().getFeatureBits()[RISCV::FeatureStdExtD]) { errs() << "Hard-float 'd' ABI can't be used for a target that " "doesn't support the D instruction set extension (ignoring " "target-abi)\n"; } + + const MCObjectFileInfo *MOFI = Parser.getContext().getObjectFileInfo(); + ParserOptions.IsPicEnabled = MOFI->isPositionIndependent(); } }; @@ -217,7 +255,8 @@ struct RISCVOperand : public MCParsedAsmOperand { Token, Register, Immediate, - SystemRegister + SystemRegister, + VType, } Kind; bool IsRV64; @@ -238,12 +277,32 @@ struct RISCVOperand : public MCParsedAsmOperand { // e.g.: read/write or user/supervisor/machine privileges. }; + enum class VSEW { + SEW_8 = 0, + SEW_16, + SEW_32, + SEW_64, + SEW_128, + SEW_256, + SEW_512, + SEW_1024, + }; + + enum class VLMUL { LMUL_1 = 0, LMUL_2, LMUL_4, LMUL_8 }; + + struct VTypeOp { + VSEW Sew; + VLMUL Lmul; + unsigned Encoding; + }; + SMLoc StartLoc, EndLoc; union { StringRef Tok; RegOp Reg; ImmOp Imm; struct SysRegOp SysReg; + struct VTypeOp VType; }; RISCVOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} @@ -267,14 +326,21 @@ public: case KindTy::SystemRegister: SysReg = o.SysReg; break; + case KindTy::VType: + VType = o.VType; + break; } } bool isToken() const override { return Kind == KindTy::Token; } bool isReg() const override { return Kind == KindTy::Register; } + bool isV0Reg() const { + return Kind == KindTy::Register && Reg.RegNum == RISCV::V0; + } bool isImm() const override { return Kind == KindTy::Immediate; } bool isMem() const override { return false; } bool isSystemRegister() const { return Kind == KindTy::SystemRegister; } + bool isVType() const { return Kind == KindTy::VType; } bool isGPR() const { return Kind == KindTy::Register && @@ -336,6 +402,16 @@ public: VK == RISCVMCExpr::VK_RISCV_CALL_PLT); } + bool isPseudoJumpSymbol() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + // Must be of 'immediate' type but not a constant. + if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) + return false; + return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) && + VK == RISCVMCExpr::VK_RISCV_CALL; + } + bool isTPRelAddSymbol() const { int64_t Imm; RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; @@ -348,6 +424,8 @@ public: bool isCSRSystemRegister() const { return isSystemRegister(); } + bool isVTypeI() const { return isVType(); } + /// Return true if the operand is a valid for the fence instruction e.g. /// ('iorw'). bool isFenceArg() const { @@ -425,6 +503,17 @@ public: return (isRV64() && isUInt<6>(Imm)) || isUInt<5>(Imm); } + bool isUImmLog2XLenHalf() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + if (!isImm()) + return false; + if (!evaluateConstantImm(getImm(), Imm, VK) || + VK != RISCVMCExpr::VK_RISCV_None) + return false; + return (isRV64() && isUInt<5>(Imm)) || isUInt<4>(Imm); + } + bool isUImm5() const { int64_t Imm; RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; @@ -444,6 +533,15 @@ public: VK == RISCVMCExpr::VK_RISCV_None; } + bool isSImm5() const { + if (!isImm()) + return false; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + int64_t Imm; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && isInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; + } + bool isSImm6() const { if (!isImm()) return false; @@ -451,7 +549,7 @@ public: int64_t Imm; bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); return IsConstantImm && isInt<6>(Imm) && - VK == RISCVMCExpr::VK_RISCV_None; + VK == RISCVMCExpr::VK_RISCV_None; } bool isSImm6NonZero() const { @@ -609,6 +707,16 @@ public: return IsConstantImm && (Imm == 0) && VK == RISCVMCExpr::VK_RISCV_None; } + bool isSImm5Plus1() const { + if (!isImm()) + return false; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + int64_t Imm; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && isInt<5>(Imm - 1) && + VK == RISCVMCExpr::VK_RISCV_None; + } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -636,6 +744,51 @@ public: return Tok; } + static StringRef getSEWStr(VSEW Sew) { + switch (Sew) { + case VSEW::SEW_8: + return "e8"; + case VSEW::SEW_16: + return "e16"; + case VSEW::SEW_32: + return "e32"; + case VSEW::SEW_64: + return "e64"; + case VSEW::SEW_128: + return "e128"; + case VSEW::SEW_256: + return "e256"; + case VSEW::SEW_512: + return "e512"; + case VSEW::SEW_1024: + return "e1024"; + } + return ""; + } + + static StringRef getLMULStr(VLMUL Lmul) { + switch (Lmul) { + case VLMUL::LMUL_1: + return "m1"; + case VLMUL::LMUL_2: + return "m2"; + case VLMUL::LMUL_4: + return "m4"; + case VLMUL::LMUL_8: + return "m8"; + } + return ""; + } + + StringRef getVType(SmallString<32> &Buf) const { + assert(Kind == KindTy::VType && "Invalid access!"); + Buf.append(getSEWStr(VType.Sew)); + Buf.append(","); + Buf.append(getLMULStr(VType.Lmul)); + + return Buf.str(); + } + void print(raw_ostream &OS) const override { switch (Kind) { case KindTy::Immediate: @@ -651,6 +804,10 @@ public: case KindTy::SystemRegister: OS << "<sysreg: " << getSysReg() << '>'; break; + case KindTy::VType: + SmallString<32> VTypeBuf; + OS << "<vtype: " << getVType(VTypeBuf) << '>'; + break; } } @@ -695,6 +852,20 @@ public: return Op; } + static std::unique_ptr<RISCVOperand> createVType(APInt Sew, APInt Lmul, + SMLoc S, bool IsRV64) { + auto Op = std::make_unique<RISCVOperand>(KindTy::VType); + Sew.ashrInPlace(3); + unsigned SewLog2 = Sew.logBase2(); + unsigned LmulLog2 = Lmul.logBase2(); + Op->VType.Sew = static_cast<VSEW>(SewLog2); + Op->VType.Lmul = static_cast<VLMUL>(LmulLog2); + Op->VType.Encoding = (SewLog2 << 2) | LmulLog2; + Op->StartLoc = S; + Op->IsRV64 = IsRV64; + return Op; + } + void addExpr(MCInst &Inst, const MCExpr *Expr) const { assert(Expr && "Expr shouldn't be null!"); int64_t Imm = 0; @@ -718,6 +889,16 @@ public: addExpr(Inst, getImm()); } + void addSImm5Plus1Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + int64_t Imm = 0; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + bool IsConstant = evaluateConstantImm(getImm(), Imm, VK); + assert(IsConstant && "Expect constant value!"); + (void)IsConstant; + Inst.addOperand(MCOperand::createImm(Imm - 1)); + } + void addFenceArgOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // isFenceArg has validated the operand, meaning this cast is safe @@ -742,6 +923,11 @@ public: Inst.addOperand(MCOperand::createImm(SysReg.Encoding)); } + void addVTypeIOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(VType.Encoding)); + } + // Returns the rounding mode represented by this RISCVOperand. Should only // be called after checking isFRMArg. RISCVFPRndMode::RoundingMode getRoundingMode() const { @@ -819,6 +1005,8 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, default: break; case Match_Success: + if (validateInstruction(Inst, Operands)) + return true; return processInstruction(Inst, IDLoc, Operands, Out); case Match_MissingFeature: { assert(MissingFeatures.any() && "Unknown missing features!"); @@ -885,6 +1073,10 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, if (isRV64()) return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6) - 1); return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 5) - 1); + case Match_InvalidUImmLog2XLenHalf: + if (isRV64()) + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 4) - 1); case Match_InvalidUImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); case Match_InvalidSImm6: @@ -975,6 +1167,10 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a bare symbol name"); } + case Match_InvalidPseudoJumpSymbol: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "operand must be a valid jump target"); + } case Match_InvalidCallSymbol: { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a bare symbol name"); @@ -983,6 +1179,20 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a symbol with %tprel_add modifier"); } + case Match_InvalidVTypeI: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, + "operand must be e[8|16|32|64|128|256|512|1024],m[1|2|4|8]"); + } + case Match_InvalidVMaskRegister: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "operand must be v0.t"); + } + case Match_InvalidSImm5Plus1: { + return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 4) + 1, + (1 << 4), + "immediate must be in the range"); + } } llvm_unreachable("Unknown match type detected!"); @@ -1009,17 +1219,25 @@ static bool matchRegisterNameHelper(bool IsRV32E, Register &RegNo, bool RISCVAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { + if (tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success) + return Error(StartLoc, "invalid register name"); + return false; +} + +OperandMatchResultTy RISCVAsmParser::tryParseRegister(unsigned &RegNo, + SMLoc &StartLoc, + SMLoc &EndLoc) { const AsmToken &Tok = getParser().getTok(); StartLoc = Tok.getLoc(); EndLoc = Tok.getEndLoc(); RegNo = 0; StringRef Name = getLexer().getTok().getIdentifier(); - if (matchRegisterNameHelper(isRV32E(), (Register&)RegNo, Name)) - return Error(StartLoc, "invalid register name"); + if (matchRegisterNameHelper(isRV32E(), (Register &)RegNo, Name)) + return MatchOperand_NoMatch; getParser().Lex(); // Eat identifier token. - return false; + return MatchOperand_Success; } OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands, @@ -1112,6 +1330,8 @@ RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) { return MatchOperand_ParseFail; auto SysReg = RISCVSysReg::lookupSysRegByName(Identifier); + if (!SysReg) + SysReg = RISCVSysReg::lookupSysRegByAltName(Identifier); // Accept a named Sys Reg if the required features are present. if (SysReg) { if (!SysReg->haveRequiredFeatures(getSTI().getFeatureBits())) { @@ -1286,6 +1506,27 @@ OperandMatchResultTy RISCVAsmParser::parseCallSymbol(OperandVector &Operands) { return MatchOperand_Success; } +OperandMatchResultTy +RISCVAsmParser::parsePseudoJumpSymbol(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; + + if (getParser().parseExpression(Res)) + return MatchOperand_ParseFail; + + if (Res->getKind() != MCExpr::ExprKind::SymbolRef || + cast<MCSymbolRefExpr>(Res)->getKind() == + MCSymbolRefExpr::VariantKind::VK_PLT) { + Error(S, "operand must be a valid jump target"); + return MatchOperand_ParseFail; + } + + Res = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, getContext()); + Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); + return MatchOperand_Success; +} + OperandMatchResultTy RISCVAsmParser::parseJALOffset(OperandVector &Operands) { // Parsing jal operands is fiddly due to the `jal foo` and `jal ra, foo` // both being acceptable forms. When parsing `jal ra, foo` this function @@ -1303,6 +1544,74 @@ OperandMatchResultTy RISCVAsmParser::parseJALOffset(OperandVector &Operands) { return parseImmediate(Operands); } +OperandMatchResultTy RISCVAsmParser::parseVTypeI(OperandVector &Operands) { + SMLoc S = getLoc(); + if (getLexer().getKind() != AsmToken::Identifier) + return MatchOperand_NoMatch; + + // Parse "e8,m1" + StringRef Name = getLexer().getTok().getIdentifier(); + if (!Name.consume_front("e")) + return MatchOperand_NoMatch; + APInt Sew(16, Name, 10); + if (Sew != 8 && Sew != 16 && Sew != 32 && Sew != 64 && Sew != 128 && + Sew != 256 && Sew != 512 && Sew != 1024) + return MatchOperand_NoMatch; + getLexer().Lex(); + + if (getLexer().getKind() == AsmToken::EndOfStatement) { + Operands.push_back( + RISCVOperand::createVType(Sew, APInt(16, 1), S, isRV64())); + + return MatchOperand_Success; + } + + if (!getLexer().is(AsmToken::Comma)) + return MatchOperand_NoMatch; + getLexer().Lex(); + + Name = getLexer().getTok().getIdentifier(); + if (!Name.consume_front("m")) + return MatchOperand_NoMatch; + APInt Lmul(16, Name, 10); + if (Lmul != 1 && Lmul != 2 && Lmul != 4 && Lmul != 8) + return MatchOperand_NoMatch; + getLexer().Lex(); + + if (getLexer().getKind() != AsmToken::EndOfStatement) + return MatchOperand_NoMatch; + + Operands.push_back(RISCVOperand::createVType(Sew, Lmul, S, isRV64())); + + return MatchOperand_Success; +} + +OperandMatchResultTy RISCVAsmParser::parseMaskReg(OperandVector &Operands) { + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::Identifier: + StringRef Name = getLexer().getTok().getIdentifier(); + if (!Name.consume_back(".t")) { + Error(getLoc(), "expected '.t' suffix"); + return MatchOperand_ParseFail; + } + Register RegNo; + matchRegisterNameHelper(isRV32E(), RegNo, Name); + + if (RegNo == RISCV::NoRegister) + return MatchOperand_NoMatch; + if (RegNo != RISCV::V0) + return MatchOperand_NoMatch; + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + getLexer().Lex(); + Operands.push_back(RISCVOperand::createReg(RegNo, S, E, isRV64())); + } + + return MatchOperand_Success; +} + OperandMatchResultTy RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { if (getLexer().isNot(AsmToken::LParen)) { @@ -1532,6 +1841,8 @@ bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { if (IDVal == ".option") return parseDirectiveOption(); + else if (IDVal == ".attribute") + return parseDirectiveAttribute(); return true; } @@ -1598,6 +1909,30 @@ bool RISCVAsmParser::parseDirectiveOption() { return false; } + if (Option == "pic") { + getTargetStreamer().emitDirectiveOptionPIC(); + + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + + ParserOptions.IsPicEnabled = true; + return false; + } + + if (Option == "nopic") { + getTargetStreamer().emitDirectiveOptionNoPIC(); + + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + + ParserOptions.IsPicEnabled = false; + return false; + } + if (Option == "relax") { getTargetStreamer().emitDirectiveOptionRelax(); @@ -1630,12 +1965,157 @@ bool RISCVAsmParser::parseDirectiveOption() { return false; } +/// parseDirectiveAttribute +/// ::= .attribute expression ',' ( expression | "string" ) +/// ::= .attribute identifier ',' ( expression | "string" ) +bool RISCVAsmParser::parseDirectiveAttribute() { + MCAsmParser &Parser = getParser(); + int64_t Tag; + SMLoc TagLoc; + TagLoc = Parser.getTok().getLoc(); + if (Parser.getTok().is(AsmToken::Identifier)) { + StringRef Name = Parser.getTok().getIdentifier(); + Optional<unsigned> Ret = + ELFAttrs::attrTypeFromString(Name, RISCVAttrs::RISCVAttributeTags); + if (!Ret.hasValue()) { + Error(TagLoc, "attribute name not recognised: " + Name); + return false; + } + Tag = Ret.getValue(); + Parser.Lex(); + } else { + const MCExpr *AttrExpr; + + TagLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(AttrExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr); + if (check(!CE, TagLoc, "expected numeric constant")) + return true; + + Tag = CE->getValue(); + } + + if (Parser.parseToken(AsmToken::Comma, "comma expected")) + return true; + + StringRef StringValue; + int64_t IntegerValue = 0; + bool IsIntegerValue = true; + + // RISC-V attributes have a string value if the tag number is odd + // and an integer value if the tag number is even. + if (Tag % 2) + IsIntegerValue = false; + + SMLoc ValueExprLoc = Parser.getTok().getLoc(); + if (IsIntegerValue) { + const MCExpr *ValueExpr; + if (Parser.parseExpression(ValueExpr)) + return true; + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr); + if (!CE) + return Error(ValueExprLoc, "expected numeric constant"); + IntegerValue = CE->getValue(); + } else { + if (Parser.getTok().isNot(AsmToken::String)) + return Error(Parser.getTok().getLoc(), "expected string constant"); + + StringValue = Parser.getTok().getStringContents(); + Parser.Lex(); + } + + if (Parser.parseToken(AsmToken::EndOfStatement, + "unexpected token in '.attribute' directive")) + return true; + + if (Tag == RISCVAttrs::ARCH) { + StringRef Arch = StringValue; + if (Arch.consume_front("rv32")) + clearFeatureBits(RISCV::Feature64Bit, "64bit"); + else if (Arch.consume_front("rv64")) + setFeatureBits(RISCV::Feature64Bit, "64bit"); + else + return Error(ValueExprLoc, "bad arch string " + Arch); + + while (!Arch.empty()) { + if (Arch[0] == 'i') + clearFeatureBits(RISCV::FeatureRV32E, "e"); + else if (Arch[0] == 'e') + setFeatureBits(RISCV::FeatureRV32E, "e"); + else if (Arch[0] == 'g') { + clearFeatureBits(RISCV::FeatureRV32E, "e"); + setFeatureBits(RISCV::FeatureStdExtM, "m"); + setFeatureBits(RISCV::FeatureStdExtA, "a"); + setFeatureBits(RISCV::FeatureStdExtF, "f"); + setFeatureBits(RISCV::FeatureStdExtD, "d"); + } else if (Arch[0] == 'm') + setFeatureBits(RISCV::FeatureStdExtM, "m"); + else if (Arch[0] == 'a') + setFeatureBits(RISCV::FeatureStdExtA, "a"); + else if (Arch[0] == 'f') + setFeatureBits(RISCV::FeatureStdExtF, "f"); + else if (Arch[0] == 'd') { + setFeatureBits(RISCV::FeatureStdExtF, "f"); + setFeatureBits(RISCV::FeatureStdExtD, "d"); + } else if (Arch[0] == 'c') { + setFeatureBits(RISCV::FeatureStdExtC, "c"); + } else + return Error(ValueExprLoc, "bad arch string " + Arch); + + Arch = Arch.drop_front(1); + int major = 0; + int minor = 0; + Arch.consumeInteger(10, major); + Arch.consume_front("p"); + Arch.consumeInteger(10, minor); + if (major != 0 || minor != 0) { + Arch = Arch.drop_until([](char c) { return c == '_' || c == '"'; }); + Arch = Arch.drop_while([](char c) { return c == '_'; }); + } + } + } + + if (IsIntegerValue) + getTargetStreamer().emitAttribute(Tag, IntegerValue); + else { + if (Tag != RISCVAttrs::ARCH) { + getTargetStreamer().emitTextAttribute(Tag, StringValue); + } else { + std::string formalArchStr = "rv32"; + if (getFeatureBits(RISCV::Feature64Bit)) + formalArchStr = "rv64"; + if (getFeatureBits(RISCV::FeatureRV32E)) + formalArchStr = (Twine(formalArchStr) + "e1p9").str(); + else + formalArchStr = (Twine(formalArchStr) + "i2p0").str(); + + if (getFeatureBits(RISCV::FeatureStdExtM)) + formalArchStr = (Twine(formalArchStr) + "_m2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtA)) + formalArchStr = (Twine(formalArchStr) + "_a2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtF)) + formalArchStr = (Twine(formalArchStr) + "_f2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtD)) + formalArchStr = (Twine(formalArchStr) + "_d2p0").str(); + if (getFeatureBits(RISCV::FeatureStdExtC)) + formalArchStr = (Twine(formalArchStr) + "_c2p0").str(); + + getTargetStreamer().emitTextAttribute(Tag, formalArchStr); + } + } + + return false; +} + void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); if (Res) ++RISCVNumInstrsCompressed; - S.EmitInstruction((Res ? CInst : Inst), getSTI()); + S.emitInstruction((Res ? CInst : Inst), getSTI()); } void RISCVAsmParser::emitLoadImm(Register DestReg, int64_t Value, @@ -1671,7 +2151,7 @@ void RISCVAsmParser::emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg, MCSymbol *TmpLabel = Ctx.createTempSymbol( "pcrel_hi", /* AlwaysAddSuffix */ true, /* CanBeUnnamed */ false); - Out.EmitLabel(TmpLabel); + Out.emitLabel(TmpLabel); const RISCVMCExpr *SymbolHi = RISCVMCExpr::create(Symbol, VKHi, Ctx); emitToStreamer( @@ -1716,8 +2196,7 @@ void RISCVAsmParser::emitLoadAddress(MCInst &Inst, SMLoc IDLoc, const MCExpr *Symbol = Inst.getOperand(1).getExpr(); unsigned SecondOpcode; RISCVMCExpr::VariantKind VKHi; - // FIXME: Should check .option (no)pic when implemented - if (getContext().getObjectFileInfo()->isPositionIndependent()) { + if (ParserOptions.IsPicEnabled) { SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW; VKHi = RISCVMCExpr::VK_RISCV_GOT_HI; } else { @@ -1788,6 +2267,89 @@ bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst, return false; } +std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultMaskRegOp() const { + return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(), + llvm::SMLoc(), isRV64()); +} + +bool RISCVAsmParser::validateInstruction(MCInst &Inst, + OperandVector &Operands) { + const MCInstrDesc &MCID = MII.get(Inst.getOpcode()); + unsigned TargetFlags = + (MCID.TSFlags >> RISCV::ConstraintOffset) & RISCV::ConstraintMask; + if (TargetFlags == RISCV::NoConstraint) + return false; + + unsigned DestReg = Inst.getOperand(0).getReg(); + // Operands[1] will be the first operand, DestReg. + SMLoc Loc = Operands[1]->getStartLoc(); + if ((TargetFlags == RISCV::WidenV) || (TargetFlags == RISCV::WidenW) || + (TargetFlags == RISCV::SlideUp) || (TargetFlags == RISCV::Vrgather) || + (TargetFlags == RISCV::Vcompress)) { + if (TargetFlags != RISCV::WidenW) { + unsigned Src2Reg = Inst.getOperand(1).getReg(); + if (DestReg == Src2Reg) + return Error(Loc, "The destination vector register group cannot overlap" + " the source vector register group."); + if (TargetFlags == RISCV::WidenV) { + // Assume DestReg LMUL is 2 at least for widening/narrowing operations. + if (DestReg + 1 == Src2Reg) + return Error(Loc, + "The destination vector register group cannot overlap" + " the source vector register group."); + } + } + if (Inst.getOperand(2).isReg()) { + unsigned Src1Reg = Inst.getOperand(2).getReg(); + if (DestReg == Src1Reg) + return Error(Loc, "The destination vector register group cannot overlap" + " the source vector register group."); + if (TargetFlags == RISCV::WidenV || TargetFlags == RISCV::WidenW) { + // Assume DestReg LMUL is 2 at least for widening/narrowing operations. + if (DestReg + 1 == Src1Reg) + return Error(Loc, + "The destination vector register group cannot overlap" + " the source vector register group."); + } + } + if (Inst.getNumOperands() == 4) { + unsigned MaskReg = Inst.getOperand(3).getReg(); + + if (DestReg == MaskReg) + return Error(Loc, "The destination vector register group cannot overlap" + " the mask register."); + } + } else if (TargetFlags == RISCV::Narrow) { + unsigned Src2Reg = Inst.getOperand(1).getReg(); + if (DestReg == Src2Reg) + return Error(Loc, "The destination vector register group cannot overlap" + " the source vector register group."); + // Assume Src2Reg LMUL is 2 at least for widening/narrowing operations. + if (DestReg == Src2Reg + 1) + return Error(Loc, "The destination vector register group cannot overlap" + " the source vector register group."); + } else if (TargetFlags == RISCV::WidenCvt || TargetFlags == RISCV::Iota) { + unsigned Src2Reg = Inst.getOperand(1).getReg(); + if (DestReg == Src2Reg) + return Error(Loc, "The destination vector register group cannot overlap" + " the source vector register group."); + if (TargetFlags == RISCV::WidenCvt) { + // Assume DestReg LMUL is 2 at least for widening/narrowing operations. + if (DestReg + 1 == Src2Reg) + return Error(Loc, "The destination vector register group cannot overlap" + " the source vector register group."); + } + if (Inst.getNumOperands() == 3) { + unsigned MaskReg = Inst.getOperand(2).getReg(); + + if (DestReg == MaskReg) + return Error(Loc, "The destination vector register group cannot overlap" + " the mask register."); + } + } + return false; +} + bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, MCStreamer &Out) { |