summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp')
-rw-r--r--llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp584
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) {