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 53562f42a184..407f980bd35e 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) { | 
