diff options
Diffstat (limited to 'lib/Target/RISCV')
51 files changed, 6234 insertions, 151 deletions
diff --git a/lib/Target/RISCV/AsmParser/CMakeLists.txt b/lib/Target/RISCV/AsmParser/CMakeLists.txt new file mode 100644 index 000000000000..10d0c89537ce --- /dev/null +++ b/lib/Target/RISCV/AsmParser/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMRISCVAsmParser +  RISCVAsmParser.cpp +  ) diff --git a/lib/Target/RISCV/AsmParser/LLVMBuild.txt b/lib/Target/RISCV/AsmParser/LLVMBuild.txt new file mode 100644 index 000000000000..a9ad92c872ea --- /dev/null +++ b/lib/Target/RISCV/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/RISCV/AsmParser/LLVMBuild.txt ---------------*- Conf -*--===; +; +;                     The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +;   http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = RISCVAsmParser +parent = RISCV +required_libraries = MC MCParser RISCVDesc RISCVInfo Support +add_to_library_groups = RISCV diff --git a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp new file mode 100644 index 000000000000..3299a53ff5ba --- /dev/null +++ b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -0,0 +1,946 @@ +//===-- RISCVAsmParser.cpp - Parse RISCV assembly to MCInst instructions --===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVMCExpr.h" +#include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +namespace { +struct RISCVOperand; + +class RISCVAsmParser : public MCTargetAsmParser { +  SMLoc getLoc() const { return getParser().getTok().getLoc(); } +  bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); } + +  unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, +                                      unsigned Kind) override; + +  bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, +                                  int Lower, int Upper, Twine Msg); + +  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, +                               OperandVector &Operands, MCStreamer &Out, +                               uint64_t &ErrorInfo, +                               bool MatchingInlineAsm) override; + +  bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + +  bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, +                        SMLoc NameLoc, OperandVector &Operands) override; + +  bool ParseDirective(AsmToken DirectiveID) override; + +// Auto-generated instruction matching functions +#define GET_ASSEMBLER_HEADER +#include "RISCVGenAsmMatcher.inc" + +  OperandMatchResultTy parseImmediate(OperandVector &Operands); +  OperandMatchResultTy parseRegister(OperandVector &Operands, +                                     bool AllowParens = false); +  OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); +  OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); + +  bool parseOperand(OperandVector &Operands); + +public: +  enum RISCVMatchResultTy { +    Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "RISCVGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES +  }; + +  static bool classifySymbolRef(const MCExpr *Expr, +                                RISCVMCExpr::VariantKind &Kind, +                                int64_t &Addend); + +  RISCVAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, +                 const MCInstrInfo &MII, const MCTargetOptions &Options) +      : MCTargetAsmParser(Options, STI, MII) { +    setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); +  } +}; + +/// RISCVOperand - Instances of this class represent a parsed machine +/// instruction +struct RISCVOperand : public MCParsedAsmOperand { + +  enum KindTy { +    Token, +    Register, +    Immediate, +  } Kind; + +  bool IsRV64; + +  struct RegOp { +    unsigned RegNum; +  }; + +  struct ImmOp { +    const MCExpr *Val; +  }; + +  SMLoc StartLoc, EndLoc; +  union { +    StringRef Tok; +    RegOp Reg; +    ImmOp Imm; +  }; + +  RISCVOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + +public: +  RISCVOperand(const RISCVOperand &o) : MCParsedAsmOperand() { +    Kind = o.Kind; +    IsRV64 = o.IsRV64; +    StartLoc = o.StartLoc; +    EndLoc = o.EndLoc; +    switch (Kind) { +    case Register: +      Reg = o.Reg; +      break; +    case Immediate: +      Imm = o.Imm; +      break; +    case Token: +      Tok = o.Tok; +      break; +    } +  } + +  bool isToken() const override { return Kind == Token; } +  bool isReg() const override { return Kind == Register; } +  bool isImm() const override { return Kind == Immediate; } +  bool isMem() const override { return false; } + +  bool evaluateConstantImm(int64_t &Imm, RISCVMCExpr::VariantKind &VK) const { +    const MCExpr *Val = getImm(); +    bool Ret = false; +    if (auto *RE = dyn_cast<RISCVMCExpr>(Val)) { +      Ret = RE->evaluateAsConstant(Imm); +      VK = RE->getKind(); +    } else if (auto CE = dyn_cast<MCConstantExpr>(Val)) { +      Ret = true; +      VK = RISCVMCExpr::VK_RISCV_None; +      Imm = CE->getValue(); +    } +    return Ret; +  } + +  // True if operand is a symbol with no modifiers, or a constant with no +  // modifiers and isShiftedInt<N-1, 1>(Op). +  template <int N> bool isBareSimmNLsb0() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    if (!isImm()) +      return false; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    bool IsValid; +    if (!IsConstantImm) +      IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); +    else +      IsValid = isShiftedInt<N - 1, 1>(Imm); +    return IsValid && VK == RISCVMCExpr::VK_RISCV_None; +  } + +  // Predicate methods for AsmOperands defined in RISCVInstrInfo.td + +  /// Return true if the operand is a valid for the fence instruction e.g. +  /// ('iorw'). +  bool isFenceArg() const { +    if (!isImm()) +      return false; +    const MCExpr *Val = getImm(); +    auto *SVal = dyn_cast<MCSymbolRefExpr>(Val); +    if (!SVal || SVal->getKind() != MCSymbolRefExpr::VK_None) +      return false; + +    StringRef Str = SVal->getSymbol().getName(); +    // Letters must be unique, taken from 'iorw', and in ascending order. This +    // holds as long as each individual character is one of 'iorw' and is +    // greater than the previous character. +    char Prev = '\0'; +    for (char c : Str) { +      if (c != 'i' && c != 'o' && c != 'r' && c != 'w') +        return false; +      if (c <= Prev) +        return false; +      Prev = c; +    } +    return true; +  } + +  /// Return true if the operand is a valid floating point rounding mode. +  bool isFRMArg() const { +    if (!isImm()) +      return false; +    const MCExpr *Val = getImm(); +    auto *SVal = dyn_cast<MCSymbolRefExpr>(Val); +    if (!SVal || SVal->getKind() != MCSymbolRefExpr::VK_None) +      return false; + +    StringRef Str = SVal->getSymbol().getName(); + +    return RISCVFPRndMode::stringToRoundingMode(Str) != RISCVFPRndMode::Invalid; +  } + +  bool isUImmLog2XLen() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    if (!isImm()) +      return false; +    if (!evaluateConstantImm(Imm, VK) || VK != RISCVMCExpr::VK_RISCV_None) +      return false; +    return (isRV64() && isUInt<6>(Imm)) || isUInt<5>(Imm); +  } + +  bool isUImmLog2XLenNonZero() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    if (!isImm()) +      return false; +    if (!evaluateConstantImm(Imm, VK) || VK != RISCVMCExpr::VK_RISCV_None) +      return false; +    if (Imm == 0) +      return false; +    return (isRV64() && isUInt<6>(Imm)) || isUInt<5>(Imm); +  } + +  bool isUImm5() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    if (!isImm()) +      return false; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isUInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isUImm5NonZero() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    if (!isImm()) +      return false; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isUInt<5>(Imm) && (Imm != 0) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isSImm6() const { +    RISCVMCExpr::VariantKind VK; +    int64_t Imm; +    bool IsValid; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    if (!IsConstantImm) +      IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); +    else +      IsValid = isInt<6>(Imm); +    return IsValid && +           (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO); +  } + +  bool isUImm6NonZero() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isUInt<6>(Imm) && (Imm != 0) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isUImm7Lsb00() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isShiftedUInt<5, 2>(Imm) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isUImm8Lsb00() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isShiftedUInt<6, 2>(Imm) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isUImm8Lsb000() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isShiftedUInt<5, 3>(Imm) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isSImm9Lsb0() const { return isBareSimmNLsb0<9>(); } + +  bool isUImm9Lsb000() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isShiftedUInt<6, 3>(Imm) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isUImm10Lsb00NonZero() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isShiftedUInt<8, 2>(Imm) && (Imm != 0) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isSImm12() const { +    RISCVMCExpr::VariantKind VK; +    int64_t Imm; +    bool IsValid; +    if (!isImm()) +      return false; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    if (!IsConstantImm) +      IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); +    else +      IsValid = isInt<12>(Imm); +    return IsValid && +           (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO); +  } + +  bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); } + +  bool isUImm12() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    if (!isImm()) +      return false; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isUInt<12>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isSImm13Lsb0() const { return isBareSimmNLsb0<13>(); } + +  bool isSImm10Lsb0000() const { +    int64_t Imm; +    RISCVMCExpr::VariantKind VK; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    return IsConstantImm && isShiftedInt<6, 4>(Imm) && +           VK == RISCVMCExpr::VK_RISCV_None; +  } + +  bool isUImm20() const { +    RISCVMCExpr::VariantKind VK; +    int64_t Imm; +    bool IsValid; +    if (!isImm()) +      return false; +    bool IsConstantImm = evaluateConstantImm(Imm, VK); +    if (!IsConstantImm) +      IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); +    else +      IsValid = isUInt<20>(Imm); +    return IsValid && (VK == RISCVMCExpr::VK_RISCV_None || +                       VK == RISCVMCExpr::VK_RISCV_HI || +                       VK == RISCVMCExpr::VK_RISCV_PCREL_HI); +  } + +  bool isSImm21Lsb0() const { return isBareSimmNLsb0<21>(); } + +  /// 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 +  SMLoc getEndLoc() const override { return EndLoc; } +  /// True if this operand is for an RV64 instruction +  bool isRV64() const { return IsRV64; } + +  unsigned getReg() const override { +    assert(Kind == Register && "Invalid type access!"); +    return Reg.RegNum; +  } + +  const MCExpr *getImm() const { +    assert(Kind == Immediate && "Invalid type access!"); +    return Imm.Val; +  } + +  StringRef getToken() const { +    assert(Kind == Token && "Invalid type access!"); +    return Tok; +  } + +  void print(raw_ostream &OS) const override { +    switch (Kind) { +    case Immediate: +      OS << *getImm(); +      break; +    case Register: +      OS << "<register x"; +      OS << getReg() << ">"; +      break; +    case Token: +      OS << "'" << getToken() << "'"; +      break; +    } +  } + +  static std::unique_ptr<RISCVOperand> createToken(StringRef Str, SMLoc S, +                                                   bool IsRV64) { +    auto Op = make_unique<RISCVOperand>(Token); +    Op->Tok = Str; +    Op->StartLoc = S; +    Op->EndLoc = S; +    Op->IsRV64 = IsRV64; +    return Op; +  } + +  static std::unique_ptr<RISCVOperand> createReg(unsigned RegNo, SMLoc S, +                                                 SMLoc E, bool IsRV64) { +    auto Op = make_unique<RISCVOperand>(Register); +    Op->Reg.RegNum = RegNo; +    Op->StartLoc = S; +    Op->EndLoc = E; +    Op->IsRV64 = IsRV64; +    return Op; +  } + +  static std::unique_ptr<RISCVOperand> createImm(const MCExpr *Val, SMLoc S, +                                                 SMLoc E, bool IsRV64) { +    auto Op = make_unique<RISCVOperand>(Immediate); +    Op->Imm.Val = Val; +    Op->StartLoc = S; +    Op->EndLoc = E; +    Op->IsRV64 = IsRV64; +    return Op; +  } + +  void addExpr(MCInst &Inst, const MCExpr *Expr) const { +    assert(Expr && "Expr shouldn't be null!"); +    int64_t Imm = 0; +    bool IsConstant = false; +    if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) { +      IsConstant = RE->evaluateAsConstant(Imm); +    } else if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) { +      IsConstant = true; +      Imm = CE->getValue(); +    } + +    if (IsConstant) +      Inst.addOperand(MCOperand::createImm(Imm)); +    else +      Inst.addOperand(MCOperand::createExpr(Expr)); +  } + +  // Used by the TableGen Code +  void addRegOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); +    Inst.addOperand(MCOperand::createReg(getReg())); +  } + +  void addImmOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); +    addExpr(Inst, getImm()); +  } + +  void addFenceArgOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); +    // isFenceArg has validated the operand, meaning this cast is safe +    auto SE = cast<MCSymbolRefExpr>(getImm()); + +    unsigned Imm = 0; +    for (char c : SE->getSymbol().getName()) { +      switch (c) { +        default: llvm_unreachable("FenceArg must contain only [iorw]"); +        case 'i': Imm |= RISCVFenceField::I; break; +        case 'o': Imm |= RISCVFenceField::O; break; +        case 'r': Imm |= RISCVFenceField::R; break; +        case 'w': Imm |= RISCVFenceField::W; break; +      } +    } +    Inst.addOperand(MCOperand::createImm(Imm)); +  } + +  // Returns the rounding mode represented by this RISCVOperand. Should only +  // be called after checking isFRMArg. +  RISCVFPRndMode::RoundingMode getRoundingMode() const { +    // isFRMArg has validated the operand, meaning this cast is safe. +    auto SE = cast<MCSymbolRefExpr>(getImm()); +    RISCVFPRndMode::RoundingMode FRM = +        RISCVFPRndMode::stringToRoundingMode(SE->getSymbol().getName()); +    assert(FRM != RISCVFPRndMode::Invalid && "Invalid rounding mode"); +    return FRM; +  } + +  void addFRMArgOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); +    Inst.addOperand(MCOperand::createImm(getRoundingMode())); +  } +}; +} // end anonymous namespace. + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "RISCVGenAsmMatcher.inc" + +// Return the matching FPR64 register for the given FPR32. +// FIXME: Ideally this function could be removed in favour of using +// information from TableGen. +unsigned convertFPR32ToFPR64(unsigned Reg) { +  switch (Reg) { +    default: +      llvm_unreachable("Not a recognised FPR32 register"); +    case RISCV::F0_32: return RISCV::F0_64; +    case RISCV::F1_32: return RISCV::F1_64; +    case RISCV::F2_32: return RISCV::F2_64; +    case RISCV::F3_32: return RISCV::F3_64; +    case RISCV::F4_32: return RISCV::F4_64; +    case RISCV::F5_32: return RISCV::F5_64; +    case RISCV::F6_32: return RISCV::F6_64; +    case RISCV::F7_32: return RISCV::F7_64; +    case RISCV::F8_32: return RISCV::F8_64; +    case RISCV::F9_32: return RISCV::F9_64; +    case RISCV::F10_32: return RISCV::F10_64; +    case RISCV::F11_32: return RISCV::F11_64; +    case RISCV::F12_32: return RISCV::F12_64; +    case RISCV::F13_32: return RISCV::F13_64; +    case RISCV::F14_32: return RISCV::F14_64; +    case RISCV::F15_32: return RISCV::F15_64; +    case RISCV::F16_32: return RISCV::F16_64; +    case RISCV::F17_32: return RISCV::F17_64; +    case RISCV::F18_32: return RISCV::F18_64; +    case RISCV::F19_32: return RISCV::F19_64; +    case RISCV::F20_32: return RISCV::F20_64; +    case RISCV::F21_32: return RISCV::F21_64; +    case RISCV::F22_32: return RISCV::F22_64; +    case RISCV::F23_32: return RISCV::F23_64; +    case RISCV::F24_32: return RISCV::F24_64; +    case RISCV::F25_32: return RISCV::F25_64; +    case RISCV::F26_32: return RISCV::F26_64; +    case RISCV::F27_32: return RISCV::F27_64; +    case RISCV::F28_32: return RISCV::F28_64; +    case RISCV::F29_32: return RISCV::F29_64; +    case RISCV::F30_32: return RISCV::F30_64; +    case RISCV::F31_32: return RISCV::F31_64; +  } +} + +unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, +                                                    unsigned Kind) { +  RISCVOperand &Op = static_cast<RISCVOperand &>(AsmOp); +  if (!Op.isReg()) +    return Match_InvalidOperand; + +  unsigned Reg = Op.getReg(); +  bool IsRegFPR32 = +      RISCVMCRegisterClasses[RISCV::FPR32RegClassID].contains(Reg); +  bool IsRegFPR32C = +      RISCVMCRegisterClasses[RISCV::FPR32CRegClassID].contains(Reg); + +  // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the +  // register from FPR32 to FPR64 or FPR32C to FPR64C if necessary. +  if ((IsRegFPR32 && Kind == MCK_FPR64) || +      (IsRegFPR32C && Kind == MCK_FPR64C)) { +    Op.Reg.RegNum = convertFPR32ToFPR64(Reg); +    return Match_Success; +  } +  return Match_InvalidOperand; +} + +bool RISCVAsmParser::generateImmOutOfRangeError( +    OperandVector &Operands, uint64_t ErrorInfo, int Lower, int Upper, +    Twine Msg = "immediate must be an integer in the range") { +  SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); +  return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); +} + +bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, +                                             OperandVector &Operands, +                                             MCStreamer &Out, +                                             uint64_t &ErrorInfo, +                                             bool MatchingInlineAsm) { +  MCInst Inst; + +  switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) { +  default: +    break; +  case Match_Success: +    Inst.setLoc(IDLoc); +    Out.EmitInstruction(Inst, getSTI()); +    return false; +  case Match_MissingFeature: +    return Error(IDLoc, "instruction use requires an option to be enabled"); +  case Match_MnemonicFail: +    return Error(IDLoc, "unrecognized instruction mnemonic"); +  case Match_InvalidOperand: { +    SMLoc ErrorLoc = IDLoc; +    if (ErrorInfo != ~0U) { +      if (ErrorInfo >= Operands.size()) +        return Error(ErrorLoc, "too few operands for instruction"); + +      ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); +      if (ErrorLoc == SMLoc()) +        ErrorLoc = IDLoc; +    } +    return Error(ErrorLoc, "invalid operand for instruction"); +  } +  case Match_InvalidUImmLog2XLen: +    if (isRV64()) +      return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); +    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); +  case Match_InvalidUImmLog2XLenNonZero: +    if (isRV64()) +      return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6) - 1); +    return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 5) - 1); +  case Match_InvalidUImm5: +    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); +  case Match_InvalidSImm6: +    return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 5), +                                      (1 << 5) - 1); +  case Match_InvalidUImm6NonZero: +    return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6) - 1); +  case Match_InvalidUImm7Lsb00: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, 0, (1 << 7) - 4, +        "immediate must be a multiple of 4 bytes in the range"); +  case Match_InvalidUImm8Lsb00: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, 0, (1 << 8) - 4, +        "immediate must be a multiple of 4 bytes in the range"); +  case Match_InvalidUImm8Lsb000: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, 0, (1 << 8) - 8, +        "immediate must be a multiple of 8 bytes in the range"); +  case Match_InvalidSImm9Lsb0: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, -(1 << 8), (1 << 8) - 2, +        "immediate must be a multiple of 2 bytes in the range"); +  case Match_InvalidUImm9Lsb000: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, 0, (1 << 9) - 8, +        "immediate must be a multiple of 8 bytes in the range"); +  case Match_InvalidUImm10Lsb00NonZero: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, 4, (1 << 10) - 4, +        "immediate must be a multiple of 4 bytes in the range"); +  case Match_InvalidSImm10Lsb0000: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, -(1 << 9), (1 << 9) - 16, +        "immediate must be a multiple of 16 bytes in the range"); +  case Match_InvalidSImm12: +    return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 11), +                                      (1 << 11) - 1); +  case Match_InvalidSImm12Lsb0: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, -(1 << 11), (1 << 11) - 2, +        "immediate must be a multiple of 2 bytes in the range"); +  case Match_InvalidUImm12: +    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1); +  case Match_InvalidSImm13Lsb0: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, -(1 << 12), (1 << 12) - 2, +        "immediate must be a multiple of 2 bytes in the range"); +  case Match_InvalidUImm20: +    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 20) - 1); +  case Match_InvalidSImm21Lsb0: +    return generateImmOutOfRangeError( +        Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, +        "immediate must be a multiple of 2 bytes in the range"); +  case Match_InvalidFenceArg: { +    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); +    return Error( +        ErrorLoc, +        "operand must be formed of letters selected in-order from 'iorw'"); +  } +  case Match_InvalidFRMArg: { +    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); +    return Error( +        ErrorLoc, +        "operand must be a valid floating point rounding mode mnemonic"); +  } +  } + +  llvm_unreachable("Unknown match type detected!"); +} + +bool RISCVAsmParser::ParseRegister(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 (!MatchRegisterName(Name) || !MatchRegisterAltName(Name)) { +    getParser().Lex(); // Eat identifier token. +    return false; +  } + +  return Error(StartLoc, "invalid register name"); +} + +OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands, +                                                   bool AllowParens) { +  SMLoc FirstS = getLoc(); +  bool HadParens = false; +  AsmToken Buf[2]; + +  // If this a parenthesised register name is allowed, parse it atomically +  if (AllowParens && getLexer().is(AsmToken::LParen)) { +    size_t ReadCount = getLexer().peekTokens(Buf); +    if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { +      HadParens = true; +      getParser().Lex(); // Eat '(' +    } +  } + +  switch (getLexer().getKind()) { +  default: +    return MatchOperand_NoMatch; +  case AsmToken::Identifier: +    StringRef Name = getLexer().getTok().getIdentifier(); +    unsigned RegNo = MatchRegisterName(Name); +    if (RegNo == 0) { +      RegNo = MatchRegisterAltName(Name); +      if (RegNo == 0) { +        if (HadParens) +          getLexer().UnLex(Buf[0]); +        return MatchOperand_NoMatch; +      } +    } +    if (HadParens) +      Operands.push_back(RISCVOperand::createToken("(", FirstS, isRV64())); +    SMLoc S = getLoc(); +    SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); +    getLexer().Lex(); +    Operands.push_back(RISCVOperand::createReg(RegNo, S, E, isRV64())); +  } + +  if (HadParens) { +    getParser().Lex(); // Eat ')' +    Operands.push_back(RISCVOperand::createToken(")", getLoc(), isRV64())); +  } + +  return MatchOperand_Success; +} + +OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { +  SMLoc S = getLoc(); +  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); +  const MCExpr *Res; + +  switch (getLexer().getKind()) { +  default: +    return MatchOperand_NoMatch; +  case AsmToken::LParen: +  case AsmToken::Minus: +  case AsmToken::Plus: +  case AsmToken::Integer: +  case AsmToken::String: +    if (getParser().parseExpression(Res)) +      return MatchOperand_ParseFail; +    break; +  case AsmToken::Identifier: { +    StringRef Identifier; +    if (getParser().parseIdentifier(Identifier)) +      return MatchOperand_ParseFail; +    MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); +    Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); +    break; +  } +  case AsmToken::Percent: +    return parseOperandWithModifier(Operands); +  } + +  Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); +  return MatchOperand_Success; +} + +OperandMatchResultTy +RISCVAsmParser::parseOperandWithModifier(OperandVector &Operands) { +  SMLoc S = getLoc(); +  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + +  if (getLexer().getKind() != AsmToken::Percent) { +    Error(getLoc(), "expected '%' for operand modifier"); +    return MatchOperand_ParseFail; +  } + +  getParser().Lex(); // Eat '%' + +  if (getLexer().getKind() != AsmToken::Identifier) { +    Error(getLoc(), "expected valid identifier for operand modifier"); +    return MatchOperand_ParseFail; +  } +  StringRef Identifier = getParser().getTok().getIdentifier(); +  RISCVMCExpr::VariantKind VK = RISCVMCExpr::getVariantKindForName(Identifier); +  if (VK == RISCVMCExpr::VK_RISCV_Invalid) { +    Error(getLoc(), "unrecognized operand modifier"); +    return MatchOperand_ParseFail; +  } + +  getParser().Lex(); // Eat the identifier +  if (getLexer().getKind() != AsmToken::LParen) { +    Error(getLoc(), "expected '('"); +    return MatchOperand_ParseFail; +  } +  getParser().Lex(); // Eat '(' + +  const MCExpr *SubExpr; +  if (getParser().parseParenExpression(SubExpr, E)) { +    return MatchOperand_ParseFail; +  } + +  const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, VK, getContext()); +  Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, isRV64())); +  return MatchOperand_Success; +} + +OperandMatchResultTy +RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { +  if (getLexer().isNot(AsmToken::LParen)) { +    Error(getLoc(), "expected '('"); +    return MatchOperand_ParseFail; +  } + +  getParser().Lex(); // Eat '(' +  Operands.push_back(RISCVOperand::createToken("(", getLoc(), isRV64())); + +  if (parseRegister(Operands) != MatchOperand_Success) { +    Error(getLoc(), "expected register"); +    return MatchOperand_ParseFail; +  } + +  if (getLexer().isNot(AsmToken::RParen)) { +    Error(getLoc(), "expected ')'"); +    return MatchOperand_ParseFail; +  } + +  getParser().Lex(); // Eat ')' +  Operands.push_back(RISCVOperand::createToken(")", getLoc(), isRV64())); + +  return MatchOperand_Success; +} + +/// Looks at a token type and creates the relevant operand +/// from this information, adding to Operands. +/// If operand was parsed, returns false, else true. +bool RISCVAsmParser::parseOperand(OperandVector &Operands) { +  // Attempt to parse token as register +  if (parseRegister(Operands, true) == MatchOperand_Success) +    return false; + +  // Attempt to parse token as an immediate +  if (parseImmediate(Operands) == MatchOperand_Success) { +    // Parse memory base register if present +    if (getLexer().is(AsmToken::LParen)) +      return parseMemOpBaseReg(Operands) != MatchOperand_Success; +    return false; +  } + +  // Finally we have exhausted all options and must declare defeat. +  Error(getLoc(), "unknown operand"); +  return true; +} + +bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info, +                                      StringRef Name, SMLoc NameLoc, +                                      OperandVector &Operands) { +  // First operand is token for instruction +  Operands.push_back(RISCVOperand::createToken(Name, NameLoc, isRV64())); + +  // If there are no more operands, then finish +  if (getLexer().is(AsmToken::EndOfStatement)) +    return false; + +  // Parse first operand +  if (parseOperand(Operands)) +    return true; + +  // Parse until end of statement, consuming commas between operands +  while (getLexer().is(AsmToken::Comma)) { +    // Consume comma token +    getLexer().Lex(); + +    // Parse next operand +    if (parseOperand(Operands)) +      return true; +  } + +  if (getLexer().isNot(AsmToken::EndOfStatement)) { +    SMLoc Loc = getLexer().getLoc(); +    getParser().eatToEndOfStatement(); +    return Error(Loc, "unexpected token"); +  } + +  getParser().Lex(); // Consume the EndOfStatement. +  return false; +} + +bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr, +                                       RISCVMCExpr::VariantKind &Kind, +                                       int64_t &Addend) { +  Kind = RISCVMCExpr::VK_RISCV_None; +  Addend = 0; + +  if (const RISCVMCExpr *RE = dyn_cast<RISCVMCExpr>(Expr)) { +    Kind = RE->getKind(); +    Expr = RE->getSubExpr(); +  } + +  // It's a simple symbol reference or constant with no addend. +  if (isa<MCConstantExpr>(Expr) || isa<MCSymbolRefExpr>(Expr)) +    return true; + +  const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr); +  if (!BE) +    return false; + +  if (!isa<MCSymbolRefExpr>(BE->getLHS())) +    return false; + +  if (BE->getOpcode() != MCBinaryExpr::Add && +      BE->getOpcode() != MCBinaryExpr::Sub) +    return false; + +  // We are able to support the subtraction of two symbol references +  if (BE->getOpcode() == MCBinaryExpr::Sub && +      isa<MCSymbolRefExpr>(BE->getRHS())) +    return true; + +  // See if the addend is is a constant, otherwise there's more going +  // on here than we can deal with. +  auto AddendExpr = dyn_cast<MCConstantExpr>(BE->getRHS()); +  if (!AddendExpr) +    return false; + +  Addend = AddendExpr->getValue(); +  if (BE->getOpcode() == MCBinaryExpr::Sub) +    Addend = -Addend; + +  // It's some symbol reference + a constant addend +  return Kind != RISCVMCExpr::VK_RISCV_Invalid; +} + +bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } + +extern "C" void LLVMInitializeRISCVAsmParser() { +  RegisterMCAsmParser<RISCVAsmParser> X(getTheRISCV32Target()); +  RegisterMCAsmParser<RISCVAsmParser> Y(getTheRISCV64Target()); +} diff --git a/lib/Target/RISCV/CMakeLists.txt b/lib/Target/RISCV/CMakeLists.txt index c8887548b917..66b50f8728e1 100644 --- a/lib/Target/RISCV/CMakeLists.txt +++ b/lib/Target/RISCV/CMakeLists.txt @@ -3,12 +3,29 @@ set(LLVM_TARGET_DEFINITIONS RISCV.td)  tablegen(LLVM RISCVGenRegisterInfo.inc -gen-register-info)  tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)  tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter) +tablegen(LLVM RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering) +tablegen(LLVM RISCVGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM RISCVGenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler)  add_public_tablegen_target(RISCVCommonTableGen)  add_llvm_target(RISCVCodeGen +  RISCVAsmPrinter.cpp +  RISCVFrameLowering.cpp +  RISCVInstrInfo.cpp +  RISCVISelDAGToDAG.cpp +  RISCVISelLowering.cpp +  RISCVMCInstLower.cpp +  RISCVRegisterInfo.cpp +  RISCVSubtarget.cpp    RISCVTargetMachine.cpp    ) -add_subdirectory(TargetInfo) +add_subdirectory(AsmParser) +add_subdirectory(Disassembler) +add_subdirectory(InstPrinter)  add_subdirectory(MCTargetDesc) +add_subdirectory(TargetInfo) diff --git a/lib/Target/RISCV/Disassembler/CMakeLists.txt b/lib/Target/RISCV/Disassembler/CMakeLists.txt new file mode 100644 index 000000000000..39bd2b7669f5 --- /dev/null +++ b/lib/Target/RISCV/Disassembler/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMRISCVDisassembler +  RISCVDisassembler.cpp +  ) diff --git a/lib/Target/RISCV/Disassembler/LLVMBuild.txt b/lib/Target/RISCV/Disassembler/LLVMBuild.txt new file mode 100644 index 000000000000..340e89d4cf35 --- /dev/null +++ b/lib/Target/RISCV/Disassembler/LLVMBuild.txt @@ -0,0 +1,24 @@ +;===- ./lib/Target/RISCV/Disassembler/LLVMBuild.txt ------------*- Conf -*--===; +; +;                     The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +;   http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = RISCVDisassembler +parent = RISCV +required_libraries = MCDisassembler RISCVInfo Support +add_to_library_groups = RISCV + diff --git a/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp new file mode 100644 index 000000000000..563edc9e29d8 --- /dev/null +++ b/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -0,0 +1,274 @@ +//===-- RISCVDisassembler.cpp - Disassembler for RISCV --------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the RISCVDisassembler class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscv-disassembler" + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { +class RISCVDisassembler : public MCDisassembler { + +public: +  RISCVDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) +      : MCDisassembler(STI, Ctx) {} + +  DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, +                              ArrayRef<uint8_t> Bytes, uint64_t Address, +                              raw_ostream &VStream, +                              raw_ostream &CStream) const override; +}; +} // end anonymous namespace + +static MCDisassembler *createRISCVDisassembler(const Target &T, +                                               const MCSubtargetInfo &STI, +                                               MCContext &Ctx) { +  return new RISCVDisassembler(STI, Ctx); +} + +extern "C" void LLVMInitializeRISCVDisassembler() { +  // Register the disassembler for each target. +  TargetRegistry::RegisterMCDisassembler(getTheRISCV32Target(), +                                         createRISCVDisassembler); +  TargetRegistry::RegisterMCDisassembler(getTheRISCV64Target(), +                                         createRISCVDisassembler); +} + +static const unsigned GPRDecoderTable[] = { +  RISCV::X0,  RISCV::X1,  RISCV::X2,  RISCV::X3, +  RISCV::X4,  RISCV::X5,  RISCV::X6,  RISCV::X7, +  RISCV::X8,  RISCV::X9,  RISCV::X10, RISCV::X11, +  RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, +  RISCV::X16, RISCV::X17, RISCV::X18, RISCV::X19, +  RISCV::X20, RISCV::X21, RISCV::X22, RISCV::X23, +  RISCV::X24, RISCV::X25, RISCV::X26, RISCV::X27, +  RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31 +}; + +static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, +                                           uint64_t Address, +                                           const void *Decoder) { +  if (RegNo > sizeof(GPRDecoderTable)) +    return MCDisassembler::Fail; + +  // We must define our own mapping from RegNo to register identifier. +  // Accessing index RegNo in the register class will work in the case that +  // registers were added in ascending order, but not in general. +  unsigned Reg = GPRDecoderTable[RegNo]; +  Inst.addOperand(MCOperand::createReg(Reg)); +  return MCDisassembler::Success; +} + +static const unsigned FPR32DecoderTable[] = { +  RISCV::F0_32,  RISCV::F1_32,  RISCV::F2_32,  RISCV::F3_32, +  RISCV::F4_32,  RISCV::F5_32,  RISCV::F6_32,  RISCV::F7_32, +  RISCV::F8_32,  RISCV::F9_32,  RISCV::F10_32, RISCV::F11_32, +  RISCV::F12_32, RISCV::F13_32, RISCV::F14_32, RISCV::F15_32, +  RISCV::F16_32, RISCV::F17_32, RISCV::F18_32, RISCV::F19_32, +  RISCV::F20_32, RISCV::F21_32, RISCV::F22_32, RISCV::F23_32, +  RISCV::F24_32, RISCV::F25_32, RISCV::F26_32, RISCV::F27_32, +  RISCV::F28_32, RISCV::F29_32, RISCV::F30_32, RISCV::F31_32 +}; + +static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo, +                                             uint64_t Address, +                                             const void *Decoder) { +  if (RegNo > sizeof(FPR32DecoderTable)) +    return MCDisassembler::Fail; + +  // We must define our own mapping from RegNo to register identifier. +  // Accessing index RegNo in the register class will work in the case that +  // registers were added in ascending order, but not in general. +  unsigned Reg = FPR32DecoderTable[RegNo]; +  Inst.addOperand(MCOperand::createReg(Reg)); +  return MCDisassembler::Success; +} + +static DecodeStatus DecodeFPR32CRegisterClass(MCInst &Inst, uint64_t RegNo, +                                              uint64_t Address, +                                              const void *Decoder) { +  if (RegNo > 8) { +    return MCDisassembler::Fail; +  } +  unsigned Reg = FPR32DecoderTable[RegNo + 8]; +  Inst.addOperand(MCOperand::createReg(Reg)); +  return MCDisassembler::Success; +} + +static const unsigned FPR64DecoderTable[] = { +  RISCV::F0_64,  RISCV::F1_64,  RISCV::F2_64,  RISCV::F3_64, +  RISCV::F4_64,  RISCV::F5_64,  RISCV::F6_64,  RISCV::F7_64, +  RISCV::F8_64,  RISCV::F9_64,  RISCV::F10_64, RISCV::F11_64, +  RISCV::F12_64, RISCV::F13_64, RISCV::F14_64, RISCV::F15_64, +  RISCV::F16_64, RISCV::F17_64, RISCV::F18_64, RISCV::F19_64, +  RISCV::F20_64, RISCV::F21_64, RISCV::F22_64, RISCV::F23_64, +  RISCV::F24_64, RISCV::F25_64, RISCV::F26_64, RISCV::F27_64, +  RISCV::F28_64, RISCV::F29_64, RISCV::F30_64, RISCV::F31_64 +}; + +static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo, +                                             uint64_t Address, +                                             const void *Decoder) { +  if (RegNo > sizeof(FPR64DecoderTable)) +    return MCDisassembler::Fail; + +  // We must define our own mapping from RegNo to register identifier. +  // Accessing index RegNo in the register class will work in the case that +  // registers were added in ascending order, but not in general. +  unsigned Reg = FPR64DecoderTable[RegNo]; +  Inst.addOperand(MCOperand::createReg(Reg)); +  return MCDisassembler::Success; +} + +static DecodeStatus DecodeFPR64CRegisterClass(MCInst &Inst, uint64_t RegNo, +                                              uint64_t Address, +                                              const void *Decoder) { +  if (RegNo > 8) { +    return MCDisassembler::Fail; +  } +  unsigned Reg = FPR64DecoderTable[RegNo + 8]; +  Inst.addOperand(MCOperand::createReg(Reg)); +  return MCDisassembler::Success; +} + +static DecodeStatus DecodeGPRNoX0RegisterClass(MCInst &Inst, uint64_t RegNo, +                                               uint64_t Address, +                                               const void *Decoder) { +  if (RegNo == 0) { +    return MCDisassembler::Fail; +  } + +  return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder); +} + +static DecodeStatus DecodeGPRNoX0X2RegisterClass(MCInst &Inst, uint64_t RegNo, +                                                 uint64_t Address, +                                                 const void *Decoder) { +  if (RegNo == 2) { +    return MCDisassembler::Fail; +  } + +  return DecodeGPRNoX0RegisterClass(Inst, RegNo, Address, Decoder); +} + +static DecodeStatus DecodeGPRCRegisterClass(MCInst &Inst, uint64_t RegNo, +                                            uint64_t Address, +                                            const void *Decoder) { +  if (RegNo > 8) +    return MCDisassembler::Fail; + +  unsigned Reg = GPRDecoderTable[RegNo + 8]; +  Inst.addOperand(MCOperand::createReg(Reg)); +  return MCDisassembler::Success; +} + +// Add implied SP operand for instructions *SP compressed instructions. The SP +// operand isn't explicitly encoded in the instruction. +static void addImplySP(MCInst &Inst, int64_t Address, const void *Decoder) { +  if (Inst.getOpcode() == RISCV::C_LWSP || Inst.getOpcode() == RISCV::C_SWSP || +      Inst.getOpcode() == RISCV::C_LDSP || Inst.getOpcode() == RISCV::C_SDSP || +      Inst.getOpcode() == RISCV::C_FLWSP || +      Inst.getOpcode() == RISCV::C_FSWSP || +      Inst.getOpcode() == RISCV::C_FLDSP || +      Inst.getOpcode() == RISCV::C_FSDSP || +      Inst.getOpcode() == RISCV::C_ADDI4SPN) { +    DecodeGPRRegisterClass(Inst, 2, Address, Decoder); +  } +  if (Inst.getOpcode() == RISCV::C_ADDI16SP) { +    DecodeGPRRegisterClass(Inst, 2, Address, Decoder); +    DecodeGPRRegisterClass(Inst, 2, Address, Decoder); +  } +} + +template <unsigned N> +static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm, +                                      int64_t Address, const void *Decoder) { +  assert(isUInt<N>(Imm) && "Invalid immediate"); +  addImplySP(Inst, Address, Decoder); +  Inst.addOperand(MCOperand::createImm(Imm)); +  return MCDisassembler::Success; +} + +template <unsigned N> +static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm, +                                      int64_t Address, const void *Decoder) { +  assert(isUInt<N>(Imm) && "Invalid immediate"); +  addImplySP(Inst, Address, Decoder); +  // Sign-extend the number in the bottom N bits of Imm +  Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm))); +  return MCDisassembler::Success; +} + +template <unsigned N> +static DecodeStatus decodeSImmOperandAndLsl1(MCInst &Inst, uint64_t Imm, +                                             int64_t Address, +                                             const void *Decoder) { +  assert(isUInt<N>(Imm) && "Invalid immediate"); +  // Sign-extend the number in the bottom N bits of Imm after accounting for +  // the fact that the N bit immediate is stored in N-1 bits (the LSB is +  // always zero) +  Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm << 1))); +  return MCDisassembler::Success; +} + +#include "RISCVGenDisassemblerTables.inc" + +DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, +                                               ArrayRef<uint8_t> Bytes, +                                               uint64_t Address, +                                               raw_ostream &OS, +                                               raw_ostream &CS) const { +  // TODO: This will need modification when supporting instruction set +  // extensions with instructions > 32-bits (up to 176 bits wide). +  uint32_t Insn; +  DecodeStatus Result; + +  // It's a 32 bit instruction if bit 0 and 1 are 1. +  if ((Bytes[0] & 0x3) == 0x3) { +    Insn = support::endian::read32le(Bytes.data()); +    DEBUG(dbgs() << "Trying RISCV32 table :\n"); +    Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI); +    Size = 4; +  } else { +    Insn = support::endian::read16le(Bytes.data()); + +    if (!STI.getFeatureBits()[RISCV::Feature64Bit]) { +      DEBUG(dbgs() << "Trying RISCV32Only_16 table (16-bit Instruction):\n"); +      // Calling the auto-generated decoder function. +      Result = decodeInstruction(DecoderTableRISCV32Only_16, MI, Insn, Address, +                                 this, STI); +      if (Result != MCDisassembler::Fail) { +        Size = 2; +        return Result; +      } +    } + +    DEBUG(dbgs() << "Trying RISCV_C table (16-bit Instruction):\n"); +    // Calling the auto-generated decoder function. +    Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI); +    Size = 2; +  } + +  return Result; +} diff --git a/lib/Target/RISCV/InstPrinter/CMakeLists.txt b/lib/Target/RISCV/InstPrinter/CMakeLists.txt new file mode 100644 index 000000000000..7f91743fb934 --- /dev/null +++ b/lib/Target/RISCV/InstPrinter/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMRISCVAsmPrinter +  RISCVInstPrinter.cpp +  ) diff --git a/lib/Target/RISCV/InstPrinter/LLVMBuild.txt b/lib/Target/RISCV/InstPrinter/LLVMBuild.txt new file mode 100644 index 000000000000..5f4545e3d676 --- /dev/null +++ b/lib/Target/RISCV/InstPrinter/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/RISCV/InstPrinter/LLVMBuild.txt -------------*- Conf -*--===; +; +;                     The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +;   http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = RISCVAsmPrinter +parent = RISCV +required_libraries = MC Support +add_to_library_groups = RISCV diff --git a/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp b/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp new file mode 100644 index 000000000000..ff56fc5d90ff --- /dev/null +++ b/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp @@ -0,0 +1,86 @@ +//===-- RISCVInstPrinter.cpp - Convert RISCV MCInst to asm syntax ---------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an RISCV MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "RISCVInstPrinter.h" +#include "MCTargetDesc/RISCVBaseInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +// Include the auto-generated portion of the assembly writer. +#define PRINT_ALIAS_INSTR +#include "RISCVGenAsmWriter.inc" + +static cl::opt<bool> +NoAliases("riscv-no-aliases", +            cl::desc("Disable the emission of assembler pseudo instructions"), +            cl::init(false), +            cl::Hidden); + +void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O, +                                 StringRef Annot, const MCSubtargetInfo &STI) { +  if (NoAliases || !printAliasInstr(MI, O)) +    printInstruction(MI, O); +  printAnnotation(O, Annot); +} + +void RISCVInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const { +  O << getRegisterName(RegNo); +} + +void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, +                                    raw_ostream &O, const char *Modifier) { +  assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); +  const MCOperand &MO = MI->getOperand(OpNo); + +  if (MO.isReg()) { +    printRegName(O, MO.getReg()); +    return; +  } + +  if (MO.isImm()) { +    O << MO.getImm(); +    return; +  } + +  assert(MO.isExpr() && "Unknown operand kind in printOperand"); +  MO.getExpr()->print(O, &MAI); +} + +void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo, +                                     raw_ostream &O) { +  unsigned FenceArg = MI->getOperand(OpNo).getImm(); +  if ((FenceArg & RISCVFenceField::I) != 0) +    O << 'i'; +  if ((FenceArg & RISCVFenceField::O) != 0) +    O << 'o'; +  if ((FenceArg & RISCVFenceField::R) != 0) +    O << 'r'; +  if ((FenceArg & RISCVFenceField::W) != 0) +    O << 'w'; +} + +void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo, +                                   raw_ostream &O) { +  auto FRMArg = +      static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm()); +  O << RISCVFPRndMode::roundingModeToString(FRMArg); +} diff --git a/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h b/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h new file mode 100644 index 000000000000..58f3f8410159 --- /dev/null +++ b/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h @@ -0,0 +1,48 @@ +//===-- RISCVInstPrinter.h - Convert RISCV MCInst to asm syntax ---*- C++ -*--// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a RISCV MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_INSTPRINTER_RISCVINSTPRINTER_H +#define LLVM_LIB_TARGET_RISCV_INSTPRINTER_RISCVINSTPRINTER_H + +#include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +class MCOperand; + +class RISCVInstPrinter : public MCInstPrinter { +public: +  RISCVInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, +                   const MCRegisterInfo &MRI) +      : MCInstPrinter(MAI, MII, MRI) {} + +  void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, +                 const MCSubtargetInfo &STI) override; +  void printRegName(raw_ostream &O, unsigned RegNo) const override; + +  void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, +                    const char *Modifier = nullptr); +  void printFenceArg(const MCInst *MI, unsigned OpNo, raw_ostream &O); +  void printFRMArg(const MCInst *MI, unsigned OpNo, raw_ostream &O); + +  // Autogenerated by tblgen. +  void printInstruction(const MCInst *MI, raw_ostream &O); +  bool printAliasInstr(const MCInst *MI, raw_ostream &O); +  void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, +                               unsigned PrintMethodIdx, raw_ostream &O); +  static const char *getRegisterName(unsigned RegNo, +                                     unsigned AltIdx = RISCV::ABIRegAltName); +}; +} + +#endif diff --git a/lib/Target/RISCV/LLVMBuild.txt b/lib/Target/RISCV/LLVMBuild.txt index 9ba5fec928f3..ab21565b0c2e 100644 --- a/lib/Target/RISCV/LLVMBuild.txt +++ b/lib/Target/RISCV/LLVMBuild.txt @@ -16,16 +16,20 @@  ;===------------------------------------------------------------------------===;  [common] -subdirectories = TargetInfo MCTargetDesc +subdirectories = AsmParser Disassembler InstPrinter TargetInfo MCTargetDesc  [component_0]  type = TargetGroup  name = RISCV  parent = Target +has_asmparser = 1 +has_asmprinter = 1 +has_disassembler = 1  [component_1]  type = Library  name = RISCVCodeGen  parent = RISCV -required_libraries = Core CodeGen RISCVInfo Support Target +required_libraries = AsmPrinter Core CodeGen MC RISCVAsmPrinter RISCVDesc +  RISCVInfo SelectionDAG Support Target  add_to_library_groups = RISCV diff --git a/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt b/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt index d79de74f7cfc..60429647edd1 100644 --- a/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_library(LLVMRISCVDesc    RISCVAsmBackend.cpp    RISCVELFObjectWriter.cpp    RISCVMCAsmInfo.cpp -  RISCVMCTargetDesc.cpp    RISCVMCCodeEmitter.cpp +  RISCVMCExpr.cpp +  RISCVMCTargetDesc.cpp  ) diff --git a/lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt b/lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt index e48f04963ff8..92daae30e3ff 100644 --- a/lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt +++ b/lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt @@ -19,5 +19,5 @@  type = Library  name = RISCVDesc  parent = RISCV -required_libraries = MC RISCVInfo Support +required_libraries = MC RISCVAsmPrinter RISCVInfo Support  add_to_library_groups = RISCV diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index be83efc02d27..b91467fe1455 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -7,9 +7,12 @@  //  //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVFixupKinds.h"  #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/ADT/APInt.h"  #include "llvm/MC/MCAsmBackend.h"  #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h"  #include "llvm/MC/MCDirectives.h"  #include "llvm/MC/MCELFObjectWriter.h"  #include "llvm/MC/MCExpr.h" @@ -36,7 +39,8 @@ public:                    const MCValue &Target, MutableArrayRef<char> Data,                    uint64_t Value, bool IsResolved) const override; -  MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; +  std::unique_ptr<MCObjectWriter> +  createObjectWriter(raw_pwrite_stream &OS) const override;    bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,                              const MCRelaxableFragment *DF, @@ -44,14 +48,40 @@ public:      return false;    } -  unsigned getNumFixupKinds() const override { return 1; } +  unsigned getNumFixupKinds() const override { +    return RISCV::NumTargetFixupKinds; +  } + +  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { +    const static MCFixupKindInfo Infos[RISCV::NumTargetFixupKinds] = { +      // This table *must* be in the order that the fixup_* kinds are defined in +      // RISCVFixupKinds.h. +      // +      // name                    offset bits  flags +      { "fixup_riscv_hi20",       12,     20,  0 }, +      { "fixup_riscv_lo12_i",     20,     12,  0 }, +      { "fixup_riscv_lo12_s",      0,     32,  0 }, +      { "fixup_riscv_pcrel_hi20", 12,     20,  MCFixupKindInfo::FKF_IsPCRel }, +      { "fixup_riscv_jal",        12,     20,  MCFixupKindInfo::FKF_IsPCRel }, +      { "fixup_riscv_branch",      0,     32,  MCFixupKindInfo::FKF_IsPCRel }, +      { "fixup_riscv_rvc_jump",    2,     11,  MCFixupKindInfo::FKF_IsPCRel }, +      { "fixup_riscv_rvc_branch",  0,     16,  MCFixupKindInfo::FKF_IsPCRel } +    }; + +    if (Kind < FirstTargetFixupKind) +      return MCAsmBackend::getFixupKindInfo(Kind); + +    assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && +           "Invalid kind!"); +    return Infos[Kind - FirstTargetFixupKind]; +  }    bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }    void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,                          MCInst &Res) const override { -    llvm_unreachable("RISCVAsmBackend::relaxInstruction() unimplemented"); +    report_fatal_error("RISCVAsmBackend::relaxInstruction() unimplemented");    }    bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; @@ -70,14 +100,129 @@ bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {    return true;  } +static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, +                                 MCContext &Ctx) { +  unsigned Kind = Fixup.getKind(); +  switch (Kind) { +  default: +    llvm_unreachable("Unknown fixup kind!"); +  case FK_Data_1: +  case FK_Data_2: +  case FK_Data_4: +  case FK_Data_8: +    return Value; +  case RISCV::fixup_riscv_lo12_i: +    return Value & 0xfff; +  case RISCV::fixup_riscv_lo12_s: +    return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); +  case RISCV::fixup_riscv_hi20: +  case RISCV::fixup_riscv_pcrel_hi20: +    // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. +    return ((Value + 0x800) >> 12) & 0xfffff; +  case RISCV::fixup_riscv_jal: { +    if (!isInt<21>(Value)) +      Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); +    if (Value & 0x1) +      Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); +    // Need to produce imm[19|10:1|11|19:12] from the 21-bit Value. +    unsigned Sbit = (Value >> 20) & 0x1; +    unsigned Hi8 = (Value >> 12) & 0xff; +    unsigned Mid1 = (Value >> 11) & 0x1; +    unsigned Lo10 = (Value >> 1) & 0x3ff; +    // Inst{31} = Sbit; +    // Inst{30-21} = Lo10; +    // Inst{20} = Mid1; +    // Inst{19-12} = Hi8; +    Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8; +    return Value; +  } +  case RISCV::fixup_riscv_branch: { +    if (!isInt<13>(Value)) +      Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); +    if (Value & 0x1) +      Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); +    // Need to extract imm[12], imm[10:5], imm[4:1], imm[11] from the 13-bit +    // Value. +    unsigned Sbit = (Value >> 12) & 0x1; +    unsigned Hi1 = (Value >> 11) & 0x1; +    unsigned Mid6 = (Value >> 5) & 0x3f; +    unsigned Lo4 = (Value >> 1) & 0xf; +    // Inst{31} = Sbit; +    // Inst{30-25} = Mid6; +    // Inst{11-8} = Lo4; +    // Inst{7} = Hi1; +    Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); +    return Value; +  } +  case RISCV::fixup_riscv_rvc_jump: { +    // Need to produce offset[11|4|9:8|10|6|7|3:1|5] from the 11-bit Value. +    unsigned Bit11  = (Value >> 11) & 0x1; +    unsigned Bit4   = (Value >> 4) & 0x1; +    unsigned Bit9_8 = (Value >> 8) & 0x3; +    unsigned Bit10  = (Value >> 10) & 0x1; +    unsigned Bit6   = (Value >> 6) & 0x1; +    unsigned Bit7   = (Value >> 7) & 0x1; +    unsigned Bit3_1 = (Value >> 1) & 0x7; +    unsigned Bit5   = (Value >> 5) & 0x1; +    Value = (Bit11 << 10) | (Bit4 << 9) | (Bit9_8 << 7) | (Bit10 << 6) | +            (Bit6 << 5) | (Bit7 << 4) | (Bit3_1 << 1) | Bit5; +    return Value; +  } +  case RISCV::fixup_riscv_rvc_branch: { +    // Need to produce offset[8|4:3], [reg 3 bit], offset[7:6|2:1|5] +    unsigned Bit8   = (Value >> 8) & 0x1; +    unsigned Bit7_6 = (Value >> 6) & 0x3; +    unsigned Bit5   = (Value >> 5) & 0x1; +    unsigned Bit4_3 = (Value >> 3) & 0x3; +    unsigned Bit2_1 = (Value >> 1) & 0x3; +    Value = (Bit8 << 12) | (Bit4_3 << 10) | (Bit7_6 << 5) | (Bit2_1 << 3) | +            (Bit5 << 2); +    return Value; +  } + +  } +} + +static unsigned getSize(unsigned Kind) { +  switch (Kind) { +  default: +    return 4; +  case RISCV::fixup_riscv_rvc_jump: +  case RISCV::fixup_riscv_rvc_branch: +    return 2; +  } +} +  void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,                                   const MCValue &Target,                                   MutableArrayRef<char> Data, uint64_t Value,                                   bool IsResolved) const { -  return; +  MCContext &Ctx = Asm.getContext(); +  MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); +  if (!Value) +    return; // Doesn't change encoding. +  // Apply any target-specific value adjustments. +  Value = adjustFixupValue(Fixup, Value, Ctx); + +  // Shift the value into position. +  Value <<= Info.TargetOffset; + +  unsigned Offset = Fixup.getOffset(); +  unsigned FullSize = getSize(Fixup.getKind()); + +#ifndef NDEBUG +  unsigned NumBytes = (Info.TargetSize + 7) / 8; +  assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); +#endif + +  // For each byte of the fragment that the fixup touches, mask in the +  // bits from the fixup value. +  for (unsigned i = 0; i != FullSize; ++i) { +    Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); +  }  } -MCObjectWriter * +std::unique_ptr<MCObjectWriter>  RISCVAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {    return createRISCVELFObjectWriter(OS, OSABI, Is64Bit);  } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h new file mode 100644 index 000000000000..b278a2ed3903 --- /dev/null +++ b/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -0,0 +1,110 @@ +//===-- RISCVBaseInfo.h - Top level definitions for RISCV MC ----*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone enum definitions for the RISCV target +// useful for the compiler back-end and the MC libraries. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H + +#include "RISCVMCTargetDesc.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +namespace llvm { + +// RISCVII - This namespace holds all of the target specific flags that +// instruction info tracks. All definitions must match RISCVInstrFormats.td. +namespace RISCVII { +enum { +  InstFormatPseudo = 0, +  InstFormatR = 1, +  InstFormatR4 = 2, +  InstFormatI = 3, +  InstFormatS = 4, +  InstFormatB = 5, +  InstFormatU = 6, +  InstFormatJ = 7, +  InstFormatCR = 8, +  InstFormatCI = 9, +  InstFormatCSS = 10, +  InstFormatCIW = 11, +  InstFormatCL = 12, +  InstFormatCS = 13, +  InstFormatCB = 14, +  InstFormatCJ = 15, +  InstFormatOther = 16, + +  InstFormatMask = 31 +}; + +enum { +  MO_None, +  MO_LO, +  MO_HI, +  MO_PCREL_HI, +}; +} // namespace RISCVII + +// Describes the predecessor/successor bits used in the FENCE instruction. +namespace RISCVFenceField { +enum FenceField { +  I = 8, +  O = 4, +  R = 2, +  W = 1 +}; +} + +// Describes the supported floating point rounding mode encodings. +namespace RISCVFPRndMode { +enum RoundingMode { +  RNE = 0, +  RTZ = 1, +  RDN = 2, +  RUP = 3, +  RMM = 4, +  DYN = 7, +  Invalid +}; + +inline static StringRef roundingModeToString(RoundingMode RndMode) { +  switch (RndMode) { +  default: +    llvm_unreachable("Unknown floating point rounding mode"); +  case RISCVFPRndMode::RNE: +    return "rne"; +  case RISCVFPRndMode::RTZ: +    return "rtz"; +  case RISCVFPRndMode::RDN: +    return "rdn"; +  case RISCVFPRndMode::RUP: +    return "rup"; +  case RISCVFPRndMode::RMM: +    return "rmm"; +  case RISCVFPRndMode::DYN: +    return "dyn"; +  } +} + +inline static RoundingMode stringToRoundingMode(StringRef Str) { +  return StringSwitch<RoundingMode>(Str) +      .Case("rne", RISCVFPRndMode::RNE) +      .Case("rtz", RISCVFPRndMode::RTZ) +      .Case("rdn", RISCVFPRndMode::RDN) +      .Case("rup", RISCVFPRndMode::RUP) +      .Case("rmm", RISCVFPRndMode::RMM) +      .Case("dyn", RISCVFPRndMode::DYN) +      .Default(RISCVFPRndMode::Invalid); +} +} // namespace RISCVFPRndMode +} // namespace llvm + +#endif diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index 4f085d31a267..ad53228c104a 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -7,9 +7,11 @@  //  //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVFixupKinds.h"  #include "MCTargetDesc/RISCVMCTargetDesc.h"  #include "llvm/MC/MCELFObjectWriter.h"  #include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h"  #include "llvm/Support/ErrorHandling.h"  using namespace llvm; @@ -29,7 +31,7 @@ protected:  RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)      : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV, -                              /*HasRelocationAddend*/ false) {} +                              /*HasRelocationAddend*/ true) {}  RISCVELFObjectWriter::~RISCVELFObjectWriter() {} @@ -37,11 +39,37 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,                                              const MCValue &Target,                                              const MCFixup &Fixup,                                              bool IsPCRel) const { -  llvm_unreachable("invalid fixup kind!"); +  // Determine the type of the relocation +  switch ((unsigned)Fixup.getKind()) { +  default: +    llvm_unreachable("invalid fixup kind!"); +  case FK_Data_4: +    return ELF::R_RISCV_32; +  case FK_Data_8: +    return ELF::R_RISCV_64; +  case RISCV::fixup_riscv_hi20: +    return ELF::R_RISCV_HI20; +  case RISCV::fixup_riscv_lo12_i: +    return ELF::R_RISCV_LO12_I; +  case RISCV::fixup_riscv_lo12_s: +    return ELF::R_RISCV_LO12_S; +  case RISCV::fixup_riscv_pcrel_hi20: +    return ELF::R_RISCV_PCREL_HI20; +  case RISCV::fixup_riscv_jal: +    return ELF::R_RISCV_JAL; +  case RISCV::fixup_riscv_branch: +    return ELF::R_RISCV_BRANCH; +  case RISCV::fixup_riscv_rvc_jump: +    return ELF::R_RISCV_RVC_JUMP; +  case RISCV::fixup_riscv_rvc_branch: +    return ELF::R_RISCV_RVC_BRANCH; +  }  } -MCObjectWriter *llvm::createRISCVELFObjectWriter(raw_pwrite_stream &OS, -                                                 uint8_t OSABI, bool Is64Bit) { -  MCELFObjectTargetWriter *MOTW = new RISCVELFObjectWriter(OSABI, Is64Bit); -  return createELFObjectWriter(MOTW, OS, /*IsLittleEndian*/ true); +std::unique_ptr<MCObjectWriter> +llvm::createRISCVELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI, +                                 bool Is64Bit) { +  return createELFObjectWriter( +      llvm::make_unique<RISCVELFObjectWriter>(OSABI, Is64Bit), OS, +      /*IsLittleEndian=*/true);  } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h new file mode 100644 index 000000000000..cfb5d99e79f5 --- /dev/null +++ b/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -0,0 +1,52 @@ +//===-- RISCVFixupKinds.h - RISCV Specific Fixup Entries --------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVFIXUPKINDS_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +#undef RISCV + +namespace llvm { +namespace RISCV { +enum Fixups { +  // fixup_riscv_hi20 - 20-bit fixup corresponding to hi(foo) for +  // instructions like lui +  fixup_riscv_hi20 = FirstTargetFixupKind, +  // fixup_riscv_lo12_i - 12-bit fixup corresponding to lo(foo) for +  // instructions like addi +  fixup_riscv_lo12_i, +  // fixup_riscv_lo12_s - 12-bit fixup corresponding to lo(foo) for +  // the S-type store instructions +  fixup_riscv_lo12_s, +  // fixup_riscv_pcrel_hi20 - 20-bit fixup corresponding to pcrel_hi(foo) for +  // instructions like auipc +  fixup_riscv_pcrel_hi20, +  // fixup_riscv_jal - 20-bit fixup for symbol references in the jal +  // instruction +  fixup_riscv_jal, +  // fixup_riscv_branch - 12-bit fixup for symbol references in the branch +  // instructions +  fixup_riscv_branch, +  // fixup_riscv_rvc_jump - 11-bit fixup for symbol references in the +  // compressed jump instruction +  fixup_riscv_rvc_jump, +  // fixup_riscv_rvc_branch - 8-bit fixup for symbol references in the +  // compressed branch instruction +  fixup_riscv_rvc_branch, + +  // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup +  fixup_riscv_invalid, +  NumTargetFixupKinds = fixup_riscv_invalid - FirstTargetFixupKind +}; +} // end namespace RISCV +} // end namespace llvm + +#endif diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index 9309d493cef4..641997e67e06 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -11,6 +11,9 @@  //  //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVFixupKinds.h" +#include "MCTargetDesc/RISCVMCExpr.h"  #include "MCTargetDesc/RISCVMCTargetDesc.h"  #include "llvm/ADT/Statistic.h"  #include "llvm/MC/MCAsmInfo.h" @@ -18,8 +21,10 @@  #include "llvm/MC/MCContext.h"  #include "llvm/MC/MCExpr.h"  #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h"  #include "llvm/MC/MCRegisterInfo.h"  #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h"  #include "llvm/Support/EndianStream.h"  #include "llvm/Support/raw_ostream.h" @@ -28,15 +33,18 @@ using namespace llvm;  #define DEBUG_TYPE "mccodeemitter"  STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); +STATISTIC(MCNumFixups, "Number of MC fixups created");  namespace {  class RISCVMCCodeEmitter : public MCCodeEmitter {    RISCVMCCodeEmitter(const RISCVMCCodeEmitter &) = delete;    void operator=(const RISCVMCCodeEmitter &) = delete;    MCContext &Ctx; +  MCInstrInfo const &MCII;  public: -  RISCVMCCodeEmitter(MCContext &ctx) : Ctx(ctx) {} +  RISCVMCCodeEmitter(MCContext &ctx, MCInstrInfo const &MCII) +      : Ctx(ctx), MCII(MCII) {}    ~RISCVMCCodeEmitter() override {} @@ -55,21 +63,45 @@ public:    unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,                               SmallVectorImpl<MCFixup> &Fixups,                               const MCSubtargetInfo &STI) const; + +  unsigned getImmOpValueAsr1(const MCInst &MI, unsigned OpNo, +                             SmallVectorImpl<MCFixup> &Fixups, +                             const MCSubtargetInfo &STI) const; + +  unsigned getImmOpValue(const MCInst &MI, unsigned OpNo, +                         SmallVectorImpl<MCFixup> &Fixups, +                         const MCSubtargetInfo &STI) const;  };  } // end anonymous namespace  MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII,                                                const MCRegisterInfo &MRI,                                                MCContext &Ctx) { -  return new RISCVMCCodeEmitter(Ctx); +  return new RISCVMCCodeEmitter(Ctx, MCII);  }  void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,                                             SmallVectorImpl<MCFixup> &Fixups,                                             const MCSubtargetInfo &STI) const { -  // For now, we only support RISC-V instructions with 32-bit length -  uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); -  support::endian::Writer<support::little>(OS).write(Bits); +  const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); +  // Get byte count of instruction. +  unsigned Size = Desc.getSize(); + +  switch (Size) { +  default: +    llvm_unreachable("Unhandled encodeInstruction length!"); +  case 2: { +    uint16_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); +    support::endian::Writer<support::little>(OS).write<uint16_t>(Bits); +    break; +  } +  case 4: { +    uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); +    support::endian::Writer<support::little>(OS).write(Bits); +    break; +  } +  } +    ++MCNumEmitted; // Keep track of the # of mi's emitted.  } @@ -88,4 +120,77 @@ RISCVMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,    return 0;  } +unsigned +RISCVMCCodeEmitter::getImmOpValueAsr1(const MCInst &MI, unsigned OpNo, +                                      SmallVectorImpl<MCFixup> &Fixups, +                                      const MCSubtargetInfo &STI) const { +  const MCOperand &MO = MI.getOperand(OpNo); + +  if (MO.isImm()) { +    unsigned Res = MO.getImm(); +    assert((Res & 1) == 0 && "LSB is non-zero"); +    return Res >> 1; +  } + +  return getImmOpValue(MI, OpNo, Fixups, STI); +} + +unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, +                                           SmallVectorImpl<MCFixup> &Fixups, +                                           const MCSubtargetInfo &STI) const { + +  const MCOperand &MO = MI.getOperand(OpNo); + +  MCInstrDesc const &Desc = MCII.get(MI.getOpcode()); +  unsigned MIFrm = Desc.TSFlags & RISCVII::InstFormatMask; + +  // If the destination is an immediate, there is nothing to do +  if (MO.isImm()) +    return MO.getImm(); + +  assert(MO.isExpr() && +         "getImmOpValue expects only expressions or immediates"); +  const MCExpr *Expr = MO.getExpr(); +  MCExpr::ExprKind Kind = Expr->getKind(); +  RISCV::Fixups FixupKind = RISCV::fixup_riscv_invalid; +  if (Kind == MCExpr::Target) { +    const RISCVMCExpr *RVExpr = cast<RISCVMCExpr>(Expr); + +    switch (RVExpr->getKind()) { +    case RISCVMCExpr::VK_RISCV_None: +    case RISCVMCExpr::VK_RISCV_Invalid: +      llvm_unreachable("Unhandled fixup kind!"); +    case RISCVMCExpr::VK_RISCV_LO: +      FixupKind = MIFrm == RISCVII::InstFormatI ? RISCV::fixup_riscv_lo12_i +                                                : RISCV::fixup_riscv_lo12_s; +      break; +    case RISCVMCExpr::VK_RISCV_HI: +      FixupKind = RISCV::fixup_riscv_hi20; +      break; +    case RISCVMCExpr::VK_RISCV_PCREL_HI: +      FixupKind = RISCV::fixup_riscv_pcrel_hi20; +      break; +    } +  } else if (Kind == MCExpr::SymbolRef && +             cast<MCSymbolRefExpr>(Expr)->getKind() == MCSymbolRefExpr::VK_None) { +    if (Desc.getOpcode() == RISCV::JAL) { +      FixupKind = RISCV::fixup_riscv_jal; +    } else if (MIFrm == RISCVII::InstFormatB) { +      FixupKind = RISCV::fixup_riscv_branch; +    } else if (MIFrm == RISCVII::InstFormatCJ) { +      FixupKind = RISCV::fixup_riscv_rvc_jump; +    } else if (MIFrm == RISCVII::InstFormatCB) { +      FixupKind = RISCV::fixup_riscv_rvc_branch; +    } +  } + +  assert(FixupKind != RISCV::fixup_riscv_invalid && "Unhandled expression!"); + +  Fixups.push_back( +      MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc())); +  ++MCNumFixups; + +  return 0; +} +  #include "RISCVGenMCCodeEmitter.inc" diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp new file mode 100644 index 000000000000..b36236ea155f --- /dev/null +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -0,0 +1,99 @@ +//===-- RISCVMCExpr.cpp - RISCV specific MC expression classes ------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the assembly expression modifiers +// accepted by the RISCV architecture (e.g. ":lo12:", ":gottprel_g1:", ...). +// +//===----------------------------------------------------------------------===// + +#include "RISCVMCExpr.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscvmcexpr" + +const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind, +                                       MCContext &Ctx) { +  return new (Ctx) RISCVMCExpr(Expr, Kind); +} + +void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { +  bool HasVariant = getKind() != VK_RISCV_None; +  if (HasVariant) +    OS << '%' << getVariantKindName(getKind()) << '('; +  Expr->print(OS, MAI); +  if (HasVariant) +    OS << ')'; +} + +bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, +                                            const MCAsmLayout *Layout, +                                            const MCFixup *Fixup) const { +  return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); +} + +void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const { +  Streamer.visitUsedExpr(*getSubExpr()); +} + +RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) { +  return StringSwitch<RISCVMCExpr::VariantKind>(name) +      .Case("lo", VK_RISCV_LO) +      .Case("hi", VK_RISCV_HI) +      .Case("pcrel_hi", VK_RISCV_PCREL_HI) +      .Default(VK_RISCV_Invalid); +} + +StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { +  switch (Kind) { +  default: +    llvm_unreachable("Invalid ELF symbol kind"); +  case VK_RISCV_LO: +    return "lo"; +  case VK_RISCV_HI: +    return "hi"; +  case VK_RISCV_PCREL_HI: +    return "pcrel_hi"; +  } +} + +bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { +  MCValue Value; + +  if (Kind == VK_RISCV_PCREL_HI) +    return false; + +  if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) +    return false; + +  if (!Value.isAbsolute()) +    return false; + +  Res = evaluateAsInt64(Value.getConstant()); +  return true; +} + +int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const { +  switch (Kind) { +  default: +    llvm_unreachable("Invalid kind"); +  case VK_RISCV_LO: +    return SignExtend64<12>(Value); +  case VK_RISCV_HI: +    // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. +    return ((Value + 0x800) >> 12) & 0xfffff; +  } +} diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h new file mode 100644 index 000000000000..69b55ca6f7cd --- /dev/null +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -0,0 +1,75 @@ +//===-- RISCVMCExpr.h - RISCV specific MC expression classes ----*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes RISCV-specific MCExprs, used for modifiers like +// "%hi" or "%lo" etc., +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCEXPR_H +#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCEXPR_H + +#include "llvm/MC/MCExpr.h" + +namespace llvm { + +class StringRef; +class RISCVMCExpr : public MCTargetExpr { +public: +  enum VariantKind { +    VK_RISCV_None, +    VK_RISCV_LO, +    VK_RISCV_HI, +    VK_RISCV_PCREL_HI, +    VK_RISCV_Invalid +  }; + +private: +  const MCExpr *Expr; +  const VariantKind Kind; + +  int64_t evaluateAsInt64(int64_t Value) const; + +  explicit RISCVMCExpr(const MCExpr *Expr, VariantKind Kind) +      : Expr(Expr), Kind(Kind) {} + +public: +  static const RISCVMCExpr *create(const MCExpr *Expr, VariantKind Kind, +                                   MCContext &Ctx); + +  VariantKind getKind() const { return Kind; } + +  const MCExpr *getSubExpr() const { return Expr; } + +  void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; +  bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, +                                 const MCFixup *Fixup) const override; +  void visitUsedExpr(MCStreamer &Streamer) const override; +  MCFragment *findAssociatedFragment() const override { +    return getSubExpr()->findAssociatedFragment(); +  } + +  // There are no TLS RISCVMCExprs at the moment. +  void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + +  bool evaluateAsConstant(int64_t &Res) const; + +  static bool classof(const MCExpr *E) { +    return E->getKind() == MCExpr::Target; +  } + +  static bool classof(const RISCVMCExpr *) { return true; } + +  static VariantKind getVariantKindForName(StringRef name); +  static StringRef getVariantKindName(VariantKind Kind); +}; + +} // end namespace llvm. + +#endif diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp index 41be0a2084b3..45de976ec6c2 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "RISCVMCTargetDesc.h" +#include "InstPrinter/RISCVInstPrinter.h"  #include "RISCVMCAsmInfo.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/MC/MCAsmInfo.h" @@ -28,6 +29,9 @@  #define GET_REGINFO_MC_DESC  #include "RISCVGenRegisterInfo.inc" +#define GET_SUBTARGETINFO_MC_DESC +#include "RISCVGenSubtargetInfo.inc" +  using namespace llvm;  static MCInstrInfo *createRISCVMCInstrInfo() { @@ -38,7 +42,7 @@ static MCInstrInfo *createRISCVMCInstrInfo() {  static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) {    MCRegisterInfo *X = new MCRegisterInfo(); -  InitRISCVMCRegisterInfo(X, RISCV::X1_32); +  InitRISCVMCRegisterInfo(X, RISCV::X1);    return X;  } @@ -47,6 +51,22 @@ static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI,    return new RISCVMCAsmInfo(TT);  } +static MCSubtargetInfo *createRISCVMCSubtargetInfo(const Triple &TT, +                                                   StringRef CPU, StringRef FS) { +  std::string CPUName = CPU; +  if (CPUName.empty()) +    CPUName = TT.isArch64Bit() ? "generic-rv64" : "generic-rv32"; +  return createRISCVMCSubtargetInfoImpl(TT, CPUName, FS); +} + +static MCInstPrinter *createRISCVMCInstPrinter(const Triple &T, +                                               unsigned SyntaxVariant, +                                               const MCAsmInfo &MAI, +                                               const MCInstrInfo &MII, +                                               const MCRegisterInfo &MRI) { +  return new RISCVInstPrinter(MAI, MII, MRI); +} +  extern "C" void LLVMInitializeRISCVTargetMC() {    for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) {      TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); @@ -54,5 +74,7 @@ extern "C" void LLVMInitializeRISCVTargetMC() {      TargetRegistry::RegisterMCRegInfo(*T, createRISCVMCRegisterInfo);      TargetRegistry::RegisterMCAsmBackend(*T, createRISCVAsmBackend);      TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter); +    TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter); +    TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);    }  } diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h index 7c98b1c8f321..bea2f8800fa6 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h @@ -17,6 +17,7 @@  #include "llvm/Config/config.h"  #include "llvm/MC/MCTargetOptions.h"  #include "llvm/Support/DataTypes.h" +#include <memory>  namespace llvm {  class MCAsmBackend; @@ -43,8 +44,8 @@ MCAsmBackend *createRISCVAsmBackend(const Target &T, const MCRegisterInfo &MRI,                                      const Triple &TT, StringRef CPU,                                      const MCTargetOptions &Options); -MCObjectWriter *createRISCVELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI, -                                           bool Is64Bit); +std::unique_ptr<MCObjectWriter> +createRISCVELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI, bool Is64Bit);  }  // Defines symbolic names for RISC-V registers. @@ -55,4 +56,7 @@ MCObjectWriter *createRISCVELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI,  #define GET_INSTRINFO_ENUM  #include "RISCVGenInstrInfo.inc" +#define GET_SUBTARGETINFO_ENUM +#include "RISCVGenSubtargetInfo.inc" +  #endif diff --git a/lib/Target/RISCV/RISCV.h b/lib/Target/RISCV/RISCV.h new file mode 100644 index 000000000000..884cb2e5014d --- /dev/null +++ b/lib/Target/RISCV/RISCV.h @@ -0,0 +1,37 @@ +//===-- RISCV.h - Top-level interface for RISCV -----------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in the LLVM +// RISC-V back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCV_H +#define LLVM_LIB_TARGET_RISCV_RISCV_H + +#include "MCTargetDesc/RISCVBaseInfo.h" + +namespace llvm { +class RISCVTargetMachine; +class AsmPrinter; +class FunctionPass; +class MCInst; +class MCOperand; +class MachineInstr; +class MachineOperand; + +void LowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, +                                    const AsmPrinter &AP); +bool LowerRISCVMachineOperandToMCOperand(const MachineOperand &MO, +                                         MCOperand &MCOp, const AsmPrinter &AP); + +FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM); +} + +#endif diff --git a/lib/Target/RISCV/RISCV.td b/lib/Target/RISCV/RISCV.td index 14838309a1bf..c74d560b2e03 100644 --- a/lib/Target/RISCV/RISCV.td +++ b/lib/Target/RISCV/RISCV.td @@ -9,19 +9,82 @@  include "llvm/Target/Target.td" -include "RISCVRegisterInfo.td" -include "RISCVInstrInfo.td" +//===----------------------------------------------------------------------===// +// RISC-V subtarget features and instruction predicates. +//===----------------------------------------------------------------------===// + +def FeatureStdExtM +    : SubtargetFeature<"m", "HasStdExtM", "true", +                       "'M' (Integer Multiplication and Division)">; +def HasStdExtM : Predicate<"Subtarget->hasStdExtM()">, +                           AssemblerPredicate<"FeatureStdExtM">; + +def FeatureStdExtA +    : SubtargetFeature<"a", "HasStdExtA", "true", +                       "'A' (Atomic Instructions)">; +def HasStdExtA : Predicate<"Subtarget->hasStdExtA()">, +                           AssemblerPredicate<"FeatureStdExtA">; + +def FeatureStdExtF +    : SubtargetFeature<"f", "HasStdExtF", "true", +                       "'F' (Single-Precision Floating-Point)">; +def HasStdExtF : Predicate<"Subtarget->hasStdExtF()">, +                           AssemblerPredicate<"FeatureStdExtF">; +def FeatureStdExtD +    : SubtargetFeature<"d", "HasStdExtD", "true", +                       "'D' (Double-Precision Floating-Point)", +                       [FeatureStdExtF]>; +def HasStdExtD : Predicate<"Subtarget->hasStdExtD()">, +                           AssemblerPredicate<"FeatureStdExtD">; -def RISCVInstrInfo : InstrInfo; +def FeatureStdExtC +    : SubtargetFeature<"c", "HasStdExtC", "true", +                       "'C' (Compressed Instructions)">; +def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">, +                           AssemblerPredicate<"FeatureStdExtC">; -def Feature64Bit   : SubtargetFeature<"64bit", "HasRV64", "true", -                                      "Implements RV64">; + +def Feature64Bit +    : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; +def IsRV64 : Predicate<"Subtarget->is64Bit()">, +                       AssemblerPredicate<"Feature64Bit">; +def IsRV32 : Predicate<"!Subtarget->is64Bit()">, +                       AssemblerPredicate<"!Feature64Bit">; + +def RV64           : HwMode<"+64bit">; +def RV32           : HwMode<"-64bit">; + +//===----------------------------------------------------------------------===// +// Registers, calling conventions, instruction descriptions. +//===----------------------------------------------------------------------===// + +include "RISCVRegisterInfo.td" +include "RISCVCallingConv.td" +include "RISCVInstrInfo.td" + +//===----------------------------------------------------------------------===// +// RISC-V processors supported. +//===----------------------------------------------------------------------===//  def : ProcessorModel<"generic-rv32", NoSchedModel, []>;  def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit]>; +//===----------------------------------------------------------------------===// +// Define the RISC-V target. +//===----------------------------------------------------------------------===// + +def RISCVInstrInfo : InstrInfo { +  let guessInstructionProperties = 0; +} + +def RISCVAsmParser : AsmParser { +  let ShouldEmitMatchRegisterAltName = 1; +  let AllowDuplicateRegisterNames = 1; +} +  def RISCV : Target {    let InstructionSet = RISCVInstrInfo; +  let AssemblyParsers = [RISCVAsmParser];  } diff --git a/lib/Target/RISCV/RISCVAsmPrinter.cpp b/lib/Target/RISCV/RISCVAsmPrinter.cpp new file mode 100644 index 000000000000..4808e6c73c50 --- /dev/null +++ b/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -0,0 +1,72 @@ +//===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to the RISCV assembly language. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "InstPrinter/RISCVInstPrinter.h" +#include "RISCVTargetMachine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +namespace { +class RISCVAsmPrinter : public AsmPrinter { +public: +  explicit RISCVAsmPrinter(TargetMachine &TM, +                           std::unique_ptr<MCStreamer> Streamer) +      : AsmPrinter(TM, std::move(Streamer)) {} + +  StringRef getPassName() const override { return "RISCV Assembly Printer"; } + +  void EmitInstruction(const MachineInstr *MI) override; + +  bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, +                                   const MachineInstr *MI); + +  // Wrapper needed for tblgenned pseudo lowering. +  bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const { +    return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this); +  } +}; +} + +// Simple pseudo-instructions have their lowering (with expansion to real +// instructions) auto-generated. +#include "RISCVGenMCPseudoLowering.inc" + +void RISCVAsmPrinter::EmitInstruction(const MachineInstr *MI) { +  // Do any auto-generated pseudo lowerings. +  if (emitPseudoExpansionLowering(*OutStreamer, MI)) +    return; + +  MCInst TmpInst; +  LowerRISCVMachineInstrToMCInst(MI, TmpInst, *this); +  EmitToStreamer(*OutStreamer, TmpInst); +} + +// Force static initialization. +extern "C" void LLVMInitializeRISCVAsmPrinter() { +  RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target()); +  RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target()); +} diff --git a/lib/Target/RISCV/RISCVCallingConv.td b/lib/Target/RISCV/RISCVCallingConv.td new file mode 100644 index 000000000000..d2b17c64c9c2 --- /dev/null +++ b/lib/Target/RISCV/RISCVCallingConv.td @@ -0,0 +1,20 @@ +//===-- RISCVCallingConv.td - Calling Conventions RISCV ----*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This describes the calling conventions for the RISCV architecture. +// +//===----------------------------------------------------------------------===// + +// The RISC-V calling convention is handled with custom code in +// RISCVISelLowering.cpp (CC_RISCV). + +def CSR : CalleeSavedRegs<(add X1, X3, X4, X8, X9, (sequence "X%u", 18, 27))>; + +// Needed for implementation of RISCVRegisterInfo::getNoPreservedMask() +def CSR_NoRegs : CalleeSavedRegs<(add)>; diff --git a/lib/Target/RISCV/RISCVFrameLowering.cpp b/lib/Target/RISCV/RISCVFrameLowering.cpp new file mode 100644 index 000000000000..e9e003e63d59 --- /dev/null +++ b/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -0,0 +1,201 @@ +//===-- RISCVFrameLowering.cpp - RISCV Frame Information ------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the RISCV implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "RISCVFrameLowering.h" +#include "RISCVSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +using namespace llvm; + +bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const { return true; } + +// Determines the size of the frame and maximum call frame size. +void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { +  MachineFrameInfo &MFI = MF.getFrameInfo(); +  const RISCVRegisterInfo *RI = STI.getRegisterInfo(); + +  // Get the number of bytes to allocate from the FrameInfo. +  uint64_t FrameSize = MFI.getStackSize(); + +  // Get the alignment. +  uint64_t StackAlign = RI->needsStackRealignment(MF) ? MFI.getMaxAlignment() +                                                      : getStackAlignment(); + +  // Get the maximum call frame size of all the calls. +  uint64_t MaxCallFrameSize = MFI.getMaxCallFrameSize(); + +  // If we have dynamic alloca then MaxCallFrameSize needs to be aligned so +  // that allocations will be aligned. +  if (MFI.hasVarSizedObjects()) +    MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign); + +  // Update maximum call frame size. +  MFI.setMaxCallFrameSize(MaxCallFrameSize); + +  // Include call frame size in total. +  if (!(hasReservedCallFrame(MF) && MFI.adjustsStack())) +    FrameSize += MaxCallFrameSize; + +  // Make sure the frame is aligned. +  FrameSize = alignTo(FrameSize, StackAlign); + +  // Update frame info. +  MFI.setStackSize(FrameSize); +} + +void RISCVFrameLowering::adjustReg(MachineBasicBlock &MBB, +                                   MachineBasicBlock::iterator MBBI, +                                   const DebugLoc &DL, unsigned DestReg, +                                   unsigned SrcReg, int64_t Val, +                                   MachineInstr::MIFlag Flag) const { +  const RISCVInstrInfo *TII = STI.getInstrInfo(); + +  if (DestReg == SrcReg && Val == 0) +    return; + +  if (!isInt<12>(Val)) +    report_fatal_error("adjustReg cannot yet handle adjustments >12 bits"); + +  BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DestReg) +      .addReg(SrcReg) +      .addImm(Val) +      .setMIFlag(Flag); +} + +// Returns the register used to hold the frame pointer. +static unsigned getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; } + +// Returns the register used to hold the stack pointer. +static unsigned getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; } + +void RISCVFrameLowering::emitPrologue(MachineFunction &MF, +                                      MachineBasicBlock &MBB) const { +  assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); + +  if (!hasFP(MF)) { +    report_fatal_error( +        "emitPrologue doesn't support framepointer-less functions"); +  } + +  MachineFrameInfo &MFI = MF.getFrameInfo(); +  MachineBasicBlock::iterator MBBI = MBB.begin(); + +  unsigned FPReg = getFPReg(STI); +  unsigned SPReg = getSPReg(STI); + +  // Debug location must be unknown since the first debug location is used +  // to determine the end of the prologue. +  DebugLoc DL; + +  // Determine the correct frame layout +  determineFrameLayout(MF); + +  // FIXME (note copied from Lanai): This appears to be overallocating.  Needs +  // investigation. Get the number of bytes to allocate from the FrameInfo. +  uint64_t StackSize = MFI.getStackSize(); + +  // Early exit if there is no need to allocate on the stack +  if (StackSize == 0 && !MFI.adjustsStack()) +    return; + +  // Allocate space on the stack if necessary. +  adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); + +  // The frame pointer is callee-saved, and code has been generated for us to +  // save it to the stack. We need to skip over the storing of callee-saved +  // registers as the frame pointer must be modified after it has been saved +  // to the stack, not before. +  // FIXME: assumes exactly one instruction is used to save each callee-saved +  // register. +  const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); +  std::advance(MBBI, CSI.size()); + +  // Generate new FP. +  adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize, MachineInstr::FrameSetup); +} + +void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, +                                      MachineBasicBlock &MBB) const { +  if (!hasFP(MF)) { +    report_fatal_error( +        "emitEpilogue doesn't support framepointer-less functions"); +  } + +  MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); +  const RISCVRegisterInfo *RI = STI.getRegisterInfo(); +  MachineFrameInfo &MFI = MF.getFrameInfo(); +  DebugLoc DL = MBBI->getDebugLoc(); +  unsigned FPReg = getFPReg(STI); +  unsigned SPReg = getSPReg(STI); + +  // Skip to before the restores of callee-saved registers +  // FIXME: assumes exactly one instruction is used to restore each +  // callee-saved register. +  MachineBasicBlock::iterator LastFrameDestroy = MBBI; +  std::advance(LastFrameDestroy, -MFI.getCalleeSavedInfo().size()); + +  uint64_t StackSize = MFI.getStackSize(); + +  // Restore the stack pointer using the value of the frame pointer. Only +  // necessary if the stack pointer was modified, meaning the stack size is +  // unknown. +  if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { +    adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -StackSize, +              MachineInstr::FrameDestroy); +  } + +  // Deallocate stack +  adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); +} + +int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, +                                               int FI, +                                               unsigned &FrameReg) const { +  const MachineFrameInfo &MFI = MF.getFrameInfo(); +  const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); + +  // Callee-saved registers should be referenced relative to the stack +  // pointer (positive offset), otherwise use the frame pointer (negative +  // offset). +  const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); +  int MinCSFI = 0; +  int MaxCSFI = -1; + +  int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + +               MFI.getOffsetAdjustment(); + +  if (CSI.size()) { +    MinCSFI = CSI[0].getFrameIdx(); +    MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); +  } + +  FrameReg = RI->getFrameRegister(MF); +  if (FI >= MinCSFI && FI <= MaxCSFI) { +    FrameReg = RISCV::X2; +    Offset += MF.getFrameInfo().getStackSize(); +  } +  return Offset; +} + +void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, +                                              BitVector &SavedRegs, +                                              RegScavenger *RS) const { +  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); +  // TODO: Once frame pointer elimination is implemented, don't +  // unconditionally spill the frame pointer and return address. +  SavedRegs.set(RISCV::X1); +  SavedRegs.set(RISCV::X8); +} diff --git a/lib/Target/RISCV/RISCVFrameLowering.h b/lib/Target/RISCV/RISCVFrameLowering.h new file mode 100644 index 000000000000..d92bb70c76da --- /dev/null +++ b/lib/Target/RISCV/RISCVFrameLowering.h @@ -0,0 +1,57 @@ +//===-- RISCVFrameLowering.h - Define frame lowering for RISCV -*- C++ -*--===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements RISCV-specific bits of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVFRAMELOWERING_H +#define LLVM_LIB_TARGET_RISCV_RISCVFRAMELOWERING_H + +#include "llvm/CodeGen/TargetFrameLowering.h" + +namespace llvm { +class RISCVSubtarget; + +class RISCVFrameLowering : public TargetFrameLowering { +public: +  explicit RISCVFrameLowering(const RISCVSubtarget &STI) +      : TargetFrameLowering(StackGrowsDown, +                            /*StackAlignment=*/16, +                            /*LocalAreaOffset=*/0), +        STI(STI) {} + +  void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; +  void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + +  int getFrameIndexReference(const MachineFunction &MF, int FI, +                             unsigned &FrameReg) const override; + +  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, +                            RegScavenger *RS) const override; + +  bool hasFP(const MachineFunction &MF) const override; + +  MachineBasicBlock::iterator +  eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, +                                MachineBasicBlock::iterator MI) const override { +    return MBB.erase(MI); +  } + +protected: +  const RISCVSubtarget &STI; + +private: +  void determineFrameLayout(MachineFunction &MF) const; +  void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, +                 const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, +                 int64_t Val, MachineInstr::MIFlag Flag) const; +}; +} +#endif diff --git a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp new file mode 100644 index 000000000000..113a45ac7cc0 --- /dev/null +++ b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -0,0 +1,108 @@ +//===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the RISCV target. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "RISCVTargetMachine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "riscv-isel" + +// RISCV-specific code to select RISCV machine instructions for +// SelectionDAG operations. +namespace { +class RISCVDAGToDAGISel final : public SelectionDAGISel { +  const RISCVSubtarget *Subtarget; + +public: +  explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine) +      : SelectionDAGISel(TargetMachine) {} + +  StringRef getPassName() const override { +    return "RISCV DAG->DAG Pattern Instruction Selection"; +  } + +  bool runOnMachineFunction(MachineFunction &MF) override { +    Subtarget = &MF.getSubtarget<RISCVSubtarget>(); +    return SelectionDAGISel::runOnMachineFunction(MF); +  } + +  void Select(SDNode *Node) override; + +  bool SelectAddrFI(SDValue Addr, SDValue &Base); + +// Include the pieces autogenerated from the target description. +#include "RISCVGenDAGISel.inc" +}; +} + +void RISCVDAGToDAGISel::Select(SDNode *Node) { +  unsigned Opcode = Node->getOpcode(); +  MVT XLenVT = Subtarget->getXLenVT(); + +  // Dump information about the Node being selected. +  DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << "\n"); + +  // If we have a custom node, we have already selected +  if (Node->isMachineOpcode()) { +    DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); +    Node->setNodeId(-1); +    return; +  } + +  // Instruction Selection not handled by the auto-generated tablegen selection +  // should be handled here. +  EVT VT = Node->getValueType(0); +  if (Opcode == ISD::Constant && VT == XLenVT) { +    auto *ConstNode = cast<ConstantSDNode>(Node); +    // Materialize zero constants as copies from X0. This allows the coalescer +    // to propagate these into other instructions. +    if (ConstNode->isNullValue()) { +      SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node), +                                           RISCV::X0, XLenVT); +      ReplaceNode(Node, New.getNode()); +      return; +    } +  } +  if (Opcode == ISD::FrameIndex) { +    SDLoc DL(Node); +    SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT); +    int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex(); +    EVT VT = Node->getValueType(0); +    SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); +    ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm)); +    return; +  } + +  // Select the default instruction. +  SelectCode(Node); +} + +bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { +  if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) { +    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); +    return true; +  } +  return false; +} + +// This pass converts a legalized DAG into a RISCV-specific DAG, ready +// for instruction scheduling. +FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) { +  return new RISCVDAGToDAGISel(TM); +} diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp new file mode 100644 index 000000000000..7d32954936be --- /dev/null +++ b/lib/Target/RISCV/RISCVISelLowering.cpp @@ -0,0 +1,892 @@ +//===-- RISCVISelLowering.cpp - RISCV DAG Lowering Implementation  --------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that RISCV uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#include "RISCVISelLowering.h" +#include "RISCV.h" +#include "RISCVRegisterInfo.h" +#include "RISCVSubtarget.h" +#include "RISCVTargetMachine.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscv-lower" + +RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, +                                         const RISCVSubtarget &STI) +    : TargetLowering(TM), Subtarget(STI) { + +  MVT XLenVT = Subtarget.getXLenVT(); + +  // Set up the register classes. +  addRegisterClass(XLenVT, &RISCV::GPRRegClass); + +  // Compute derived properties from the register classes. +  computeRegisterProperties(STI.getRegisterInfo()); + +  setStackPointerRegisterToSaveRestore(RISCV::X2); + +  for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) +    setLoadExtAction(N, XLenVT, MVT::i1, Promote); + +  // TODO: add all necessary setOperationAction calls. +  setOperationAction(ISD::DYNAMIC_STACKALLOC, XLenVT, Expand); + +  setOperationAction(ISD::BR_JT, MVT::Other, Expand); +  setOperationAction(ISD::BR_CC, XLenVT, Expand); +  setOperationAction(ISD::SELECT, XLenVT, Custom); +  setOperationAction(ISD::SELECT_CC, XLenVT, Expand); + +  setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); +  setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + +  for (auto VT : {MVT::i1, MVT::i8, MVT::i16}) +    setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand); + +  setOperationAction(ISD::ADDC, XLenVT, Expand); +  setOperationAction(ISD::ADDE, XLenVT, Expand); +  setOperationAction(ISD::SUBC, XLenVT, Expand); +  setOperationAction(ISD::SUBE, XLenVT, Expand); + +  setOperationAction(ISD::SREM, XLenVT, Expand); +  setOperationAction(ISD::SDIVREM, XLenVT, Expand); +  setOperationAction(ISD::SDIV, XLenVT, Expand); +  setOperationAction(ISD::UREM, XLenVT, Expand); +  setOperationAction(ISD::UDIVREM, XLenVT, Expand); +  setOperationAction(ISD::UDIV, XLenVT, Expand); + +  setOperationAction(ISD::MUL, XLenVT, Expand); +  setOperationAction(ISD::SMUL_LOHI, XLenVT, Expand); +  setOperationAction(ISD::UMUL_LOHI, XLenVT, Expand); +  setOperationAction(ISD::MULHS, XLenVT, Expand); +  setOperationAction(ISD::MULHU, XLenVT, Expand); + +  setOperationAction(ISD::SHL_PARTS, XLenVT, Expand); +  setOperationAction(ISD::SRL_PARTS, XLenVT, Expand); +  setOperationAction(ISD::SRA_PARTS, XLenVT, Expand); + +  setOperationAction(ISD::ROTL, XLenVT, Expand); +  setOperationAction(ISD::ROTR, XLenVT, Expand); +  setOperationAction(ISD::BSWAP, XLenVT, Expand); +  setOperationAction(ISD::CTTZ, XLenVT, Expand); +  setOperationAction(ISD::CTLZ, XLenVT, Expand); +  setOperationAction(ISD::CTPOP, XLenVT, Expand); + +  setOperationAction(ISD::GlobalAddress, XLenVT, Custom); +  setOperationAction(ISD::BlockAddress, XLenVT, Custom); + +  setBooleanContents(ZeroOrOneBooleanContent); + +  // Function alignments (log2). +  setMinFunctionAlignment(3); +  setPrefFunctionAlignment(3); + +  // Effectively disable jump table generation. +  setMinimumJumpTableEntries(INT_MAX); +} + +// Changes the condition code and swaps operands if necessary, so the SetCC +// operation matches one of the comparisons supported directly in the RISC-V +// ISA. +static void normaliseSetCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) { +  switch (CC) { +  default: +    break; +  case ISD::SETGT: +  case ISD::SETLE: +  case ISD::SETUGT: +  case ISD::SETULE: +    CC = ISD::getSetCCSwappedOperands(CC); +    std::swap(LHS, RHS); +    break; +  } +} + +// Return the RISC-V branch opcode that matches the given DAG integer +// condition code. The CondCode must be one of those supported by the RISC-V +// ISA (see normaliseSetCC). +static unsigned getBranchOpcodeForIntCondCode(ISD::CondCode CC) { +  switch (CC) { +  default: +    llvm_unreachable("Unsupported CondCode"); +  case ISD::SETEQ: +    return RISCV::BEQ; +  case ISD::SETNE: +    return RISCV::BNE; +  case ISD::SETLT: +    return RISCV::BLT; +  case ISD::SETGE: +    return RISCV::BGE; +  case ISD::SETULT: +    return RISCV::BLTU; +  case ISD::SETUGE: +    return RISCV::BGEU; +  } +} + +SDValue RISCVTargetLowering::LowerOperation(SDValue Op, +                                            SelectionDAG &DAG) const { +  switch (Op.getOpcode()) { +  default: +    report_fatal_error("unimplemented operand"); +  case ISD::GlobalAddress: +    return lowerGlobalAddress(Op, DAG); +  case ISD::BlockAddress: +    return lowerBlockAddress(Op, DAG); +  case ISD::SELECT: +    return lowerSELECT(Op, DAG); +  } +} + +SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op, +                                                SelectionDAG &DAG) const { +  SDLoc DL(Op); +  EVT Ty = Op.getValueType(); +  GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); +  const GlobalValue *GV = N->getGlobal(); +  int64_t Offset = N->getOffset(); + +  if (isPositionIndependent() || Subtarget.is64Bit()) +    report_fatal_error("Unable to lowerGlobalAddress"); + +  SDValue GAHi = +    DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, RISCVII::MO_HI); +  SDValue GALo = +    DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, RISCVII::MO_LO); +  SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0); +  SDValue MNLo = +    SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0); +  return MNLo; +} + +SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op, +                                               SelectionDAG &DAG) const { +  SDLoc DL(Op); +  EVT Ty = Op.getValueType(); +  BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); +  const BlockAddress *BA = N->getBlockAddress(); +  int64_t Offset = N->getOffset(); + +  if (isPositionIndependent() || Subtarget.is64Bit()) +    report_fatal_error("Unable to lowerBlockAddress"); + +  SDValue BAHi = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_HI); +  SDValue BALo = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_LO); +  SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, BAHi), 0); +  SDValue MNLo = +    SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, BALo), 0); +  return MNLo; +} + +SDValue RISCVTargetLowering::lowerExternalSymbol(SDValue Op, +                                                 SelectionDAG &DAG) const { +  SDLoc DL(Op); +  EVT Ty = Op.getValueType(); +  ExternalSymbolSDNode *N = cast<ExternalSymbolSDNode>(Op); +  const char *Sym = N->getSymbol(); + +  // TODO: should also handle gp-relative loads. + +  if (isPositionIndependent() || Subtarget.is64Bit()) +    report_fatal_error("Unable to lowerExternalSymbol"); + +  SDValue GAHi = DAG.getTargetExternalSymbol(Sym, Ty, RISCVII::MO_HI); +  SDValue GALo = DAG.getTargetExternalSymbol(Sym, Ty, RISCVII::MO_LO); +  SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0); +  SDValue MNLo = +    SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0); +  return MNLo; +} + +SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const { +  SDValue CondV = Op.getOperand(0); +  SDValue TrueV = Op.getOperand(1); +  SDValue FalseV = Op.getOperand(2); +  SDLoc DL(Op); +  MVT XLenVT = Subtarget.getXLenVT(); + +  // If the result type is XLenVT and CondV is the output of a SETCC node +  // which also operated on XLenVT inputs, then merge the SETCC node into the +  // lowered RISCVISD::SELECT_CC to take advantage of the integer +  // compare+branch instructions. i.e.: +  // (select (setcc lhs, rhs, cc), truev, falsev) +  // -> (riscvisd::select_cc lhs, rhs, cc, truev, falsev) +  if (Op.getSimpleValueType() == XLenVT && CondV.getOpcode() == ISD::SETCC && +      CondV.getOperand(0).getSimpleValueType() == XLenVT) { +    SDValue LHS = CondV.getOperand(0); +    SDValue RHS = CondV.getOperand(1); +    auto CC = cast<CondCodeSDNode>(CondV.getOperand(2)); +    ISD::CondCode CCVal = CC->get(); + +    normaliseSetCC(LHS, RHS, CCVal); + +    SDValue TargetCC = DAG.getConstant(CCVal, DL, XLenVT); +    SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); +    SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV}; +    return DAG.getNode(RISCVISD::SELECT_CC, DL, VTs, Ops); +  } + +  // Otherwise: +  // (select condv, truev, falsev) +  // -> (riscvisd::select_cc condv, zero, setne, truev, falsev) +  SDValue Zero = DAG.getConstant(0, DL, XLenVT); +  SDValue SetNE = DAG.getConstant(ISD::SETNE, DL, XLenVT); + +  SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); +  SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV}; + +  return DAG.getNode(RISCVISD::SELECT_CC, DL, VTs, Ops); +} + +MachineBasicBlock * +RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, +                                                 MachineBasicBlock *BB) const { +  const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); +  DebugLoc DL = MI.getDebugLoc(); + +  assert(MI.getOpcode() == RISCV::Select_GPR_Using_CC_GPR && +         "Unexpected instr type to insert"); + +  // To "insert" a SELECT instruction, we actually have to insert the triangle +  // control-flow pattern.  The incoming instruction knows the destination vreg +  // to set, the condition code register to branch on, the true/false values to +  // select between, and the condcode to use to select the appropriate branch. +  // +  // We produce the following control flow: +  //     HeadMBB +  //     |  \ +  //     |  IfFalseMBB +  //     | / +  //    TailMBB +  const BasicBlock *LLVM_BB = BB->getBasicBlock(); +  MachineFunction::iterator I = ++BB->getIterator(); + +  MachineBasicBlock *HeadMBB = BB; +  MachineFunction *F = BB->getParent(); +  MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB); +  MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB); + +  F->insert(I, IfFalseMBB); +  F->insert(I, TailMBB); +  // Move all remaining instructions to TailMBB. +  TailMBB->splice(TailMBB->begin(), HeadMBB, +                  std::next(MachineBasicBlock::iterator(MI)), HeadMBB->end()); +  // Update machine-CFG edges by transferring all successors of the current +  // block to the new block which will contain the Phi node for the select. +  TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB); +  // Set the successors for HeadMBB. +  HeadMBB->addSuccessor(IfFalseMBB); +  HeadMBB->addSuccessor(TailMBB); + +  // Insert appropriate branch. +  unsigned LHS = MI.getOperand(1).getReg(); +  unsigned RHS = MI.getOperand(2).getReg(); +  auto CC = static_cast<ISD::CondCode>(MI.getOperand(3).getImm()); +  unsigned Opcode = getBranchOpcodeForIntCondCode(CC); + +  BuildMI(HeadMBB, DL, TII.get(Opcode)) +    .addReg(LHS) +    .addReg(RHS) +    .addMBB(TailMBB); + +  // IfFalseMBB just falls through to TailMBB. +  IfFalseMBB->addSuccessor(TailMBB); + +  // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ] +  BuildMI(*TailMBB, TailMBB->begin(), DL, TII.get(RISCV::PHI), +          MI.getOperand(0).getReg()) +      .addReg(MI.getOperand(4).getReg()) +      .addMBB(HeadMBB) +      .addReg(MI.getOperand(5).getReg()) +      .addMBB(IfFalseMBB); + +  MI.eraseFromParent(); // The pseudo instruction is gone now. +  return TailMBB; +} + +// Calling Convention Implementation. +// The expectations for frontend ABI lowering vary from target to target. +// Ideally, an LLVM frontend would be able to avoid worrying about many ABI +// details, but this is a longer term goal. For now, we simply try to keep the +// role of the frontend as simple and well-defined as possible. The rules can +// be summarised as: +// * Never split up large scalar arguments. We handle them here. +// * If a hardfloat calling convention is being used, and the struct may be +// passed in a pair of registers (fp+fp, int+fp), and both registers are +// available, then pass as two separate arguments. If either the GPRs or FPRs +// are exhausted, then pass according to the rule below. +// * If a struct could never be passed in registers or directly in a stack +// slot (as it is larger than 2*XLEN and the floating point rules don't +// apply), then pass it using a pointer with the byval attribute. +// * If a struct is less than 2*XLEN, then coerce to either a two-element +// word-sized array or a 2*XLEN scalar (depending on alignment). +// * The frontend can determine whether a struct is returned by reference or +// not based on its size and fields. If it will be returned by reference, the +// frontend must modify the prototype so a pointer with the sret annotation is +// passed as the first argument. This is not necessary for large scalar +// returns. +// * Struct return values and varargs should be coerced to structs containing +// register-size fields in the same situations they would be for fixed +// arguments. + +static const MCPhysReg ArgGPRs[] = { +  RISCV::X10, RISCV::X11, RISCV::X12, RISCV::X13, +  RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17 +}; + +// Pass a 2*XLEN argument that has been split into two XLEN values through +// registers or the stack as necessary. +static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1, +                                ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, +                                MVT ValVT2, MVT LocVT2, +                                ISD::ArgFlagsTy ArgFlags2) { +  unsigned XLenInBytes = XLen / 8; +  if (unsigned Reg = State.AllocateReg(ArgGPRs)) { +    // At least one half can be passed via register. +    State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg, +                                     VA1.getLocVT(), CCValAssign::Full)); +  } else { +    // Both halves must be passed on the stack, with proper alignment. +    unsigned StackAlign = std::max(XLenInBytes, ArgFlags1.getOrigAlign()); +    State.addLoc( +        CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(), +                            State.AllocateStack(XLenInBytes, StackAlign), +                            VA1.getLocVT(), CCValAssign::Full)); +    State.addLoc(CCValAssign::getMem( +        ValNo2, ValVT2, State.AllocateStack(XLenInBytes, XLenInBytes), LocVT2, +        CCValAssign::Full)); +    return false; +  } + +  if (unsigned Reg = State.AllocateReg(ArgGPRs)) { +    // The second half can also be passed via register. +    State.addLoc( +        CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full)); +  } else { +    // The second half is passed via the stack, without additional alignment. +    State.addLoc(CCValAssign::getMem( +        ValNo2, ValVT2, State.AllocateStack(XLenInBytes, XLenInBytes), LocVT2, +        CCValAssign::Full)); +  } + +  return false; +} + +// Implements the RISC-V calling convention. Returns true upon failure. +static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT, +                     CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, +                     CCState &State, bool IsFixed, bool IsRet) { +  unsigned XLen = DL.getLargestLegalIntTypeSizeInBits(); +  assert(XLen == 32 || XLen == 64); +  MVT XLenVT = XLen == 32 ? MVT::i32 : MVT::i64; +  assert(ValVT == XLenVT && "Unexpected ValVT"); +  assert(LocVT == XLenVT && "Unexpected LocVT"); +  assert(IsFixed && "Vararg support not yet implemented"); + +  // Any return value split in to more than two values can't be returned +  // directly. +  if (IsRet && ValNo > 1) +    return true; + +  SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs(); +  SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags = +      State.getPendingArgFlags(); + +  assert(PendingLocs.size() == PendingArgFlags.size() && +         "PendingLocs and PendingArgFlags out of sync"); + +  // Split arguments might be passed indirectly, so keep track of the pending +  // values. +  if (ArgFlags.isSplit() || !PendingLocs.empty()) { +    LocVT = XLenVT; +    LocInfo = CCValAssign::Indirect; +    PendingLocs.push_back( +        CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo)); +    PendingArgFlags.push_back(ArgFlags); +    if (!ArgFlags.isSplitEnd()) { +      return false; +    } +  } + +  // If the split argument only had two elements, it should be passed directly +  // in registers or on the stack. +  if (ArgFlags.isSplitEnd() && PendingLocs.size() <= 2) { +    assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()"); +    // Apply the normal calling convention rules to the first half of the +    // split argument. +    CCValAssign VA = PendingLocs[0]; +    ISD::ArgFlagsTy AF = PendingArgFlags[0]; +    PendingLocs.clear(); +    PendingArgFlags.clear(); +    return CC_RISCVAssign2XLen(XLen, State, VA, AF, ValNo, ValVT, LocVT, +                               ArgFlags); +  } + +  // Allocate to a register if possible, or else a stack slot. +  unsigned Reg = State.AllocateReg(ArgGPRs); +  unsigned StackOffset = Reg ? 0 : State.AllocateStack(XLen / 8, XLen / 8); + +  // If we reach this point and PendingLocs is non-empty, we must be at the +  // end of a split argument that must be passed indirectly. +  if (!PendingLocs.empty()) { +    assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()"); +    assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()"); + +    for (auto &It : PendingLocs) { +      if (Reg) +        It.convertToReg(Reg); +      else +        It.convertToMem(StackOffset); +      State.addLoc(It); +    } +    PendingLocs.clear(); +    PendingArgFlags.clear(); +    return false; +  } + +  assert(LocVT == XLenVT && "Expected an XLenVT at this stage"); + +  if (Reg) { +    State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); +  } else { +    State.addLoc( +        CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); +  } +  return false; +} + +void RISCVTargetLowering::analyzeInputArgs( +    MachineFunction &MF, CCState &CCInfo, +    const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet) const { +  unsigned NumArgs = Ins.size(); + +  for (unsigned i = 0; i != NumArgs; ++i) { +    MVT ArgVT = Ins[i].VT; +    ISD::ArgFlagsTy ArgFlags = Ins[i].Flags; + +    if (CC_RISCV(MF.getDataLayout(), i, ArgVT, ArgVT, CCValAssign::Full, +                 ArgFlags, CCInfo, /*IsRet=*/true, IsRet)) { +      DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " +                   << EVT(ArgVT).getEVTString() << '\n'); +      llvm_unreachable(nullptr); +    } +  } +} + +void RISCVTargetLowering::analyzeOutputArgs( +    MachineFunction &MF, CCState &CCInfo, +    const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet) const { +  unsigned NumArgs = Outs.size(); + +  for (unsigned i = 0; i != NumArgs; i++) { +    MVT ArgVT = Outs[i].VT; +    ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; + +    if (CC_RISCV(MF.getDataLayout(), i, ArgVT, ArgVT, CCValAssign::Full, +                 ArgFlags, CCInfo, Outs[i].IsFixed, IsRet)) { +      DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " +                   << EVT(ArgVT).getEVTString() << "\n"); +      llvm_unreachable(nullptr); +    } +  } +} + +// The caller is responsible for loading the full value if the argument is +// passed with CCValAssign::Indirect. +static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, +                                const CCValAssign &VA, const SDLoc &DL) { +  MachineFunction &MF = DAG.getMachineFunction(); +  MachineRegisterInfo &RegInfo = MF.getRegInfo(); +  EVT LocVT = VA.getLocVT(); +  SDValue Val; + +  unsigned VReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass); +  RegInfo.addLiveIn(VA.getLocReg(), VReg); +  Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); + +  switch (VA.getLocInfo()) { +  default: +    llvm_unreachable("Unexpected CCValAssign::LocInfo"); +  case CCValAssign::Full: +  case CCValAssign::Indirect: +    return Val; +  } +} + +// The caller is responsible for loading the full value if the argument is +// passed with CCValAssign::Indirect. +static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, +                                const CCValAssign &VA, const SDLoc &DL) { +  MachineFunction &MF = DAG.getMachineFunction(); +  MachineFrameInfo &MFI = MF.getFrameInfo(); +  EVT LocVT = VA.getLocVT(); +  EVT ValVT = VA.getValVT(); +  EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)); +  int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, +                                 VA.getLocMemOffset(), /*Immutable=*/true); +  SDValue FIN = DAG.getFrameIndex(FI, PtrVT); +  SDValue Val; + +  ISD::LoadExtType ExtType; +  switch (VA.getLocInfo()) { +  default: +    llvm_unreachable("Unexpected CCValAssign::LocInfo"); +  case CCValAssign::Full: +  case CCValAssign::Indirect: +    ExtType = ISD::NON_EXTLOAD; +    break; +  } +  Val = DAG.getExtLoad( +      ExtType, DL, LocVT, Chain, FIN, +      MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); +  return Val; +} + +// Transform physical registers into virtual registers. +SDValue RISCVTargetLowering::LowerFormalArguments( +    SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, +    const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, +    SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { + +  switch (CallConv) { +  default: +    report_fatal_error("Unsupported calling convention"); +  case CallingConv::C: +  case CallingConv::Fast: +    break; +  } + +  MachineFunction &MF = DAG.getMachineFunction(); +  MVT XLenVT = Subtarget.getXLenVT(); +  EVT PtrVT = getPointerTy(DAG.getDataLayout()); + +  if (IsVarArg) +    report_fatal_error("VarArg not supported"); + +  // Assign locations to all of the incoming arguments. +  SmallVector<CCValAssign, 16> ArgLocs; +  CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); +  analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false); + +  for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { +    CCValAssign &VA = ArgLocs[i]; +    assert(VA.getLocVT() == XLenVT && "Unhandled argument type"); +    SDValue ArgValue; +    if (VA.isRegLoc()) +      ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL); +    else +      ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); + +    if (VA.getLocInfo() == CCValAssign::Indirect) { +      // If the original argument was split and passed by reference (e.g. i128 +      // on RV32), we need to load all parts of it here (using the same +      // address). +      InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue, +                                   MachinePointerInfo())); +      unsigned ArgIndex = Ins[i].OrigArgIndex; +      assert(Ins[i].PartOffset == 0); +      while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) { +        CCValAssign &PartVA = ArgLocs[i + 1]; +        unsigned PartOffset = Ins[i + 1].PartOffset; +        SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, +                                      DAG.getIntPtrConstant(PartOffset, DL)); +        InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address, +                                     MachinePointerInfo())); +        ++i; +      } +      continue; +    } +    InVals.push_back(ArgValue); +  } +  return Chain; +} + +// Lower a call to a callseq_start + CALL + callseq_end chain, and add input +// and output parameter nodes. +SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, +                                       SmallVectorImpl<SDValue> &InVals) const { +  SelectionDAG &DAG = CLI.DAG; +  SDLoc &DL = CLI.DL; +  SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; +  SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; +  SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; +  SDValue Chain = CLI.Chain; +  SDValue Callee = CLI.Callee; +  CLI.IsTailCall = false; +  CallingConv::ID CallConv = CLI.CallConv; +  bool IsVarArg = CLI.IsVarArg; +  EVT PtrVT = getPointerTy(DAG.getDataLayout()); +  MVT XLenVT = Subtarget.getXLenVT(); + +  if (IsVarArg) { +    report_fatal_error("LowerCall with varargs not implemented"); +  } + +  MachineFunction &MF = DAG.getMachineFunction(); + +  // Analyze the operands of the call, assigning locations to each operand. +  SmallVector<CCValAssign, 16> ArgLocs; +  CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); +  analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false); + +  // Get a count of how many bytes are to be pushed on the stack. +  unsigned NumBytes = ArgCCInfo.getNextStackOffset(); + +  // Create local copies for byval args +  SmallVector<SDValue, 8> ByValArgs; +  for (unsigned i = 0, e = Outs.size(); i != e; ++i) { +    ISD::ArgFlagsTy Flags = Outs[i].Flags; +    if (!Flags.isByVal()) +      continue; + +    SDValue Arg = OutVals[i]; +    unsigned Size = Flags.getByValSize(); +    unsigned Align = Flags.getByValAlign(); + +    int FI = MF.getFrameInfo().CreateStackObject(Size, Align, /*isSS=*/false); +    SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); +    SDValue SizeNode = DAG.getConstant(Size, DL, XLenVT); + +    Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Align, +                          /*IsVolatile=*/false, +                          /*AlwaysInline=*/false, +                          /*isTailCall=*/false, MachinePointerInfo(), +                          MachinePointerInfo()); +    ByValArgs.push_back(FIPtr); +  } + +  Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); + +  // Copy argument values to their designated locations. +  SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; +  SmallVector<SDValue, 8> MemOpChains; +  SDValue StackPtr; +  for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) { +    CCValAssign &VA = ArgLocs[i]; +    SDValue ArgValue = OutVals[i]; +    ISD::ArgFlagsTy Flags = Outs[i].Flags; + +    // Promote the value if needed. +    // For now, only handle fully promoted and indirect arguments. +    switch (VA.getLocInfo()) { +    case CCValAssign::Full: +      break; +    case CCValAssign::Indirect: { +      // Store the argument in a stack slot and pass its address. +      SDValue SpillSlot = DAG.CreateStackTemporary(Outs[i].ArgVT); +      int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex(); +      MemOpChains.push_back( +          DAG.getStore(Chain, DL, ArgValue, SpillSlot, +                       MachinePointerInfo::getFixedStack(MF, FI))); +      // If the original argument was split (e.g. i128), we need +      // to store all parts of it here (and pass just one address). +      unsigned ArgIndex = Outs[i].OrigArgIndex; +      assert(Outs[i].PartOffset == 0); +      while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) { +        SDValue PartValue = OutVals[i + 1]; +        unsigned PartOffset = Outs[i + 1].PartOffset; +        SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, +                                      DAG.getIntPtrConstant(PartOffset, DL)); +        MemOpChains.push_back( +            DAG.getStore(Chain, DL, PartValue, Address, +                         MachinePointerInfo::getFixedStack(MF, FI))); +        ++i; +      } +      ArgValue = SpillSlot; +      break; +    } +    default: +      llvm_unreachable("Unknown loc info!"); +    } + +    // Use local copy if it is a byval arg. +    if (Flags.isByVal()) +      ArgValue = ByValArgs[j++]; + +    if (VA.isRegLoc()) { +      // Queue up the argument copies and emit them at the end. +      RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); +    } else { +      assert(VA.isMemLoc() && "Argument not register or memory"); + +      // Work out the address of the stack slot. +      if (!StackPtr.getNode()) +        StackPtr = DAG.getCopyFromReg(Chain, DL, RISCV::X2, PtrVT); +      SDValue Address = +          DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, +                      DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); + +      // Emit the store. +      MemOpChains.push_back( +          DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); +    } +  } + +  // Join the stores, which are independent of one another. +  if (!MemOpChains.empty()) +    Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); + +  SDValue Glue; + +  // Build a sequence of copy-to-reg nodes, chained and glued together. +  for (auto &Reg : RegsToPass) { +    Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); +    Glue = Chain.getValue(1); +  } + +  if (isa<GlobalAddressSDNode>(Callee)) { +    Callee = lowerGlobalAddress(Callee, DAG); +  } else if (isa<ExternalSymbolSDNode>(Callee)) { +    Callee = lowerExternalSymbol(Callee, DAG); +  } + +  // The first call operand is the chain and the second is the target address. +  SmallVector<SDValue, 8> Ops; +  Ops.push_back(Chain); +  Ops.push_back(Callee); + +  // Add argument registers to the end of the list so that they are +  // known live into the call. +  for (auto &Reg : RegsToPass) +    Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); + +  // Add a register mask operand representing the call-preserved registers. +  const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); +  const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); +  assert(Mask && "Missing call preserved mask for calling convention"); +  Ops.push_back(DAG.getRegisterMask(Mask)); + +  // Glue the call to the argument copies, if any. +  if (Glue.getNode()) +    Ops.push_back(Glue); + +  // Emit the call. +  SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); +  Chain = DAG.getNode(RISCVISD::CALL, DL, NodeTys, Ops); +  Glue = Chain.getValue(1); + +  // Mark the end of the call, which is glued to the call itself. +  Chain = DAG.getCALLSEQ_END(Chain, +                             DAG.getConstant(NumBytes, DL, PtrVT, true), +                             DAG.getConstant(0, DL, PtrVT, true), +                             Glue, DL); +  Glue = Chain.getValue(1); + +  // Assign locations to each value returned by this call. +  SmallVector<CCValAssign, 16> RVLocs; +  CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); +  analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true); + +  // Copy all of the result registers out of their specified physreg. +  for (auto &VA : RVLocs) { +    // Copy the value out, gluing the copy to the end of the call sequence. +    SDValue RetValue = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), +                                          VA.getLocVT(), Glue); +    Chain = RetValue.getValue(1); +    Glue = RetValue.getValue(2); + +    assert(VA.getLocInfo() == CCValAssign::Full && "Unknown loc info!"); +    InVals.push_back(RetValue); +  } + +  return Chain; +} + +bool RISCVTargetLowering::CanLowerReturn( +    CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, +    const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { +  SmallVector<CCValAssign, 16> RVLocs; +  CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); +  for (unsigned i = 0, e = Outs.size(); i != e; ++i) { +    MVT VT = Outs[i].VT; +    ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; +    if (CC_RISCV(MF.getDataLayout(), i, VT, VT, CCValAssign::Full, ArgFlags, +                 CCInfo, /*IsFixed=*/true, /*IsRet=*/true)) +      return false; +  } +  return true; +} + +SDValue +RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, +                                 bool IsVarArg, +                                 const SmallVectorImpl<ISD::OutputArg> &Outs, +                                 const SmallVectorImpl<SDValue> &OutVals, +                                 const SDLoc &DL, SelectionDAG &DAG) const { +  if (IsVarArg) { +    report_fatal_error("VarArg not supported"); +  } + +  // Stores the assignment of the return value to a location. +  SmallVector<CCValAssign, 16> RVLocs; + +  // Info about the registers and stack slot. +  CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, +                 *DAG.getContext()); + +  analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true); + +  SDValue Flag; +  SmallVector<SDValue, 4> RetOps(1, Chain); + +  // Copy the result values into the output registers. +  for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { +    SDValue Val = OutVals[i]; +    CCValAssign &VA = RVLocs[i]; +    assert(VA.isRegLoc() && "Can only return in registers!"); +    assert(VA.getLocInfo() == CCValAssign::Full && +           "Unexpected CCValAssign::LocInfo"); + +    Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Flag); + +    // Guarantee that all emitted copies are stuck together. +    Flag = Chain.getValue(1); +    RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); +  } + +  RetOps[0] = Chain; // Update chain. + +  // Add the flag if we have it. +  if (Flag.getNode()) { +    RetOps.push_back(Flag); +  } + +  return DAG.getNode(RISCVISD::RET_FLAG, DL, MVT::Other, RetOps); +} + +const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { +  switch ((RISCVISD::NodeType)Opcode) { +  case RISCVISD::FIRST_NUMBER: +    break; +  case RISCVISD::RET_FLAG: +    return "RISCVISD::RET_FLAG"; +  case RISCVISD::CALL: +    return "RISCVISD::CALL"; +  case RISCVISD::SELECT_CC: +    return "RISCVISD::SELECT_CC"; +  } +  return nullptr; +} diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h new file mode 100644 index 000000000000..9c5c7ca008c0 --- /dev/null +++ b/lib/Target/RISCV/RISCVISelLowering.h @@ -0,0 +1,84 @@ +//===-- RISCVISelLowering.h - RISCV DAG Lowering Interface ------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that RISCV uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVISELLOWERING_H +#define LLVM_LIB_TARGET_RISCV_RISCVISELLOWERING_H + +#include "RISCV.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/TargetLowering.h" + +namespace llvm { +class RISCVSubtarget; +namespace RISCVISD { +enum NodeType : unsigned { +  FIRST_NUMBER = ISD::BUILTIN_OP_END, +  RET_FLAG, +  CALL, +  SELECT_CC +}; +} + +class RISCVTargetLowering : public TargetLowering { +  const RISCVSubtarget &Subtarget; + +public: +  explicit RISCVTargetLowering(const TargetMachine &TM, +                               const RISCVSubtarget &STI); + +  // Provide custom lowering hooks for some operations. +  SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + +  // This method returns the name of a target specific DAG node. +  const char *getTargetNodeName(unsigned Opcode) const override; + +  MachineBasicBlock * +  EmitInstrWithCustomInserter(MachineInstr &MI, +                              MachineBasicBlock *BB) const override; + +private: +  void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, +                        const SmallVectorImpl<ISD::InputArg> &Ins, +                        bool IsRet) const; +  void analyzeOutputArgs(MachineFunction &MF, CCState &CCInfo, +                         const SmallVectorImpl<ISD::OutputArg> &Outs, +                         bool IsRet) const; +  // Lower incoming arguments, copy physregs into vregs +  SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, +                               bool IsVarArg, +                               const SmallVectorImpl<ISD::InputArg> &Ins, +                               const SDLoc &DL, SelectionDAG &DAG, +                               SmallVectorImpl<SDValue> &InVals) const override; +  bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, +                      bool IsVarArg, +                      const SmallVectorImpl<ISD::OutputArg> &Outs, +                      LLVMContext &Context) const override; +  SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, +                      const SmallVectorImpl<ISD::OutputArg> &Outs, +                      const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, +                      SelectionDAG &DAG) const override; +  SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, +                    SmallVectorImpl<SDValue> &InVals) const override; +  bool shouldConvertConstantLoadToIntImm(const APInt &Imm, +                                         Type *Ty) const override { +    return true; +  } +  SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; +  SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; +  SDValue lowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const; +  SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const; +}; +} + +#endif diff --git a/lib/Target/RISCV/RISCVInstrFormats.td b/lib/Target/RISCV/RISCVInstrFormats.td index 3fab7122f6f1..7479ffbc9532 100644 --- a/lib/Target/RISCV/RISCVInstrFormats.td +++ b/lib/Target/RISCV/RISCVInstrFormats.td @@ -25,9 +25,66 @@  //  //===----------------------------------------------------------------------===// -class RISCVInst<dag outs, dag ins, string asmstr, list<dag> pattern> +// Format specifies the encoding used by the instruction. This is used by +// RISCVMCCodeEmitter to determine which form of fixup to use. These +// definitions must be kept in-sync with RISCVBaseInfo.h. +class InstFormat<bits<5> val> { +  bits<5> Value = val; +} +def InstFormatPseudo : InstFormat<0>; +def InstFormatR      : InstFormat<1>; +def InstFormatR4     : InstFormat<2>; +def InstFormatI      : InstFormat<3>; +def InstFormatS      : InstFormat<4>; +def InstFormatB      : InstFormat<5>; +def InstFormatU      : InstFormat<6>; +def InstFormatJ      : InstFormat<7>; +def InstFormatCR     : InstFormat<8>; +def InstFormatCI     : InstFormat<9>; +def InstFormatCSS    : InstFormat<10>; +def InstFormatCIW    : InstFormat<11>; +def InstFormatCL     : InstFormat<12>; +def InstFormatCS     : InstFormat<13>; +def InstFormatCB     : InstFormat<14>; +def InstFormatCJ     : InstFormat<15>; +def InstFormatOther  : InstFormat<16>; + +// The following opcode names and match those given in Table 19.1 in the +// RISC-V User-level ISA specification ("RISC-V base opcode map"). +class RISCVOpcode<bits<7> val> { +  bits<7> Value = val; +} +def OPC_LOAD      : RISCVOpcode<0b0000011>; +def OPC_LOAD_FP   : RISCVOpcode<0b0000111>; +def OPC_MISC_MEM  : RISCVOpcode<0b0001111>; +def OPC_OP_IMM    : RISCVOpcode<0b0010011>; +def OPC_AUIPC     : RISCVOpcode<0b0010111>; +def OPC_OP_IMM_32 : RISCVOpcode<0b0011011>; +def OPC_STORE     : RISCVOpcode<0b0100011>; +def OPC_STORE_FP  : RISCVOpcode<0b0100111>; +def OPC_AMO       : RISCVOpcode<0b0101111>; +def OPC_OP        : RISCVOpcode<0b0110011>; +def OPC_LUI       : RISCVOpcode<0b0110111>; +def OPC_OP_32     : RISCVOpcode<0b0111011>; +def OPC_MADD      : RISCVOpcode<0b1000011>; +def OPC_MSUB      : RISCVOpcode<0b1000111>; +def OPC_NMSUB     : RISCVOpcode<0b1001011>; +def OPC_NMADD     : RISCVOpcode<0b1001111>; +def OPC_OP_FP     : RISCVOpcode<0b1010011>; +def OPC_BRANCH    : RISCVOpcode<0b1100011>; +def OPC_JALR      : RISCVOpcode<0b1100111>; +def OPC_JAL       : RISCVOpcode<0b1101111>; +def OPC_SYSTEM    : RISCVOpcode<0b1110011>; + +class RVInst<dag outs, dag ins, string opcodestr, string argstr, +             list<dag> pattern, InstFormat format>      : Instruction {    field bits<32> Inst; +  // SoftFail is a field the disassembler can use to provide a way for +  // instructions to not match without killing the whole decode process. It is +  // mainly used for ARM, but Tablegen expects this field to exist or it fails +  // to build the decode table. +  field bits<32> SoftFail = 0;    let Size = 4;    bits<7> Opcode = 0; @@ -38,20 +95,26 @@ class RISCVInst<dag outs, dag ins, string asmstr, list<dag> pattern>    dag OutOperandList = outs;    dag InOperandList = ins; -  let AsmString = asmstr; +  let AsmString = opcodestr # "\t" # argstr;    let Pattern = pattern; + +  let TSFlags{4-0} = format.Value;  }  // Pseudo instructions -class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, "", pattern> { +class Pseudo<dag outs, dag ins, list<dag> pattern> +    : RVInst<outs, ins, "", "", pattern, InstFormatPseudo> {    let isPseudo = 1;    let isCodeGenOnly = 1;  } -class FR<bits<7> funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins, -         string asmstr, list<dag> pattern> : RISCVInst<outs, ins, asmstr, pattern> -{ +// Instruction formats are listed in the order they appear in the RISC-V +// instruction set manual (R, I, S, B, U, J) with sub-formats (e.g. RVInstR4, +// RVInstRAtomic) sorted alphabetically. + +class RVInstR<bits<7> funct7, bits<3> funct3, RISCVOpcode opcode, dag outs, +              dag ins, string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatR> {    bits<5> rs2;    bits<5> rs1;    bits<5> rd; @@ -61,12 +124,64 @@ class FR<bits<7> funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins,    let Inst{19-15} = rs1;    let Inst{14-12} = funct3;    let Inst{11-7} = rd; -  let Opcode = opcode; +  let Opcode = opcode.Value; +} + +class RVInstR4<bits<2> funct2, RISCVOpcode opcode, dag outs, dag ins, +               string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatR4> { +  bits<5> rs3; +  bits<5> rs2; +  bits<5> rs1; +  bits<3> funct3; +  bits<5> rd; + +  let Inst{31-27} = rs3; +  let Inst{26-25} = funct2; +  let Inst{24-20} = rs2; +  let Inst{19-15} = rs1; +  let Inst{14-12} = funct3; +  let Inst{11-7} = rd; +  let Opcode = opcode.Value;  } -class FI<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, asmstr, pattern> -{ +class RVInstRAtomic<bits<5> funct5, bit aq, bit rl, bits<3> funct3, +                    RISCVOpcode opcode, dag outs, dag ins, string opcodestr, +                    string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatR> { +  bits<5> rs2; +  bits<5> rs1; +  bits<5> rd; + +  let Inst{31-27} = funct5; +  let Inst{26} = aq; +  let Inst{25} = rl; +  let Inst{24-20} = rs2; +  let Inst{19-15} = rs1; +  let Inst{14-12} = funct3; +  let Inst{11-7} = rd; +  let Opcode = opcode.Value; +} + +class RVInstRFrm<bits<7> funct7, RISCVOpcode opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatR> { +  bits<5> rs2; +  bits<5> rs1; +  bits<3> funct3; +  bits<5> rd; + +  let Inst{31-25} = funct7; +  let Inst{24-20} = rs2; +  let Inst{19-15} = rs1; +  let Inst{14-12} = funct3; +  let Inst{11-7} = rd; +  let Opcode = opcode.Value; +} + +class RVInstI<bits<3> funct3, RISCVOpcode opcode, dag outs, dag ins, +              string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {    bits<12> imm12;    bits<5> rs1;    bits<5> rd; @@ -75,12 +190,29 @@ class FI<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<    let Inst{19-15} = rs1;    let Inst{14-12} = funct3;    let Inst{11-7} = rd; -  let Opcode = opcode; +  let Opcode = opcode.Value; +} + +class RVInstIShift<bit arithshift, bits<3> funct3, RISCVOpcode opcode, +                   dag outs, dag ins, string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> { +  bits<6> shamt; +  bits<5> rs1; +  bits<5> rd; + +  let Inst{31} = 0; +  let Inst{30} = arithshift; +  let Inst{29-26} = 0; +  let Inst{25-20} = shamt; +  let Inst{19-15} = rs1; +  let Inst{14-12} = funct3; +  let Inst{11-7} = rd; +  let Opcode = opcode.Value;  } -class FI32Shift<bit arithshift, bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, asmstr, pattern> -{ +class RVInstIShiftW<bit arithshift, bits<3> funct3, RISCVOpcode opcode, +                    dag outs, dag ins, string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatI> {    bits<5> shamt;    bits<5> rs1;    bits<5> rd; @@ -92,12 +224,12 @@ class FI32Shift<bit arithshift, bits<3> funct3, bits<7> opcode, dag outs, dag in    let Inst{19-15} = rs1;    let Inst{14-12} = funct3;    let Inst{11-7} = rd; -  let Opcode = opcode; +  let Opcode = opcode.Value;  } -class FS<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, asmstr, pattern> -{ +class RVInstS<bits<3> funct3, RISCVOpcode opcode, dag outs, dag ins, +              string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatS> {    bits<12> imm12;    bits<5> rs2;    bits<5> rs1; @@ -107,12 +239,12 @@ class FS<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<    let Inst{19-15} = rs1;    let Inst{14-12} = funct3;    let Inst{11-7} = imm12{4-0}; -  let Opcode = opcode; +  let Opcode = opcode.Value;  } -class FSB<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, asmstr, pattern> -{ +class RVInstB<bits<3> funct3, RISCVOpcode opcode, dag outs, dag ins, +              string opcodestr, string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatB> {    bits<12> imm12;    bits<5> rs2;    bits<5> rs1; @@ -124,23 +256,23 @@ class FSB<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list    let Inst{14-12} = funct3;    let Inst{11-8} = imm12{3-0};    let Inst{7} = imm12{10}; -  let Opcode = opcode; +  let Opcode = opcode.Value;  } -class FU<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, asmstr, pattern> -{ +class RVInstU<RISCVOpcode opcode, dag outs, dag ins, string opcodestr, +              string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatU> {    bits<20> imm20;    bits<5> rd;    let Inst{31-12} = imm20;    let Inst{11-7} = rd; -  let Opcode = opcode; +  let Opcode = opcode.Value;  } -class FUJ<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern> -    : RISCVInst<outs, ins, asmstr, pattern> -{ +class RVInstJ<RISCVOpcode opcode, dag outs, dag ins, string opcodestr, +              string argstr> +    : RVInst<outs, ins, opcodestr, argstr, [], InstFormatJ> {    bits<20> imm20;    bits<5> rd; @@ -149,5 +281,5 @@ class FUJ<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>    let Inst{20} = imm20{10};    let Inst{19-12} = imm20{18-11};    let Inst{11-7} = rd; -  let Opcode = opcode; +  let Opcode = opcode.Value;  } diff --git a/lib/Target/RISCV/RISCVInstrFormatsC.td b/lib/Target/RISCV/RISCVInstrFormatsC.td new file mode 100644 index 000000000000..6abcbd7cc8a1 --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrFormatsC.td @@ -0,0 +1,147 @@ +//===-- RISCVInstrFormatsC.td - RISCV C Instruction Formats --*- tablegen -*-=// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file describes the RISC-V C extension instruction formats. +// +//===----------------------------------------------------------------------===// + +class RVInst16<dag outs, dag ins, string opcodestr, string argstr, +               list<dag> pattern, InstFormat format> +    : Instruction { +  field bits<16> Inst; +  // SoftFail is a field the disassembler can use to provide a way for +  // instructions to not match without killing the whole decode process. It is +  // mainly used for ARM, but Tablegen expects this field to exist or it fails +  // to build the decode table. +  field bits<16> SoftFail = 0; +  let Size = 2; + +  bits<2> Opcode = 0; + +  let Namespace = "RISCV"; + +  dag OutOperandList = outs; +  dag InOperandList = ins; +  let AsmString = opcodestr # "\t" # argstr; +  let Pattern = pattern; + +  let TSFlags{4-0} = format.Value; +} + +class RVInst16CR<bits<4> funct4, bits<2> opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCR> { +  bits<5> rs1; +  bits<5> rs2; + +  let Inst{15-12} = funct4; +  let Inst{11-7} = rs1; +  let Inst{6-2} = rs2; +  let Inst{1-0} = opcode; +} + +// The immediate value encoding differs for each instruction, so each subclass +// is responsible for setting the appropriate bits in the Inst field. +// The bits Inst{6-2} must be set for each instruction. +class RVInst16CI<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCI> { +  bits<10> imm; +  bits<5> rd; +  bits<5> rs1; + +  let Inst{15-13} = funct3; +  let Inst{12} = imm{5}; +  let Inst{11-7} = rd; +  let Inst{1-0} = opcode; +} + +// The immediate value encoding differs for each instruction, so each subclass +// is responsible for setting the appropriate bits in the Inst field. +// The bits Inst{12-7} must be set for each instruction. +class RVInst16CSS<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                  string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCSS> { +  bits<10> imm; +  bits<5> rs2; +  bits<5> rs1; + +  let Inst{15-13} = funct3; +  let Inst{6-2} = rs2; +  let Inst{1-0} = opcode; +} + +class RVInst16CIW<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                  string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCIW> { +  bits<10> imm; +  bits<3> rd; + +  let Inst{15-13} = funct3; +  let Inst{4-2} = rd; +  let Inst{1-0} = opcode; +} + +// The immediate value encoding differs for each instruction, so each subclass +// is responsible for setting the appropriate bits in the Inst field. +// The bits Inst{12-10} and Inst{6-5} must be set for each instruction. +class RVInst16CL<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCL> { +  bits<3> rd; +  bits<3> rs1; + +  let Inst{15-13} = funct3; +  let Inst{9-7} = rs1; +  let Inst{4-2} = rd; +  let Inst{1-0} = opcode; +} + +// The immediate value encoding differs for each instruction, so each subclass +// is responsible for setting the appropriate bits in the Inst field. +// The bits Inst{12-10} and Inst{6-5} must be set for each instruction. +class RVInst16CS<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCS> { +  bits<3> rs2; +  bits<3> rs1; + +  let Inst{15-13} = funct3; +  let Inst{9-7} = rs1; +  let Inst{4-2} = rs2; +  let Inst{1-0} = opcode; +} + +class RVInst16CB<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCB> { +  bits<9> imm; +  bits<3> rs1; + +  let Inst{15-13} = funct3; +  let Inst{9-7} = rs1; +  let Inst{1-0} = opcode; +} + +class RVInst16CJ<bits<3> funct3, bits<2> opcode, dag outs, dag ins, +                 string opcodestr, string argstr> +    : RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCJ> { +  bits<11> offset; + +  let Inst{15-13} = funct3; +  let Inst{12} = offset{10}; +  let Inst{11} = offset{3}; +  let Inst{10-9} = offset{8-7}; +  let Inst{8} = offset{9}; +  let Inst{7} = offset{5}; +  let Inst{6} = offset{6}; +  let Inst{5-3} = offset{2-0}; +  let Inst{2} = offset{4}; +  let Inst{1-0} = opcode; +} diff --git a/lib/Target/RISCV/RISCVInstrInfo.cpp b/lib/Target/RISCV/RISCVInstrInfo.cpp new file mode 100644 index 000000000000..186fe363edd9 --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -0,0 +1,77 @@ +//===-- RISCVInstrInfo.cpp - RISCV Instruction Information ------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the RISCV implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "RISCVInstrInfo.h" +#include "RISCV.h" +#include "RISCVSubtarget.h" +#include "RISCVTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "RISCVGenInstrInfo.inc" + +using namespace llvm; + +RISCVInstrInfo::RISCVInstrInfo() +    : RISCVGenInstrInfo(RISCV::ADJCALLSTACKDOWN, RISCV::ADJCALLSTACKUP) {} + +void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, +                                 MachineBasicBlock::iterator MBBI, +                                 const DebugLoc &DL, unsigned DstReg, +                                 unsigned SrcReg, bool KillSrc) const { +  assert(RISCV::GPRRegClass.contains(DstReg, SrcReg) && +         "Impossible reg-to-reg copy"); + +  BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg) +      .addReg(SrcReg, getKillRegState(KillSrc)) +      .addImm(0); +} + +void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, +                                         MachineBasicBlock::iterator I, +                                         unsigned SrcReg, bool IsKill, int FI, +                                         const TargetRegisterClass *RC, +                                         const TargetRegisterInfo *TRI) const { +  DebugLoc DL; +  if (I != MBB.end()) +    DL = I->getDebugLoc(); + +  if (RISCV::GPRRegClass.hasSubClassEq(RC)) +    BuildMI(MBB, I, DL, get(RISCV::SW)) +        .addReg(SrcReg, getKillRegState(IsKill)) +        .addFrameIndex(FI) +        .addImm(0); +  else +    llvm_unreachable("Can't store this register to stack slot"); +} + +void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, +                                          MachineBasicBlock::iterator I, +                                          unsigned DstReg, int FI, +                                          const TargetRegisterClass *RC, +                                          const TargetRegisterInfo *TRI) const { +  DebugLoc DL; +  if (I != MBB.end()) +    DL = I->getDebugLoc(); + +  if (RISCV::GPRRegClass.hasSubClassEq(RC)) +    BuildMI(MBB, I, DL, get(RISCV::LW), DstReg).addFrameIndex(FI).addImm(0); +  else +    llvm_unreachable("Can't load this register from stack slot"); +} diff --git a/lib/Target/RISCV/RISCVInstrInfo.h b/lib/Target/RISCV/RISCVInstrInfo.h new file mode 100644 index 000000000000..05c8378445cf --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfo.h @@ -0,0 +1,46 @@ +//===-- RISCVInstrInfo.h - RISCV Instruction Information --------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the RISCV implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVINSTRINFO_H +#define LLVM_LIB_TARGET_RISCV_RISCVINSTRINFO_H + +#include "RISCVRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "RISCVGenInstrInfo.inc" + +namespace llvm { + +class RISCVInstrInfo : public RISCVGenInstrInfo { + +public: +  RISCVInstrInfo(); + +  void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, +                   const DebugLoc &DL, unsigned DstReg, unsigned SrcReg, +                   bool KillSrc) const override; + +  void storeRegToStackSlot(MachineBasicBlock &MBB, +                           MachineBasicBlock::iterator MBBI, unsigned SrcReg, +                           bool IsKill, int FrameIndex, +                           const TargetRegisterClass *RC, +                           const TargetRegisterInfo *TRI) const override; + +  void loadRegFromStackSlot(MachineBasicBlock &MBB, +                            MachineBasicBlock::iterator MBBI, unsigned DstReg, +                            int FrameIndex, const TargetRegisterClass *RC, +                            const TargetRegisterInfo *TRI) const override; +}; +} +#endif diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td index 52530c2f136c..1aae2f39dbdd 100644 --- a/lib/Target/RISCV/RISCVInstrInfo.td +++ b/lib/Target/RISCV/RISCVInstrInfo.td @@ -13,22 +13,247 @@  include "RISCVInstrFormats.td" -def simm12 : Operand<i32>; +//===----------------------------------------------------------------------===// +// RISC-V specific DAG Nodes. +//===----------------------------------------------------------------------===// + +def SDT_RISCVCall         : SDTypeProfile<0, -1, [SDTCisVT<0, XLenVT>]>; +def SDT_RISCVCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, +                                            SDTCisVT<1, i32>]>; +def SDT_RISCVCallSeqEnd   : SDCallSeqEnd<[SDTCisVT<0, i32>, +                                          SDTCisVT<1, i32>]>; +def SDT_RISCVSelectCC     : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, +                                                 SDTCisSameAs<0, 4>, +                                                 SDTCisSameAs<4, 5>]>; + + +def Call         : SDNode<"RISCVISD::CALL", SDT_RISCVCall, +                          [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, +                           SDNPVariadic]>; +def CallSeqStart : SDNode<"ISD::CALLSEQ_START", SDT_RISCVCallSeqStart, +                          [SDNPHasChain, SDNPOutGlue]>; +def CallSeqEnd   : SDNode<"ISD::CALLSEQ_END", SDT_RISCVCallSeqEnd, +                          [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def RetFlag      : SDNode<"RISCVISD::RET_FLAG", SDTNone, +                          [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def SelectCC     : SDNode<"RISCVISD::SELECT_CC", SDT_RISCVSelectCC, +                          [SDNPInGlue]>; + +//===----------------------------------------------------------------------===// +// Operand and SDNode transformation definitions. +//===----------------------------------------------------------------------===// + +class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass { +  let Name = prefix # "Imm" # width # suffix; +  let RenderMethod = "addImmOperands"; +  let DiagnosticType = !strconcat("Invalid", Name); +} + +class SImmAsmOperand<int width, string suffix = ""> +    : ImmAsmOperand<"S", width, suffix> { +} + +class UImmAsmOperand<int width, string suffix = ""> +    : ImmAsmOperand<"U", width, suffix> { +} + +def FenceArg : AsmOperandClass { +  let Name = "FenceArg"; +  let RenderMethod = "addFenceArgOperands"; +  let DiagnosticType = "InvalidFenceArg"; +} + +def fencearg : Operand<XLenVT> { +  let ParserMatchClass = FenceArg; +  let PrintMethod = "printFenceArg"; +  let DecoderMethod = "decodeUImmOperand<4>"; +} + +def UImmLog2XLenAsmOperand : AsmOperandClass { +  let Name = "UImmLog2XLen"; +  let RenderMethod = "addImmOperands"; +  let DiagnosticType = "InvalidUImmLog2XLen"; +} + +def uimmlog2xlen : Operand<XLenVT>, ImmLeaf<XLenVT, [{ +  if (Subtarget->is64Bit()) +    return isUInt<6>(Imm); +  return isUInt<5>(Imm); +}]> { +  let ParserMatchClass = UImmLog2XLenAsmOperand; +  // TODO: should ensure invalid shamt is rejected when decoding. +  let DecoderMethod = "decodeUImmOperand<6>"; +} + +def uimm5 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]> { +  let ParserMatchClass = UImmAsmOperand<5>; +  let DecoderMethod = "decodeUImmOperand<5>"; +} -// As noted in RISCVRegisterInfo.td, the hope is that support for -// variable-sized register classes will mean that instruction definitions do -// not need to be duplicated for 32-bit and 64-bit register classes. For now -// we use 'GPR', which is 32-bit. When codegen for both RV32 and RV64 is -// added, we will need to duplicate instruction definitions unless a proposal -// like <http://lists.llvm.org/pipermail/llvm-dev/2016-September/105027.html> -// is adopted. +def simm12 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<12>(Imm);}]> { +  let ParserMatchClass = SImmAsmOperand<12>; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeSImmOperand<12>"; +} + +def uimm12 : Operand<XLenVT> { +  let ParserMatchClass = UImmAsmOperand<12>; +  let DecoderMethod = "decodeUImmOperand<12>"; +} + +// A 13-bit signed immediate where the least significant bit is zero. +def simm13_lsb0 : Operand<OtherVT> { +  let ParserMatchClass = SImmAsmOperand<13, "Lsb0">; +  let EncoderMethod = "getImmOpValueAsr1"; +  let DecoderMethod = "decodeSImmOperandAndLsl1<13>"; +} -class ALU_ri<bits<3> funct3, string OpcodeStr> : -      FI<funct3, 0b0010011, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), -         OpcodeStr#"\t$rd, $rs1, $imm12", []> -{ +def uimm20 : Operand<XLenVT> { +  let ParserMatchClass = UImmAsmOperand<20>; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeUImmOperand<20>";  } +// A 21-bit signed immediate where the least significant bit is zero. +def simm21_lsb0 : Operand<OtherVT> { +  let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; +  let EncoderMethod = "getImmOpValueAsr1"; +  let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; +} + +// A parameterized register class alternative to i32imm/i64imm from Target.td. +def ixlenimm : Operand<XLenVT>; + +// Standalone (codegen-only) immleaf patterns. +def simm32 : ImmLeaf<XLenVT, [{return isInt<32>(Imm);}]>; + +// Addressing modes. +// Necessary because a frameindex can't be matched directly in a pattern. +def AddrFI : ComplexPattern<iPTR, 1, "SelectAddrFI", [frameindex], []>; + +// Extract least significant 12 bits from an immediate value and sign extend +// them. +def LO12Sext : SDNodeXForm<imm, [{ +  return CurDAG->getTargetConstant(SignExtend64<12>(N->getZExtValue()), +                                   SDLoc(N), N->getValueType(0)); +}]>; + +// Extract the most significant 20 bits from an immediate value. Add 1 if bit +// 11 is 1, to compensate for the low 12 bits in the matching immediate addi +// or ld/st being negative. +def HI20 : SDNodeXForm<imm, [{ +  return CurDAG->getTargetConstant(((N->getZExtValue()+0x800) >> 12) & 0xfffff, +                                   SDLoc(N), N->getValueType(0)); +}]>; + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class BranchCC_rri<bits<3> funct3, string opcodestr> +    : RVInstB<funct3, OPC_BRANCH, (outs), +              (ins GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12), +              opcodestr, "$rs1, $rs2, $imm12"> { +  let isBranch = 1; +  let isTerminator = 1; +} + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class Load_ri<bits<3> funct3, string opcodestr> +    : RVInstI<funct3, OPC_LOAD, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), +              opcodestr, "$rd, ${imm12}(${rs1})">; + +// Operands for stores are in the order srcreg, base, offset rather than +// reflecting the order these fields are specified in the instruction +// encoding. +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class Store_rri<bits<3> funct3, string opcodestr> +    : RVInstS<funct3, OPC_STORE, (outs), +              (ins GPR:$rs2, GPR:$rs1, simm12:$imm12), +              opcodestr, "$rs2, ${imm12}(${rs1})">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class ALU_ri<bits<3> funct3, string opcodestr> +    : RVInstI<funct3, OPC_OP_IMM, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), +              opcodestr, "$rd, $rs1, $imm12">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class Shift_ri<bit arithshift, bits<3> funct3, string opcodestr> +    : RVInstIShift<arithshift, funct3, OPC_OP_IMM, (outs GPR:$rd), +                   (ins GPR:$rs1, uimmlog2xlen:$shamt), opcodestr, +                   "$rd, $rs1, $shamt">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class ALU_rr<bits<7> funct7, bits<3> funct3, string opcodestr> +    : RVInstR<funct7, funct3, OPC_OP, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), +              opcodestr, "$rd, $rs1, $rs2">; + +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in +class CSR_ir<bits<3> funct3, string opcodestr> +    : RVInstI<funct3, OPC_SYSTEM, (outs GPR:$rd), (ins uimm12:$imm12, GPR:$rs1), +              opcodestr, "$rd, $imm12, $rs1">; + +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in +class CSR_ii<bits<3> funct3, string opcodestr> +    : RVInstI<funct3, OPC_SYSTEM, (outs GPR:$rd), +              (ins uimm12:$imm12, uimm5:$rs1), +              opcodestr, "$rd, $imm12, $rs1">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class ShiftW_ri<bit arithshift, bits<3> funct3, string opcodestr> +    : RVInstIShiftW<arithshift, funct3, OPC_OP_IMM_32, (outs GPR:$rd), +                    (ins GPR:$rs1, uimm5:$shamt), opcodestr, +                    "$rd, $rs1, $shamt">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class ALUW_rr<bits<7> funct7, bits<3> funct3, string opcodestr> +    : RVInstR<funct7, funct3, OPC_OP_32, (outs GPR:$rd), +              (ins GPR:$rs1, GPR:$rs2), opcodestr, "$rd, $rs1, $rs2">; + +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in +class Priv<string opcodestr, bits<7> funct7> +    : RVInstR<funct7, 0b000, OPC_SYSTEM, (outs), (ins GPR:$rs1, GPR:$rs2), +              opcodestr, "">; + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { +def LUI : RVInstU<OPC_LUI, (outs GPR:$rd), (ins uimm20:$imm20), +                  "lui", "$rd, $imm20">; + +def AUIPC : RVInstU<OPC_AUIPC, (outs GPR:$rd), (ins uimm20:$imm20), +                    "auipc", "$rd, $imm20">; + +let isCall = 1 in +def JAL : RVInstJ<OPC_JAL, (outs GPR:$rd), (ins simm21_lsb0:$imm20), +                  "jal", "$rd, $imm20">; + +let isCall = 1 in +def JALR : RVInstI<0b000, OPC_JALR, (outs GPR:$rd), +                   (ins GPR:$rs1, simm12:$imm12), +                   "jalr", "$rd, $rs1, $imm12">; +} // hasSideEffects = 0, mayLoad = 0, mayStore = 0 + +def BEQ  : BranchCC_rri<0b000, "beq">; +def BNE  : BranchCC_rri<0b001, "bne">; +def BLT  : BranchCC_rri<0b100, "blt">; +def BGE  : BranchCC_rri<0b101, "bge">; +def BLTU : BranchCC_rri<0b110, "bltu">; +def BGEU : BranchCC_rri<0b111, "bgeu">; + +def LB  : Load_ri<0b000, "lb">; +def LH  : Load_ri<0b001, "lh">; +def LW  : Load_ri<0b010, "lw">; +def LBU : Load_ri<0b100, "lbu">; +def LHU : Load_ri<0b101, "lhu">; + +def SB : Store_rri<0b000, "sb">; +def SH : Store_rri<0b001, "sh">; +def SW : Store_rri<0b010, "sw">; +  def ADDI  : ALU_ri<0b000, "addi">;  def SLTI  : ALU_ri<0b010, "slti">;  def SLTIU : ALU_ri<0b011, "sltiu">; @@ -36,11 +261,9 @@ def XORI  : ALU_ri<0b100, "xori">;  def ORI   : ALU_ri<0b110, "ori">;  def ANDI  : ALU_ri<0b111, "andi">; -class ALU_rr<bits<7> funct7, bits<3> funct3, string OpcodeStr> : -      FR<funct7, funct3, 0b0110011, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), -         OpcodeStr#"\t$rd, $rs1, $rs2", []> -{ -} +def SLLI : Shift_ri<0, 0b001, "slli">; +def SRLI : Shift_ri<0, 0b101, "srli">; +def SRAI : Shift_ri<1, 0b101, "srai">;  def ADD  : ALU_rr<0b0000000, 0b000, "add">;  def SUB  : ALU_rr<0b0100000, 0b000, "sub">; @@ -53,3 +276,377 @@ def SRA  : ALU_rr<0b0100000, 0b101, "sra">;  def OR   : ALU_rr<0b0000000, 0b110, "or">;  def AND  : ALU_rr<0b0000000, 0b111, "and">; +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in { +def FENCE : RVInstI<0b000, OPC_MISC_MEM, (outs), +                    (ins fencearg:$pred, fencearg:$succ), +                    "fence", "$pred, $succ"> { +  bits<4> pred; +  bits<4> succ; + +  let rs1 = 0; +  let rd = 0; +  let imm12 = {0b0000,pred,succ}; +} + +def FENCE_I : RVInstI<0b001, OPC_MISC_MEM, (outs), (ins), "fence.i", ""> { +  let rs1 = 0; +  let rd = 0; +  let imm12 = 0; +} + +def ECALL : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ecall", ""> { +  let rs1 = 0; +  let rd = 0; +  let imm12 = 0; +} + +def EBREAK : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ebreak", ""> { +  let rs1 = 0; +  let rd = 0; +  let imm12 = 1; +} +} // hasSideEffects = 1, mayLoad = 0, mayStore = 0 + +def CSRRW : CSR_ir<0b001, "csrrw">; +def CSRRS : CSR_ir<0b010, "csrrs">; +def CSRRC : CSR_ir<0b011, "csrrc">; + +def CSRRWI : CSR_ii<0b101, "csrrwi">; +def CSRRSI : CSR_ii<0b110, "csrrsi">; +def CSRRCI : CSR_ii<0b111, "csrrci">; + +/// RV64I instructions + +let Predicates = [IsRV64] in { +def LWU   : Load_ri<0b110, "lwu">; +def LD    : Load_ri<0b011, "ld">; +def SD    : Store_rri<0b011, "sd">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def ADDIW : RVInstI<0b000, OPC_OP_IMM_32, (outs GPR:$rd), +                    (ins GPR:$rs1, simm12:$imm12), +                    "addiw", "$rd, $rs1, $imm12">; + +def SLLIW : ShiftW_ri<0, 0b001, "slliw">; +def SRLIW : ShiftW_ri<0, 0b101, "srliw">; +def SRAIW : ShiftW_ri<1, 0b101, "sraiw">; + +def ADDW  : ALUW_rr<0b0000000, 0b000, "addw">; +def SUBW  : ALUW_rr<0b0100000, 0b000, "subw">; +def SLLW  : ALUW_rr<0b0000000, 0b001, "sllw">; +def SRLW  : ALUW_rr<0b0000000, 0b101, "srlw">; +def SRAW  : ALUW_rr<0b0100000, 0b101, "sraw">; +} // Predicates = [IsRV64] + +//===----------------------------------------------------------------------===// +// Privileged instructions +//===----------------------------------------------------------------------===// + +let isBarrier = 1, isReturn = 1, isTerminator = 1 in { +def URET : Priv<"uret", 0b0000000> { +  let rd = 0; +  let rs1 = 0; +  let rs2 = 0b00010; +} + +def SRET : Priv<"sret", 0b0001000> { +  let rd = 0; +  let rs1 = 0; +  let rs2 = 0b00010; +} + +def MRET : Priv<"mret", 0b0011000> { +  let rd = 0; +  let rs1 = 0; +  let rs2 = 0b00010; +} +} // isBarrier = 1, isReturn = 1, isTerminator = 1 + +def WFI : Priv<"wfi", 0b0001000> { +  let rd = 0; +  let rs1 = 0; +  let rs2 = 0b00101; +} + +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in +def SFENCE_VMA : RVInstR<0b0001001, 0b000, OPC_SYSTEM, (outs), +                         (ins GPR:$rs1, GPR:$rs2), +                         "sfence.vma", "$rs1, $rs2"> { +  let rd = 0; +} + +//===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) +//===----------------------------------------------------------------------===// + +// TODO la +// TODO lb lh lw +// TODO RV64I: ld +// TODO sb sh sw +// TODO RV64I: sd + +def : InstAlias<"nop",           (ADDI      X0,      X0,       0)>; +// TODO li +def : InstAlias<"mv $rd, $rs",   (ADDI GPR:$rd, GPR:$rs,       0)>; +def : InstAlias<"not $rd, $rs",  (XORI GPR:$rd, GPR:$rs,      -1)>; +def : InstAlias<"neg $rd, $rs",  (SUB  GPR:$rd,      X0, GPR:$rs)>; + +let Predicates = [IsRV64] in { +def : InstAlias<"negw $rd, $rs",   (SUBW  GPR:$rd,      X0, GPR:$rs)>; +def : InstAlias<"sext.w $rd, $rs", (ADDIW GPR:$rd, GPR:$rs,       0)>; +} // Predicates = [IsRV64] + +def : InstAlias<"seqz $rd, $rs", (SLTIU GPR:$rd, GPR:$rs,       1)>; +def : InstAlias<"snez $rd, $rs", (SLTU  GPR:$rd,      X0, GPR:$rs)>; +def : InstAlias<"sltz $rd, $rs", (SLT   GPR:$rd, GPR:$rs,      X0)>; +def : InstAlias<"sgtz $rd, $rs", (SLT   GPR:$rd,      X0, GPR:$rs)>; + +def : InstAlias<"beqz $rs, $offset", +                (BEQ GPR:$rs,      X0, simm13_lsb0:$offset)>; +def : InstAlias<"bnez $rs, $offset", +                (BNE GPR:$rs,      X0, simm13_lsb0:$offset)>; +def : InstAlias<"blez $rs, $offset", +                (BGE      X0, GPR:$rs, simm13_lsb0:$offset)>; +def : InstAlias<"bgez $rs, $offset", +                (BGE GPR:$rs,      X0, simm13_lsb0:$offset)>; +def : InstAlias<"bltz $rs, $offset", +                (BLT GPR:$rs,      X0, simm13_lsb0:$offset)>; +def : InstAlias<"bgtz $rs, $offset", +                (BLT      X0, GPR:$rs, simm13_lsb0:$offset)>; + +// Always output the canonical mnemonic for the pseudo branch instructions. +// The GNU tools emit the canonical mnemonic for the branch pseudo instructions +// as well (e.g. "bgt" will be recognised by the assembler but never printed by +// objdump). Match this behaviour by setting a zero weight. +def : InstAlias<"bgt $rs, $rt, $offset", +                (BLT  GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>; +def : InstAlias<"ble $rs, $rt, $offset", +                (BGE  GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>; +def : InstAlias<"bgtu $rs, $rt, $offset", +                (BLTU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>; +def : InstAlias<"bleu $rs, $rt, $offset", +                (BGEU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>; + +// "ret" has more weight since "ret" and "jr" alias the same "jalr" instruction. +def : InstAlias<"j $offset",   (JAL  X0, simm21_lsb0:$offset)>; +def : InstAlias<"jal $offset", (JAL  X1, simm21_lsb0:$offset)>; +def : InstAlias<"jr $rs",      (JALR X0, GPR:$rs, 0)>; +def : InstAlias<"jalr $rs",    (JALR X1, GPR:$rs, 0)>; +def : InstAlias<"ret",         (JALR X0,      X1, 0), 2>; +// TODO call +// TODO tail + +def : InstAlias<"fence", (FENCE 0xF, 0xF)>; // 0xF == iorw + +// CSR Addresses: 0xC00 == cycle,  0xC01 == time,  0xC02 == instret +//                0xC80 == cycleh, 0xC81 == timeh, 0xC82 == instreth +def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, 0xC02, X0)>; +def : InstAlias<"rdcycle $rd",   (CSRRS GPR:$rd, 0xC00, X0)>; +def : InstAlias<"rdtime $rd",    (CSRRS GPR:$rd, 0xC01, X0)>; + +let Predicates = [IsRV32] in { +def : InstAlias<"rdinstreth $rd", (CSRRS GPR:$rd, 0xC82, X0)>; +def : InstAlias<"rdcycleh $rd",   (CSRRS GPR:$rd, 0xC80, X0)>; +def : InstAlias<"rdtimeh $rd",    (CSRRS GPR:$rd, 0xC81, X0)>; +} // Predicates = [IsRV32] + +def : InstAlias<"csrr $rd, $csr", (CSRRS GPR:$rd, uimm12:$csr,      X0)>; +def : InstAlias<"csrw $csr, $rs", (CSRRW      X0, uimm12:$csr, GPR:$rs)>; +def : InstAlias<"csrs $csr, $rs", (CSRRS      X0, uimm12:$csr, GPR:$rs)>; +def : InstAlias<"csrc $csr, $rs", (CSRRC      X0, uimm12:$csr, GPR:$rs)>; + +def : InstAlias<"csrwi $csr, $imm", (CSRRWI X0, uimm12:$csr, uimm5:$imm)>; +def : InstAlias<"csrsi $csr, $imm", (CSRRSI X0, uimm12:$csr, uimm5:$imm)>; +def : InstAlias<"csrci $csr, $imm", (CSRRCI X0, uimm12:$csr, uimm5:$imm)>; + +def : InstAlias<"sfence.vma",     (SFENCE_VMA      X0, X0)>; +def : InstAlias<"sfence.vma $rs", (SFENCE_VMA GPR:$rs, X0)>; + +//===----------------------------------------------------------------------===// +// Pseudo-instructions and codegen patterns +// +// Naming convention: For 'generic' pattern classes, we use the naming +// convention PatTy1Ty2. For pattern classes which offer a more complex +// expension, prefix the class name, e.g. BccPat. +//===----------------------------------------------------------------------===// + +/// Generic pattern classes + +class PatGprGpr<SDPatternOperator OpNode, RVInstR Inst> +    : Pat<(OpNode GPR:$rs1, GPR:$rs2), (Inst GPR:$rs1, GPR:$rs2)>; +class PatGprSimm12<SDPatternOperator OpNode, RVInstI Inst> +    : Pat<(OpNode GPR:$rs1, simm12:$imm12), (Inst GPR:$rs1, simm12:$imm12)>; +class PatGprUimmLog2XLen<SDPatternOperator OpNode, RVInstIShift Inst> +    : Pat<(OpNode GPR:$rs1, uimmlog2xlen:$shamt), +          (Inst GPR:$rs1, uimmlog2xlen:$shamt)>; + +/// Predicates + +def IsOrAdd: PatFrag<(ops node:$A, node:$B), (or node:$A, node:$B), [{ +  return isOrEquivalentToAdd(N); +}]>; + +/// Immediates + +def : Pat<(simm12:$imm), (ADDI X0, simm12:$imm)>; +// TODO: Add a pattern for immediates with all zeroes in the lower 12 bits. +def : Pat<(simm32:$imm), (ADDI (LUI (HI20 imm:$imm)), (LO12Sext imm:$imm))>; + +/// Simple arithmetic operations + +def : PatGprGpr<add, ADD>; +def : PatGprSimm12<add, ADDI>; +def : PatGprGpr<sub, SUB>; +def : PatGprGpr<or, OR>; +def : PatGprSimm12<or, ORI>; +def : PatGprGpr<and, AND>; +def : PatGprSimm12<and, ANDI>; +def : PatGprGpr<xor, XOR>; +def : PatGprSimm12<xor, XORI>; +def : PatGprGpr<shl, SLL>; +def : PatGprUimmLog2XLen<shl, SLLI>; +def : PatGprGpr<srl, SRL>; +def : PatGprUimmLog2XLen<srl, SRLI>; +def : PatGprGpr<sra, SRA>; +def : PatGprUimmLog2XLen<sra, SRAI>; + +/// FrameIndex calculations + +def : Pat<(add (i32 AddrFI:$Rs), simm12:$imm12), +          (ADDI (i32 AddrFI:$Rs), simm12:$imm12)>; +def : Pat<(IsOrAdd (i32 AddrFI:$Rs), simm12:$imm12), +          (ADDI (i32 AddrFI:$Rs), simm12:$imm12)>; + +/// Setcc + +def : PatGprGpr<setlt, SLT>; +def : PatGprSimm12<setlt, SLTI>; +def : PatGprGpr<setult, SLTU>; +def : PatGprSimm12<setult, SLTIU>; + +// Define pattern expansions for setcc operations that aren't directly +// handled by a RISC-V instruction. +def : Pat<(seteq GPR:$rs1, GPR:$rs2), (SLTIU (XOR GPR:$rs1, GPR:$rs2), 1)>; +def : Pat<(setne GPR:$rs1, GPR:$rs2), (SLTU X0, (XOR GPR:$rs1, GPR:$rs2))>; +def : Pat<(setugt GPR:$rs1, GPR:$rs2), (SLTU GPR:$rs2, GPR:$rs1)>; +def : Pat<(setuge GPR:$rs1, GPR:$rs2), (XORI (SLTU GPR:$rs1, GPR:$rs2), 1)>; +def : Pat<(setule GPR:$rs1, GPR:$rs2), (XORI (SLTU GPR:$rs2, GPR:$rs1), 1)>; +def : Pat<(setgt GPR:$rs1, GPR:$rs2), (SLT GPR:$rs2, GPR:$rs1)>; +def : Pat<(setge GPR:$rs1, GPR:$rs2), (XORI (SLT GPR:$rs1, GPR:$rs2), 1)>; +def : Pat<(setle GPR:$rs1, GPR:$rs2), (XORI (SLT GPR:$rs2, GPR:$rs1), 1)>; + +let usesCustomInserter = 1 in +def Select_GPR_Using_CC_GPR +    : Pseudo<(outs GPR:$dst), +             (ins GPR:$lhs, GPR:$rhs, ixlenimm:$imm, GPR:$src, GPR:$src2), +             [(set XLenVT:$dst, (SelectCC GPR:$lhs, GPR:$rhs, +              (XLenVT imm:$imm), GPR:$src, GPR:$src2))]>; + +/// Branches and jumps + +// Match `(brcond (CondOp ..), ..)` and lower to the appropriate RISC-V branch +// instruction. +class BccPat<PatFrag CondOp, RVInstB Inst> +    : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12), +          (Inst GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12)>; + +def : BccPat<seteq, BEQ>; +def : BccPat<setne, BNE>; +def : BccPat<setlt, BLT>; +def : BccPat<setge, BGE>; +def : BccPat<setult, BLTU>; +def : BccPat<setuge, BGEU>; + +class BccSwapPat<PatFrag CondOp, RVInst InstBcc> +    : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12), +          (InstBcc GPR:$rs2, GPR:$rs1, bb:$imm12)>; + +// Condition codes that don't have matching RISC-V branch instructions, but +// are trivially supported by swapping the two input operands +def : BccSwapPat<setgt, BLT>; +def : BccSwapPat<setle, BGE>; +def : BccSwapPat<setugt, BLTU>; +def : BccSwapPat<setule, BGEU>; + +// An extra pattern is needed for a brcond without a setcc (i.e. where the +// condition was calculated elsewhere). +def : Pat<(brcond GPR:$cond, bb:$imm12), (BNE GPR:$cond, X0, bb:$imm12)>; + +let isBarrier = 1, isBranch = 1, isTerminator = 1 in +def PseudoBR : Pseudo<(outs), (ins simm21_lsb0:$imm20), [(br bb:$imm20)]>, +               PseudoInstExpansion<(JAL X0, simm21_lsb0:$imm20)>; + +let isCall = 1, Defs=[X1] in +let isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in +def PseudoBRIND : Pseudo<(outs), (ins GPR:$rs1, simm12:$imm12), []>, +                  PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>; + +def : Pat<(brind GPR:$rs1), (PseudoBRIND GPR:$rs1, 0)>; +def : Pat<(brind (add GPR:$rs1, simm12:$imm12)), +          (PseudoBRIND GPR:$rs1, simm12:$imm12)>; + +let isCall = 1, Defs = [X1] in +def PseudoCALL : Pseudo<(outs), (ins GPR:$rs1), [(Call GPR:$rs1)]>, +                 PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; + +let isBarrier = 1, isReturn = 1, isTerminator = 1 in +def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>, +                PseudoInstExpansion<(JALR X0, X1, 0)>; + +/// Loads + +multiclass LdPat<PatFrag LoadOp, RVInst Inst> { +  def : Pat<(LoadOp GPR:$rs1), (Inst GPR:$rs1, 0)>; +  def : Pat<(LoadOp AddrFI:$rs1), (Inst AddrFI:$rs1, 0)>; +  def : Pat<(LoadOp (add GPR:$rs1, simm12:$imm12)), +            (Inst GPR:$rs1, simm12:$imm12)>; +  def : Pat<(LoadOp (add AddrFI:$rs1, simm12:$imm12)), +            (Inst AddrFI:$rs1, simm12:$imm12)>; +  def : Pat<(LoadOp (IsOrAdd AddrFI:$rs1, simm12:$imm12)), +            (Inst AddrFI:$rs1, simm12:$imm12)>; +} + +defm : LdPat<sextloadi8, LB>; +defm : LdPat<extloadi8, LB>; +defm : LdPat<sextloadi16, LH>; +defm : LdPat<extloadi16, LH>; +defm : LdPat<load, LW>; +defm : LdPat<zextloadi8, LBU>; +defm : LdPat<zextloadi16, LHU>; + +/// Stores + +multiclass StPat<PatFrag StoreOp, RVInst Inst> { +  def : Pat<(StoreOp GPR:$rs2, GPR:$rs1), (Inst GPR:$rs2, GPR:$rs1, 0)>; +  def : Pat<(StoreOp GPR:$rs2, AddrFI:$rs1), (Inst GPR:$rs2, AddrFI:$rs1, 0)>; +  def : Pat<(StoreOp GPR:$rs2, (add GPR:$rs1, simm12:$imm12)), +            (Inst GPR:$rs2, GPR:$rs1, simm12:$imm12)>; +  def : Pat<(StoreOp GPR:$rs2, (add AddrFI:$rs1, simm12:$imm12)), +            (Inst GPR:$rs2, AddrFI:$rs1, simm12:$imm12)>; +  def : Pat<(StoreOp GPR:$rs2, (IsOrAdd AddrFI:$rs1, simm12:$imm12)), +            (Inst GPR:$rs2, AddrFI:$rs1, simm12:$imm12)>; +} + +defm : StPat<truncstorei8, SB>; +defm : StPat<truncstorei16, SH>; +defm : StPat<store, SW>; + +/// Other pseudo-instructions + +// Pessimistically assume the stack pointer will be clobbered +let Defs = [X2], Uses = [X2] in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), +                              [(CallSeqStart timm:$amt1, timm:$amt2)]>; +def ADJCALLSTACKUP   : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), +                              [(CallSeqEnd timm:$amt1, timm:$amt2)]>; +} // Defs = [X2], Uses = [X2] + +//===----------------------------------------------------------------------===// +// Standard extensions +//===----------------------------------------------------------------------===// + +include "RISCVInstrInfoM.td" +include "RISCVInstrInfoA.td" +include "RISCVInstrInfoF.td" +include "RISCVInstrInfoD.td" +include "RISCVInstrInfoC.td" diff --git a/lib/Target/RISCV/RISCVInstrInfoA.td b/lib/Target/RISCV/RISCVInstrInfoA.td new file mode 100644 index 000000000000..33e863ba6a10 --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfoA.td @@ -0,0 +1,77 @@ +//===-- RISCVInstrInfoA.td - RISC-V 'A' instructions -------*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the RISC-V instructions from the standard 'A', Atomic +// Instructions extension. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction class templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class LR_r<bit aq, bit rl, bits<3> funct3, string opcodestr> +    : RVInstRAtomic<0b00010, aq, rl, funct3, OPC_AMO, +                    (outs GPR:$rd), (ins GPR:$rs1), +                    opcodestr, "$rd, (${rs1})"> { +  let rs2 = 0; +} + +multiclass LR_r_aq_rl<bits<3> funct3, string opcodestr> { +  def ""     : LR_r<0, 0, funct3, opcodestr>; +  def _AQ    : LR_r<1, 0, funct3, opcodestr # ".aq">; +  def _RL    : LR_r<0, 1, funct3, opcodestr # ".rl">; +  def _AQ_RL : LR_r<1, 1, funct3, opcodestr # ".aqrl">; +} + +let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in +class AMO_rr<bits<5> funct5, bit aq, bit rl, bits<3> funct3, string opcodestr> +    : RVInstRAtomic<funct5, aq, rl, funct3, OPC_AMO, +                    (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), +                    opcodestr, "$rd, $rs2, (${rs1})">; + +multiclass AMO_rr_aq_rl<bits<5> funct5, bits<3> funct3, string opcodestr> { +  def ""     : AMO_rr<funct5, 0, 0, funct3, opcodestr>; +  def _AQ    : AMO_rr<funct5, 1, 0, funct3, opcodestr # ".aq">; +  def _RL    : AMO_rr<funct5, 0, 1, funct3, opcodestr # ".rl">; +  def _AQ_RL : AMO_rr<funct5, 1, 1, funct3, opcodestr # ".aqrl">; +} + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtA] in { +defm LR_W       : LR_r_aq_rl<0b010, "lr.w">; +defm SC_W       : AMO_rr_aq_rl<0b00011, 0b010, "sc.w">; +defm AMOSWAP_W  : AMO_rr_aq_rl<0b00001, 0b010, "amoswap.w">; +defm AMOADD_W   : AMO_rr_aq_rl<0b00000, 0b010, "amoadd.w">; +defm AMOXOR_W   : AMO_rr_aq_rl<0b00100, 0b010, "amoxor.w">; +defm AMOAND_W   : AMO_rr_aq_rl<0b01100, 0b010, "amoand.w">; +defm AMOOR_W    : AMO_rr_aq_rl<0b01000, 0b010, "amoor.w">; +defm AMOMIN_W   : AMO_rr_aq_rl<0b10000, 0b010, "amomin.w">; +defm AMOMAX_W   : AMO_rr_aq_rl<0b10100, 0b010, "amomax.w">; +defm AMOMINU_W  : AMO_rr_aq_rl<0b11000, 0b010, "amominu.w">; +defm AMOMAXU_W  : AMO_rr_aq_rl<0b11100, 0b010, "amomaxu.w">; +} // Predicates = [HasStdExtA] + +let Predicates = [HasStdExtA, IsRV64] in { +defm LR_D       : LR_r_aq_rl<0b011, "lr.d">; +defm SC_D       : AMO_rr_aq_rl<0b00011, 0b011, "sc.d">; +defm AMOSWAP_D  : AMO_rr_aq_rl<0b00001, 0b011, "amoswap.d">; +defm AMOADD_D   : AMO_rr_aq_rl<0b00000, 0b011, "amoadd.d">; +defm AMOXOR_D   : AMO_rr_aq_rl<0b00100, 0b011, "amoxor.d">; +defm AMOAND_D   : AMO_rr_aq_rl<0b01100, 0b011, "amoand.d">; +defm AMOOR_D    : AMO_rr_aq_rl<0b01000, 0b011, "amoor.d">; +defm AMOMIN_D   : AMO_rr_aq_rl<0b10000, 0b011, "amomin.d">; +defm AMOMAX_D   : AMO_rr_aq_rl<0b10100, 0b011, "amomax.d">; +defm AMOMINU_D  : AMO_rr_aq_rl<0b11000, 0b011, "amominu.d">; +defm AMOMAXU_D  : AMO_rr_aq_rl<0b11100, 0b011, "amomaxu.d">; +} // Predicates = [HasStedExtA, IsRV64] diff --git a/lib/Target/RISCV/RISCVInstrInfoC.td b/lib/Target/RISCV/RISCVInstrInfoC.td new file mode 100644 index 000000000000..4ca52652086b --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfoC.td @@ -0,0 +1,419 @@ +//===- RISCVInstrInfoC.td - Compressed RISCV instructions -*- tblgen-*-----===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +include "RISCVInstrFormatsC.td" + +//===----------------------------------------------------------------------===// +// Operand definitions. +//===----------------------------------------------------------------------===// + +def UImmLog2XLenNonZeroAsmOperand : AsmOperandClass { +  let Name = "UImmLog2XLenNonZero"; +  let RenderMethod = "addImmOperands"; +  let DiagnosticType = "InvalidUImmLog2XLenNonZero"; +} + +def uimmlog2xlennonzero : Operand<XLenVT>, ImmLeaf<XLenVT, [{ +  if (Subtarget->is64Bit()) +    return isUInt<6>(Imm) && (Imm != 0); +  return isUInt<5>(Imm) && (Imm != 0); +}]> { +  let ParserMatchClass = UImmLog2XLenNonZeroAsmOperand; +  // TODO: should ensure invalid shamt is rejected when decoding. +  let DecoderMethod = "decodeUImmOperand<6>"; +} + +def simm6 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<6>(Imm);}]> { +  let ParserMatchClass = SImmAsmOperand<6>; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeSImmOperand<6>"; +} + +def uimm6nonzero : Operand<XLenVT>, +                   ImmLeaf<XLenVT, [{return isUInt<6>(Imm) && (Imm != 0);}]> { +  let ParserMatchClass = UImmAsmOperand<6, "NonZero">; +  let DecoderMethod = "decodeUImmOperand<6>"; +} + +// A 7-bit unsigned immediate where the least significant two bits are zero. +def uimm7_lsb00 : Operand<XLenVT>, +                  ImmLeaf<XLenVT, [{return isShiftedUInt<5, 2>(Imm);}]> { +  let ParserMatchClass = UImmAsmOperand<7, "Lsb00">; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeUImmOperand<7>"; +} + +// A 8-bit unsigned immediate where the least significant two bits are zero. +def uimm8_lsb00 : Operand<XLenVT>, +                  ImmLeaf<XLenVT, [{return isShiftedUInt<6, 2>(Imm);}]> { +  let ParserMatchClass = UImmAsmOperand<8, "Lsb00">; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeUImmOperand<8>"; +} + +// A 8-bit unsigned immediate where the least significant three bits are zero. +def uimm8_lsb000 : Operand<XLenVT>, +                   ImmLeaf<XLenVT, [{return isShiftedUInt<5, 3>(Imm);}]> { +  let ParserMatchClass = UImmAsmOperand<8, "Lsb000">; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeUImmOperand<8>"; +} + +// A 9-bit signed immediate where the least significant bit is zero. +def simm9_lsb0 : Operand<OtherVT> { +  let ParserMatchClass = SImmAsmOperand<9, "Lsb0">; +  let EncoderMethod = "getImmOpValueAsr1"; +  let DecoderMethod = "decodeSImmOperandAndLsl1<9>"; +} + +// A 9-bit unsigned immediate where the least significant three bits are zero. +def uimm9_lsb000 : Operand<XLenVT>, +                   ImmLeaf<XLenVT, [{return isShiftedUInt<6, 3>(Imm);}]> { +  let ParserMatchClass = UImmAsmOperand<9, "Lsb000">; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeUImmOperand<9>"; +} + +// A 10-bit unsigned immediate where the least significant two bits are zero +// and the immediate can't be zero. +def uimm10_lsb00nonzero : Operand<XLenVT>, +                          ImmLeaf<XLenVT, +                          [{return isShiftedUInt<8, 2>(Imm) && (Imm != 0);}]> { +  let ParserMatchClass = UImmAsmOperand<10, "Lsb00NonZero">; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeUImmOperand<10>"; +} + +// A 10-bit signed immediate where the least significant four bits are zero. +def simm10_lsb0000 : Operand<XLenVT>, +                     ImmLeaf<XLenVT, [{return isShiftedInt<6, 4>(Imm);}]> { +  let ParserMatchClass = SImmAsmOperand<10, "Lsb0000">; +  let EncoderMethod = "getImmOpValue"; +  let DecoderMethod = "decodeSImmOperand<10>"; +} + +// A 12-bit signed immediate where the least significant bit is zero. +def simm12_lsb0 : Operand<OtherVT> { +  let ParserMatchClass = SImmAsmOperand<12, "Lsb0">; +  let EncoderMethod = "getImmOpValueAsr1"; +  let DecoderMethod = "decodeSImmOperandAndLsl1<12>"; +} + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class CStackLoad<bits<3> funct3, string OpcodeStr, +                 RegisterClass cls, DAGOperand opnd> +    : RVInst16CI<funct3, 0b10, (outs cls:$rd), (ins SP:$rs1, opnd:$imm), +                 OpcodeStr, "$rd, ${imm}(${rs1})">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class CStackStore<bits<3> funct3, string OpcodeStr, +                  RegisterClass cls, DAGOperand opnd> +    : RVInst16CSS<funct3, 0b10, (outs), (ins cls:$rs2, SP:$rs1, opnd:$imm), +                  OpcodeStr, "$rs2, ${imm}(${rs1})">; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class CLoad_ri<bits<3> funct3, string OpcodeStr, +               RegisterClass cls, DAGOperand opnd> +    : RVInst16CL<funct3, 0b00, (outs cls:$rd), (ins GPRC:$rs1, opnd:$imm), +                 OpcodeStr, "$rd, ${imm}(${rs1})">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class CStore_rri<bits<3> funct3, string OpcodeStr, +                 RegisterClass cls, DAGOperand opnd> +    : RVInst16CS<funct3, 0b00, (outs), (ins cls:$rs2, GPRC:$rs1, opnd:$imm), +                 OpcodeStr, "$rs2, ${imm}(${rs1})">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class Bcz<bits<3> funct3, string OpcodeStr, PatFrag CondOp, +          RegisterClass cls> +    : RVInst16CB<funct3, 0b01, (outs), (ins cls:$rs1, simm9_lsb0:$imm), +                 OpcodeStr, "$rs1, $imm"> { +  let isBranch = 1; +  let isTerminator = 1; +  let Inst{12} = imm{7}; +  let Inst{11-10} = imm{3-2}; +  let Inst{6-5} = imm{6-5}; +  let Inst{4-3} = imm{1-0}; +  let Inst{2} = imm{4}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class Shift_right<bits<2> funct2, string OpcodeStr, RegisterClass cls, +                  Operand ImmOpnd> +    : RVInst16CB<0b100, 0b01, (outs cls:$rs1_wb), (ins cls:$rs1, ImmOpnd:$imm), +                 OpcodeStr, "$rs1, $imm"> { +  let Constraints = "$rs1 = $rs1_wb"; +  let Inst{12} = imm{5}; +  let Inst{11-10} = funct2; +  let Inst{6-2} = imm{4-0}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class CS_ALU<bits<2> funct2, string OpcodeStr, RegisterClass cls, +             bit RV64only> +    : RVInst16CS<0b100, 0b01, (outs cls:$rd_wb), (ins cls:$rd, cls:$rs2), +                 OpcodeStr, "$rd, $rs2"> { +  bits<3> rd; +  let Constraints = "$rd = $rd_wb"; +  let Inst{12} = RV64only; +  let Inst{11-10} = 0b11; +  let Inst{9-7} = rd; +  let Inst{6-5} = funct2; +} + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtC] in { + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ADDI4SPN : RVInst16CIW<0b000, 0b00, (outs GPRC:$rd), +                             (ins SP:$rs1, uimm10_lsb00nonzero:$imm), +                             "c.addi4spn", "$rd, $rs1, $imm"> { +  bits<5> rs1; +  let Inst{12-11} = imm{5-4}; +  let Inst{10-7} = imm{9-6}; +  let Inst{6} = imm{2}; +  let Inst{5} = imm{3}; +} + +def C_FLD  : CLoad_ri<0b001, "c.fld", FPR64C, uimm8_lsb000>, +             Requires<[HasStdExtD]> { +  bits<8> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6-5} = imm{7-6}; +} + +def C_LW : CLoad_ri<0b010, "c.lw", GPRC, uimm7_lsb00> { +  bits<7> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6} = imm{2}; +  let Inst{5} = imm{6}; +} + +let DecoderNamespace = "RISCV32Only_" in +def C_FLW  : CLoad_ri<0b011, "c.flw", FPR32C, uimm7_lsb00>, +             Requires<[HasStdExtF, IsRV32]> { +  bits<7> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6} = imm{2}; +  let Inst{5} = imm{6}; +} + +def C_LD : CLoad_ri<0b011, "c.ld", GPRC, uimm8_lsb000>, +           Requires<[IsRV64]> { +  bits<8> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6-5} = imm{7-6}; +} + +def C_FSD  : CStore_rri<0b101, "c.fsd", FPR64C, uimm8_lsb000>, +             Requires<[HasStdExtD]> { +  bits<8> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6-5} = imm{7-6}; +} + +def C_SW : CStore_rri<0b110, "c.sw", GPRC, uimm7_lsb00> { +  bits<7> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6} = imm{2}; +  let Inst{5} = imm{6}; +} + +let DecoderNamespace = "RISCV32Only_" in +def C_FSW  : CStore_rri<0b111, "c.fsw", FPR32C, uimm7_lsb00>, +             Requires<[HasStdExtF, IsRV32]> { +  bits<7> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6} = imm{2}; +  let Inst{5} = imm{6}; +} + +def C_SD : CStore_rri<0b111, "c.sd", GPRC, uimm8_lsb000>, +           Requires<[IsRV64]> { +  bits<8> imm; +  let Inst{12-10} = imm{5-3}; +  let Inst{6-5} = imm{7-6}; +} + +let rd = 0, imm = 0, hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", "">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ADDI : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb), +                        (ins GPRNoX0:$rd, simm6:$imm), +                        "c.addi", "$rd, $imm"> { +  let Constraints = "$rd = $rd_wb"; +  let Inst{6-2} = imm{4-0}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1, +    DecoderNamespace = "RISCV32Only_" in +def C_JAL : RVInst16CJ<0b001, 0b01, (outs), (ins simm12_lsb0:$offset), +                       "c.jal", "$offset">, +            Requires<[IsRV32]>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ADDIW : RVInst16CI<0b001, 0b01, (outs GPRNoX0:$rd_wb), +                         (ins GPRNoX0:$rd, simm6:$imm), +                         "c.addiw", "$rd, $imm">, +              Requires<[IsRV64]> { +  let Constraints = "$rd = $rd_wb"; +  let Inst{6-2} = imm{4-0}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_LI : RVInst16CI<0b010, 0b01, (outs GPRNoX0:$rd), (ins simm6:$imm), +                      "c.li", "$rd, $imm"> { +  let Inst{6-2} = imm{4-0}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ADDI16SP : RVInst16CI<0b011, 0b01, (outs SP:$rd_wb), +                            (ins SP:$rd, simm10_lsb0000:$imm), +                            "c.addi16sp", "$rd, $imm"> { +  let Constraints = "$rd = $rd_wb"; +  let Inst{12} = imm{9}; +  let Inst{11-7} = 2; +  let Inst{6} = imm{4}; +  let Inst{5} = imm{6}; +  let Inst{4-3} = imm{8-7}; +  let Inst{2} = imm{5}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_LUI : RVInst16CI<0b011, 0b01, (outs GPRNoX0X2:$rd), +                       (ins uimm6nonzero:$imm), +                       "c.lui", "$rd, $imm"> { +  let Inst{6-2} = imm{4-0}; +} + +def C_SRLI : Shift_right<0b00, "c.srli", GPRC, uimmlog2xlennonzero>; +def C_SRAI : Shift_right<0b01, "c.srai", GPRC, uimmlog2xlennonzero>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ANDI : RVInst16CB<0b100, 0b01, (outs GPRC:$rs1_wb), (ins GPRC:$rs1, simm6:$imm), +                        "c.andi", "$rs1, $imm"> { +  let Constraints = "$rs1 = $rs1_wb"; +  let Inst{12} = imm{5}; +  let Inst{11-10} = 0b10; +  let Inst{6-2} = imm{4-0}; +} + +def C_SUB  : CS_ALU<0b00, "c.sub", GPRC, 0>; +def C_XOR  : CS_ALU<0b01, "c.xor", GPRC, 0>; +def C_OR   : CS_ALU<0b10, "c.or" , GPRC, 0>; +def C_AND  : CS_ALU<0b11, "c.and", GPRC, 0>; + +def C_SUBW : CS_ALU<0b00, "c.subw", GPRC, 1>, Requires<[IsRV64]>; +def C_ADDW : CS_ALU<0b01, "c.addw", GPRC, 1>, Requires<[IsRV64]>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_J : RVInst16CJ<0b101, 0b01, (outs), (ins simm12_lsb0:$offset), +                     "c.j", "$offset"> { +  let isBranch = 1; +  let isTerminator=1; +  let isBarrier=1; +} + +def C_BEQZ : Bcz<0b110, "c.beqz",  seteq, GPRC>; +def C_BNEZ : Bcz<0b111, "c.bnez",  setne, GPRC>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_SLLI : RVInst16CI<0b000, 0b10, (outs GPRNoX0:$rd_wb), +                        (ins GPRNoX0:$rd, uimmlog2xlennonzero:$imm), +                        "c.slli" ,"$rd, $imm"> { +  let Constraints = "$rd = $rd_wb"; +  let Inst{6-2} = imm{4-0}; +} + +def C_FLDSP  : CStackLoad<0b001, "c.fldsp", FPR64, uimm9_lsb000>, +               Requires<[HasStdExtD]> { +  let Inst{6-5} = imm{4-3}; +  let Inst{4-2} = imm{8-6}; +} + +def C_LWSP : CStackLoad<0b010, "c.lwsp", GPRNoX0, uimm8_lsb00> { +  let Inst{6-4} = imm{4-2}; +  let Inst{3-2} = imm{7-6}; +} + +let DecoderNamespace = "RISCV32Only_" in +def C_FLWSP  : CStackLoad<0b011, "c.flwsp", FPR32, uimm8_lsb00>, +               Requires<[HasStdExtF, IsRV32]> { +  let Inst{6-4} = imm{4-2}; +  let Inst{3-2} = imm{7-6}; +} + +def C_LDSP : CStackLoad<0b011, "c.ldsp", GPRNoX0, uimm9_lsb000>, +             Requires<[IsRV64]> { +  let Inst{6-5} = imm{4-3}; +  let Inst{4-2} = imm{8-6}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_JR : RVInst16CR<0b1000, 0b10, (outs), (ins GPRNoX0:$rs1), +                      "c.jr", "$rs1"> { +  let isBranch = 1; +  let isBarrier = 1; +  let isTerminator = 1; +  let isIndirectBranch = 1; +  let rs2 = 0; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_MV : RVInst16CR<0b1000, 0b10, (outs GPRNoX0:$rs1), (ins GPRNoX0:$rs2), +                      "c.mv", "$rs1, $rs2">; + +let rs1 = 0, rs2 = 0, hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_EBREAK : RVInst16CR<0b1001, 0b10, (outs), (ins), "c.ebreak", "">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, +    isCall=1, Defs=[X1], rs2 = 0 in +def C_JALR : RVInst16CR<0b1001, 0b10, (outs), (ins GPRNoX0:$rs1), +                        "c.jalr", "$rs1">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ADD : RVInst16CR<0b1001, 0b10, (outs GPRNoX0:$rs1_wb), +                       (ins GPRNoX0:$rs1, GPRNoX0:$rs2), +                       "c.add", "$rs1, $rs2"> { +  let Constraints = "$rs1 = $rs1_wb"; +} + +def C_FSDSP  : CStackStore<0b101, "c.fsdsp", FPR64, uimm9_lsb000>, +               Requires<[HasStdExtD]> { +  let Inst{12-10} = imm{5-3}; +  let Inst{9-7}   = imm{8-6}; +} + +def C_SWSP : CStackStore<0b110, "c.swsp", GPR, uimm8_lsb00> { +  let Inst{12-9} = imm{5-2}; +  let Inst{8-7}  = imm{7-6}; +} + +let DecoderNamespace = "RISCV32Only_" in +def C_FSWSP  : CStackStore<0b111, "c.fswsp", FPR32, uimm8_lsb00>, +               Requires<[HasStdExtF, IsRV32]> { +  let Inst{12-9} = imm{5-2}; +  let Inst{8-7}  = imm{7-6}; +} + +def C_SDSP : CStackStore<0b111, "c.sdsp", GPR, uimm9_lsb000>, +             Requires<[IsRV64]> { +  let Inst{12-10} = imm{5-3}; +  let Inst{9-7}   = imm{8-6}; +} + +} // Predicates = [HasStdExtC] diff --git a/lib/Target/RISCV/RISCVInstrInfoD.td b/lib/Target/RISCV/RISCVInstrInfoD.td new file mode 100644 index 000000000000..48d91c0054d3 --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfoD.td @@ -0,0 +1,174 @@ +//===-- RISCVInstrInfoD.td - RISC-V 'D' instructions -------*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the RISC-V instructions from the standard 'D', +// Double-Precision Floating-Point instruction set extension. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPFMAD_rrr_frm<RISCVOpcode opcode, string opcodestr> +    : RVInstR4<0b01, opcode, (outs FPR64:$rd), +               (ins FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, frmarg:$funct3), +                opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">; + +class FPFMADDynFrmAlias<FPFMAD_rrr_frm Inst, string OpcodeStr> +    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3", +                (Inst FPR64:$rd, FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPALUD_rr<bits<7> funct7, bits<3> funct3, string opcodestr> +    : RVInstR<funct7, funct3, OPC_OP_FP, (outs FPR64:$rd), +              (ins FPR64:$rs1, FPR64:$rs2), opcodestr, "$rd, $rs1, $rs2">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPALUD_rr_frm<bits<7> funct7, string opcodestr> +    : RVInstRFrm<funct7, OPC_OP_FP, (outs FPR64:$rd), +                (ins FPR64:$rs1, FPR64:$rs2, frmarg:$funct3), opcodestr, +                 "$rd, $rs1, $rs2, $funct3">; + +class FPALUDDynFrmAlias<FPALUD_rr_frm Inst, string OpcodeStr> +    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2", +                (Inst FPR64:$rd, FPR64:$rs1, FPR64:$rs2, 0b111)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPCmpD_rr<bits<3> funct3, string opcodestr> +    : RVInstR<0b1010001, funct3, OPC_OP_FP, (outs GPR:$rd), +              (ins FPR64:$rs1, FPR64:$rs2), opcodestr, "$rd, $rs1, $rs2">; + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtD] in { + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def FLD : RVInstI<0b011, OPC_LOAD_FP, (outs FPR64:$rd), +                  (ins GPR:$rs1, simm12:$imm12), +                  "fld", "$rd, ${imm12}(${rs1})">; + +// Operands for stores are in the order srcreg, base, offset rather than +// reflecting the order these fields are specified in the instruction +// encoding. +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +def FSD : RVInstS<0b011, OPC_STORE_FP, (outs), +                  (ins FPR64:$rs2, GPR:$rs1, simm12:$imm12), +                   "fsd", "$rs2, ${imm12}(${rs1})">; + +def FMADD_D  : FPFMAD_rrr_frm<OPC_MADD, "fmadd.d">; +def          : FPFMADDynFrmAlias<FMADD_D, "fmadd.d">; +def FMSUB_D  : FPFMAD_rrr_frm<OPC_MSUB, "fmsub.d">; +def          : FPFMADDynFrmAlias<FMSUB_D, "fmsub.d">; +def FNMSUB_D : FPFMAD_rrr_frm<OPC_NMSUB, "fnmsub.d">; +def          : FPFMADDynFrmAlias<FNMSUB_D, "fnmsub.d">; +def FNMADD_D : FPFMAD_rrr_frm<OPC_NMADD, "fnmadd.d">; +def          : FPFMADDynFrmAlias<FNMADD_D, "fnmadd.d">; + +def FADD_D : FPALUD_rr_frm<0b0000001, "fadd.d">; +def        : FPALUDDynFrmAlias<FADD_D, "fadd.d">; +def FSUB_D : FPALUD_rr_frm<0b0000101, "fsub.d">; +def        : FPALUDDynFrmAlias<FSUB_D, "fsub.d">; +def FMUL_D : FPALUD_rr_frm<0b0001001, "fmul.d">; +def        : FPALUDDynFrmAlias<FMUL_D, "fmul.d">; +def FDIV_D : FPALUD_rr_frm<0b0001101, "fdiv.d">; +def        : FPALUDDynFrmAlias<FDIV_D, "fdiv.d">; + +def FSQRT_D : FPUnaryOp_r_frm<0b0101101, FPR64, FPR64, "fsqrt.d"> { +  let rs2 = 0b00000; +} +def         : FPUnaryOpDynFrmAlias<FSQRT_D, "fsqrt.d", FPR64, FPR64>; + +def FSGNJ_D  : FPALUD_rr<0b0010001, 0b000, "fsgnj.d">; +def FSGNJN_D : FPALUD_rr<0b0010001, 0b001, "fsgnjn.d">; +def FSGNJX_D : FPALUD_rr<0b0010001, 0b010, "fsgnjx.d">; +def FMIN_D   : FPALUD_rr<0b0010101, 0b000, "fmin.d">; +def FMAX_D   : FPALUD_rr<0b0010101, 0b001, "fmax.d">; + +def FCVT_S_D : FPUnaryOp_r_frm<0b0100000, FPR32, FPR64, "fcvt.s.d"> { +  let rs2 = 0b00001; +} +def          : FPUnaryOpDynFrmAlias<FCVT_S_D, "fcvt.s.d", FPR32, FPR64>; + +def FCVT_D_S : FPUnaryOp_r<0b0100001, 0b000, FPR64, FPR32, "fcvt.d.s"> { +  let rs2 = 0b00000; +} + +def FEQ_D : FPCmpD_rr<0b010, "feq.d">; +def FLT_D : FPCmpD_rr<0b001, "flt.d">; +def FLE_D : FPCmpD_rr<0b000, "fle.d">; + +def FCLASS_D : FPUnaryOp_r<0b1110001, 0b001, GPR, FPR64, "fclass.d"> { +  let rs2 = 0b00000; +} + +def FCVT_W_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.w.d"> { +  let rs2 = 0b00000; +} +def          : FPUnaryOpDynFrmAlias<FCVT_W_D, "fcvt.w.d", GPR, FPR64>; + +def FCVT_WU_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.wu.d"> { +  let rs2 = 0b00001; +} +def           : FPUnaryOpDynFrmAlias<FCVT_WU_D, "fcvt.wu.d", GPR, FPR64>; + +def FCVT_D_W : FPUnaryOp_r<0b1101001, 0b000, FPR64, GPR, "fcvt.d.w"> { +  let rs2 = 0b00000; +} + +def FCVT_D_WU : FPUnaryOp_r<0b1101001, 0b000, FPR64, GPR, "fcvt.d.wu"> { +  let rs2 = 0b00001; +} +} // Predicates = [HasStdExtD] + +let Predicates = [HasStdExtD, IsRV64] in { +def FCVT_L_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.l.d"> { +  let rs2 = 0b00010; +} +def          : FPUnaryOpDynFrmAlias<FCVT_L_D, "fcvt.l.d", GPR, FPR64>; + +def FCVT_LU_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.lu.d"> { +  let rs2 = 0b00011; +} +def           : FPUnaryOpDynFrmAlias<FCVT_LU_D, "fcvt.lu.d", GPR, FPR64>; + +def FMV_X_D : FPUnaryOp_r<0b1110001, 0b000, GPR, FPR64, "fmv.x.d"> { +  let rs2 = 0b00000; +} + +def FCVT_D_L : FPUnaryOp_r_frm<0b1101001, FPR64, GPR, "fcvt.d.l"> { +  let rs2 = 0b00010; +} +def          : FPUnaryOpDynFrmAlias<FCVT_D_L, "fcvt.d.l", FPR64, GPR>; + +def FCVT_D_LU : FPUnaryOp_r_frm<0b1101001, FPR64, GPR, "fcvt.d.lu"> { +  let rs2 = 0b00011; +} +def           : FPUnaryOpDynFrmAlias<FCVT_D_LU, "fcvt.d.lu", FPR64, GPR>; + +def FMV_D_X : FPUnaryOp_r<0b1111001, 0b000, FPR64, GPR, "fmv.d.x"> { +  let rs2 = 0b00000; +} +} // Predicates = [HasStdExtD, IsRV64] + +//===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtD] in { +// TODO fld +// TODO fsd + +def : InstAlias<"fmv.d $rd, $rs",  (FSGNJ_D  FPR64:$rd, FPR64:$rs, FPR64:$rs)>; +def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>; +def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>; +} // Predicates = [HasStdExtD] diff --git a/lib/Target/RISCV/RISCVInstrInfoF.td b/lib/Target/RISCV/RISCVInstrInfoF.td new file mode 100644 index 000000000000..07722d2cbf34 --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfoF.td @@ -0,0 +1,222 @@ +//===-- RISCVInstrInfoF.td - RISC-V 'F' instructions -------*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the RISC-V instructions from the standard 'F', +// Single-Precision Floating-Point instruction set extension. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Operand and SDNode transformation definitions. +//===----------------------------------------------------------------------===// + +// Floating-point rounding mode + +def FRMArg : AsmOperandClass { +  let Name = "FRMArg"; +  let RenderMethod = "addFRMArgOperands"; +  let DiagnosticType = "InvalidFRMArg"; +} + +def frmarg : Operand<XLenVT> { +  let ParserMatchClass = FRMArg; +  let PrintMethod = "printFRMArg"; +  let DecoderMethod = "decodeUImmOperand<3>"; +} + +//===----------------------------------------------------------------------===// +// Instruction class templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPFMAS_rrr_frm<RISCVOpcode opcode, string opcodestr> +    : RVInstR4<0b00, opcode, (outs FPR32:$rd), +               (ins FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, frmarg:$funct3), +                opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">; + +class FPFMASDynFrmAlias<FPFMAS_rrr_frm Inst, string OpcodeStr> +    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3", +                (Inst FPR32:$rd, FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPALUS_rr<bits<7> funct7, bits<3> funct3, string opcodestr> +    : RVInstR<funct7, funct3, OPC_OP_FP, (outs FPR32:$rd), +              (ins FPR32:$rs1, FPR32:$rs2), opcodestr, "$rd, $rs1, $rs2">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPALUS_rr_frm<bits<7> funct7, string opcodestr> +    : RVInstRFrm<funct7, OPC_OP_FP, (outs FPR32:$rd), +                 (ins FPR32:$rs1, FPR32:$rs2, frmarg:$funct3), opcodestr, +                  "$rd, $rs1, $rs2, $funct3">; + +class FPALUSDynFrmAlias<FPALUS_rr_frm Inst, string OpcodeStr> +    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2", +                (Inst FPR32:$rd, FPR32:$rs1, FPR32:$rs2, 0b111)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPUnaryOp_r<bits<7> funct7, bits<3> funct3, RegisterClass rdty, +                RegisterClass rs1ty, string opcodestr> +    : RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd), (ins rs1ty:$rs1), +              opcodestr, "$rd, $rs1">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPUnaryOp_r_frm<bits<7> funct7, RegisterClass rdty, RegisterClass rs1ty, +                      string opcodestr> +    : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd), +                 (ins rs1ty:$rs1, frmarg:$funct3), opcodestr, +                  "$rd, $rs1, $funct3">; + +class FPUnaryOpDynFrmAlias<FPUnaryOp_r_frm Inst, string OpcodeStr, +                           RegisterClass rdty, RegisterClass rs1ty> +    : InstAlias<OpcodeStr#" $rd, $rs1", +                (Inst rdty:$rd, rs1ty:$rs1, 0b111)>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class FPCmpS_rr<bits<3> funct3, string opcodestr> +    : RVInstR<0b1010000, funct3, OPC_OP_FP, (outs GPR:$rd), +              (ins FPR32:$rs1, FPR32:$rs2), opcodestr, "$rd, $rs1, $rs2">; + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtF] in { +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def FLW : RVInstI<0b010, OPC_LOAD_FP, (outs FPR32:$rd), +                  (ins GPR:$rs1, simm12:$imm12), +                   "flw", "$rd, ${imm12}(${rs1})">; + +// Operands for stores are in the order srcreg, base, offset rather than +// reflecting the order these fields are specified in the instruction +// encoding. +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +def FSW : RVInstS<0b010, OPC_STORE_FP, (outs), +                  (ins FPR32:$rs2, GPR:$rs1, simm12:$imm12), +                   "fsw", "$rs2, ${imm12}(${rs1})">; + +def FMADD_S  : FPFMAS_rrr_frm<OPC_MADD, "fmadd.s">; +def          : FPFMASDynFrmAlias<FMADD_S, "fmadd.s">; +def FMSUB_S  : FPFMAS_rrr_frm<OPC_MSUB, "fmsub.s">; +def          : FPFMASDynFrmAlias<FMSUB_S, "fmsub.s">; +def FNMSUB_S : FPFMAS_rrr_frm<OPC_NMSUB, "fnmsub.s">; +def          : FPFMASDynFrmAlias<FNMSUB_S, "fnmsub.s">; +def FNMADD_S : FPFMAS_rrr_frm<OPC_NMADD, "fnmadd.s">; +def          : FPFMASDynFrmAlias<FNMADD_S, "fnmadd.s">; + +def FADD_S : FPALUS_rr_frm<0b0000000, "fadd.s">; +def        : FPALUSDynFrmAlias<FADD_S, "fadd.s">; +def FSUB_S : FPALUS_rr_frm<0b0000100, "fsub.s">; +def        : FPALUSDynFrmAlias<FSUB_S, "fsub.s">; +def FMUL_S : FPALUS_rr_frm<0b0001000, "fmul.s">; +def        : FPALUSDynFrmAlias<FMUL_S, "fmul.s">; +def FDIV_S : FPALUS_rr_frm<0b0001100, "fdiv.s">; +def        : FPALUSDynFrmAlias<FDIV_S, "fdiv.s">; + +def FSQRT_S : FPUnaryOp_r_frm<0b0101100, FPR32, FPR32, "fsqrt.s"> { +  let rs2 = 0b00000; +} +def         : FPUnaryOpDynFrmAlias<FSQRT_S, "fsqrt.s", FPR32, FPR32>; + +def FSGNJ_S  : FPALUS_rr<0b0010000, 0b000, "fsgnj.s">; +def FSGNJN_S : FPALUS_rr<0b0010000, 0b001, "fsgnjn.s">; +def FSGNJX_S : FPALUS_rr<0b0010000, 0b010, "fsgnjx.s">; +def FMIN_S   : FPALUS_rr<0b0010100, 0b000, "fmin.s">; +def FMAX_S   : FPALUS_rr<0b0010100, 0b001, "fmax.s">; + +def FCVT_W_S : FPUnaryOp_r_frm<0b1100000, GPR, FPR32, "fcvt.w.s"> { +  let rs2 = 0b00000; +} +def          : FPUnaryOpDynFrmAlias<FCVT_W_S, "fcvt.w.s", GPR, FPR32>; + +def FCVT_WU_S : FPUnaryOp_r_frm<0b1100000, GPR, FPR32, "fcvt.wu.s"> { +  let rs2 = 0b00001; +} +def           : FPUnaryOpDynFrmAlias<FCVT_WU_S, "fcvt.wu.s", GPR, FPR32>; + +def FMV_X_W : FPUnaryOp_r<0b1110000, 0b000, GPR, FPR32, "fmv.x.w"> { +  let rs2 = 0b00000; +} + +def FEQ_S : FPCmpS_rr<0b010, "feq.s">; +def FLT_S : FPCmpS_rr<0b001, "flt.s">; +def FLE_S : FPCmpS_rr<0b000, "fle.s">; + +def FCLASS_S : FPUnaryOp_r<0b1110000, 0b001, GPR, FPR32, "fclass.s"> { +  let rs2 = 0b00000; +} + +def FCVT_S_W : FPUnaryOp_r_frm<0b1101000, FPR32, GPR, "fcvt.s.w"> { +  let rs2 = 0b00000; +} +def          : FPUnaryOpDynFrmAlias<FCVT_S_W, "fcvt.s.w", FPR32, GPR>; + +def FCVT_S_WU : FPUnaryOp_r_frm<0b1101000, FPR32, GPR, "fcvt.s.wu"> { +  let rs2 = 0b00001; +} +def           : FPUnaryOpDynFrmAlias<FCVT_S_WU, "fcvt.s.wu", FPR32, GPR>; + +def FMV_W_X : FPUnaryOp_r<0b1111000, 0b000, FPR32, GPR, "fmv.w.x"> { +  let rs2 = 0b00000; +} +} // Predicates = [HasStdExtF] + +let Predicates = [HasStdExtF, IsRV64] in { +def FCVT_L_S  : FPUnaryOp_r_frm<0b1100000, GPR, FPR32, "fcvt.l.s"> { +  let rs2 = 0b00010; +} +def           : FPUnaryOpDynFrmAlias<FCVT_L_S, "fcvt.l.s", GPR, FPR32>; + +def FCVT_LU_S  : FPUnaryOp_r_frm<0b1100000, GPR, FPR32, "fcvt.lu.s"> { +  let rs2 = 0b00011; +} +def            : FPUnaryOpDynFrmAlias<FCVT_LU_S, "fcvt.lu.s", GPR, FPR32>; + +def FCVT_S_L : FPUnaryOp_r_frm<0b1101000, FPR32, GPR, "fcvt.s.l"> { +  let rs2 = 0b00010; +} +def          : FPUnaryOpDynFrmAlias<FCVT_S_L, "fcvt.s.l", FPR32, GPR>; + +def FCVT_S_LU : FPUnaryOp_r_frm<0b1101000, FPR32, GPR, "fcvt.s.lu"> { +  let rs2 = 0b00011; +} +def           : FPUnaryOpDynFrmAlias<FCVT_S_LU, "fcvt.s.lu", FPR32, GPR>; +} // Predicates = [HasStdExtF, IsRV64] + +//===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtF] in { +// TODO flw +// TODO fsw + +def : InstAlias<"fmv.s $rd, $rs",  (FSGNJ_S  FPR32:$rd, FPR32:$rs, FPR32:$rs)>; +def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; +def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; + +// The following csr instructions actually alias instructions from the base ISA. +// However, it only makes sense to support them when the F extension is enabled. +// CSR Addresses: 0x003 == fcsr, 0x002 == frm, 0x001 == fflags +// NOTE: "frcsr", "frrm", and "frflags" are more specialized version of "csrr". +def : InstAlias<"frcsr $rd",      (CSRRS GPR:$rd, 0x003, X0), 2>; +def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, 0x003, GPR:$rs)>; +def : InstAlias<"fscsr $rs",      (CSRRW      X0, 0x003, GPR:$rs), 2>; + +def : InstAlias<"frrm $rd",        (CSRRS  GPR:$rd, 0x002, X0), 2>; +def : InstAlias<"fsrm $rd, $rs",   (CSRRW  GPR:$rd, 0x002, GPR:$rs)>; +def : InstAlias<"fsrm $rs",        (CSRRW       X0, 0x002, GPR:$rs), 2>; +def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, 0x002, uimm5:$imm)>; +def : InstAlias<"fsrmi $imm",      (CSRRWI      X0, 0x002, uimm5:$imm), 2>; + +def : InstAlias<"frflags $rd",        (CSRRS  GPR:$rd, 0x001, X0), 2>; +def : InstAlias<"fsflags $rd, $rs",   (CSRRW  GPR:$rd, 0x001, GPR:$rs)>; +def : InstAlias<"fsflags $rs",        (CSRRW       X0, 0x001, GPR:$rs), 2>; +def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, 0x001, uimm5:$imm)>; +def : InstAlias<"fsflagsi $imm",      (CSRRWI      X0, 0x001, uimm5:$imm), 2>; +} // Predicates = [HasStdExtF] diff --git a/lib/Target/RISCV/RISCVInstrInfoM.td b/lib/Target/RISCV/RISCVInstrInfoM.td new file mode 100644 index 000000000000..fec9c1f93997 --- /dev/null +++ b/lib/Target/RISCV/RISCVInstrInfoM.td @@ -0,0 +1,36 @@ +//===-- RISCVInstrInfoM.td - RISC-V 'M' instructions -------*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the RISC-V instructions from the standard 'M', Integer +// Multiplication and Division instruction set extension. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtM] in { +def MUL     : ALU_rr<0b0000001, 0b000, "mul">; +def MULH    : ALU_rr<0b0000001, 0b001, "mulh">; +def MULHSU  : ALU_rr<0b0000001, 0b010, "mulhsu">; +def MULHU   : ALU_rr<0b0000001, 0b011, "mulhu">; +def DIV     : ALU_rr<0b0000001, 0b100, "div">; +def DIVU    : ALU_rr<0b0000001, 0b101, "divu">; +def REM     : ALU_rr<0b0000001, 0b110, "rem">; +def REMU    : ALU_rr<0b0000001, 0b111, "remu">; +} // Predicates = [HasStdExtM] + +let Predicates = [HasStdExtM, IsRV64] in { +def MULW    : ALUW_rr<0b0000001, 0b000, "mulw">; +def DIVW    : ALUW_rr<0b0000001, 0b100, "divw">; +def DIVUW   : ALUW_rr<0b0000001, 0b101, "divuw">; +def REMW    : ALUW_rr<0b0000001, 0b110, "remw">; +def REMUW   : ALUW_rr<0b0000001, 0b111, "remuw">; +} // Predicates = [HasStdExtM, IsRV64] diff --git a/lib/Target/RISCV/RISCVMCInstLower.cpp b/lib/Target/RISCV/RISCVMCInstLower.cpp new file mode 100644 index 000000000000..d8ae11f2bd90 --- /dev/null +++ b/lib/Target/RISCV/RISCVMCInstLower.cpp @@ -0,0 +1,105 @@ +//===-- RISCVMCInstLower.cpp - Convert RISCV MachineInstr to an MCInst ------=// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower RISCV MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "MCTargetDesc/RISCVMCExpr.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, +                                    const AsmPrinter &AP) { +  MCContext &Ctx = AP.OutContext; +  RISCVMCExpr::VariantKind Kind; + +  switch (MO.getTargetFlags()) { +  default: +    llvm_unreachable("Unknown target flag on GV operand"); +  case RISCVII::MO_None: +    Kind = RISCVMCExpr::VK_RISCV_None; +    break; +  case RISCVII::MO_LO: +    Kind = RISCVMCExpr::VK_RISCV_LO; +    break; +  case RISCVII::MO_HI: +    Kind = RISCVMCExpr::VK_RISCV_HI; +    break; +  } + +  const MCExpr *ME = +      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); + +  if (!MO.isJTI() && MO.getOffset()) +    ME = MCBinaryExpr::createAdd( +        ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); + +  ME = RISCVMCExpr::create(ME, Kind, Ctx); +  return MCOperand::createExpr(ME); +} + +bool llvm::LowerRISCVMachineOperandToMCOperand(const MachineOperand &MO, +                                               MCOperand &MCOp, +                                               const AsmPrinter &AP) { +  switch (MO.getType()) { +  default: +    report_fatal_error("LowerRISCVMachineInstrToMCInst: unknown operand type"); +  case MachineOperand::MO_Register: +    // Ignore all implicit register operands. +    if (MO.isImplicit()) +      return false; +    MCOp = MCOperand::createReg(MO.getReg()); +    break; +  case MachineOperand::MO_RegisterMask: +    // Regmasks are like implicit defs. +    return false; +  case MachineOperand::MO_Immediate: +    MCOp = MCOperand::createImm(MO.getImm()); +    break; +  case MachineOperand::MO_MachineBasicBlock: +    MCOp = MCOperand::createExpr( +        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), AP.OutContext)); +    break; +  case MachineOperand::MO_GlobalAddress: +    MCOp = lowerSymbolOperand(MO, AP.getSymbol(MO.getGlobal()), AP); +    break; +  case MachineOperand::MO_BlockAddress: +    MCOp = lowerSymbolOperand( +        MO, AP.GetBlockAddressSymbol(MO.getBlockAddress()), AP); +    break; +  case MachineOperand::MO_ExternalSymbol: +    MCOp = lowerSymbolOperand( +        MO, AP.GetExternalSymbolSymbol(MO.getSymbolName()), AP); +    break; +  } +  return true; +} + +void llvm::LowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, +                                          const AsmPrinter &AP) { +  OutMI.setOpcode(MI->getOpcode()); + +  for (const MachineOperand &MO : MI->operands()) { +    MCOperand MCOp; +    if (LowerRISCVMachineOperandToMCOperand(MO, MCOp, AP)) +      OutMI.addOperand(MCOp); +  } +} diff --git a/lib/Target/RISCV/RISCVRegisterInfo.cpp b/lib/Target/RISCV/RISCVRegisterInfo.cpp new file mode 100644 index 000000000000..5776a92cab91 --- /dev/null +++ b/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -0,0 +1,93 @@ +//===-- RISCVRegisterInfo.cpp - RISCV Register Information ------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the RISCV implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "RISCVRegisterInfo.h" +#include "RISCV.h" +#include "RISCVSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/Support/ErrorHandling.h" + +#define GET_REGINFO_TARGET_DESC +#include "RISCVGenRegisterInfo.inc" + +using namespace llvm; + +RISCVRegisterInfo::RISCVRegisterInfo(unsigned HwMode) +    : RISCVGenRegisterInfo(RISCV::X1, /*DwarfFlavour*/0, /*EHFlavor*/0, +                           /*PC*/0, HwMode) {} + +const MCPhysReg * +RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { +  return CSR_SaveList; +} + +BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { +  BitVector Reserved(getNumRegs()); + +  // Use markSuperRegs to ensure any register aliases are also reserved +  markSuperRegs(Reserved, RISCV::X0); // zero +  markSuperRegs(Reserved, RISCV::X1); // ra +  markSuperRegs(Reserved, RISCV::X2); // sp +  markSuperRegs(Reserved, RISCV::X3); // gp +  markSuperRegs(Reserved, RISCV::X4); // tp +  markSuperRegs(Reserved, RISCV::X8); // fp +  assert(checkAllSuperRegsMarked(Reserved)); +  return Reserved; +} + +const uint32_t *RISCVRegisterInfo::getNoPreservedMask() const { +  return CSR_NoRegs_RegMask; +} + +void RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, +                                            int SPAdj, unsigned FIOperandNum, +                                            RegScavenger *RS) const { +  assert(SPAdj == 0 && "Unexpected non-zero SPAdj value"); + +  MachineInstr &MI = *II; +  MachineFunction &MF = *MI.getParent()->getParent(); +  DebugLoc DL = MI.getDebugLoc(); + +  int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); +  unsigned FrameReg; +  int Offset = +      getFrameLowering(MF)->getFrameIndexReference(MF, FrameIndex, FrameReg) + +      MI.getOperand(FIOperandNum + 1).getImm(); + +  assert(MF.getSubtarget().getFrameLowering()->hasFP(MF) && +         "eliminateFrameIndex currently requires hasFP"); + +  // Offsets must be directly encoded in a 12-bit immediate field +  if (!isInt<12>(Offset)) { +    report_fatal_error( +        "Frame offsets outside of the signed 12-bit range not supported"); +  } + +  MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false); +  MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); +} + +unsigned RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const { +  return RISCV::X8; +} + +const uint32_t * +RISCVRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/, +                                        CallingConv::ID /*CC*/) const { +  return CSR_RegMask; +} diff --git a/lib/Target/RISCV/RISCVRegisterInfo.h b/lib/Target/RISCV/RISCVRegisterInfo.h new file mode 100644 index 000000000000..0b2bc3776fc6 --- /dev/null +++ b/lib/Target/RISCV/RISCVRegisterInfo.h @@ -0,0 +1,45 @@ +//===-- RISCVRegisterInfo.h - RISCV Register Information Impl ---*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the RISCV implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVREGISTERINFO_H +#define LLVM_LIB_TARGET_RISCV_RISCVREGISTERINFO_H + +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "RISCVGenRegisterInfo.inc" + +namespace llvm { + +struct RISCVRegisterInfo : public RISCVGenRegisterInfo { + +  RISCVRegisterInfo(unsigned HwMode); + +  const uint32_t *getCallPreservedMask(const MachineFunction &MF, +                                       CallingConv::ID) const override; + +  const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + +  BitVector getReservedRegs(const MachineFunction &MF) const override; + +  const uint32_t *getNoPreservedMask() const override; + +  void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, +                           unsigned FIOperandNum, +                           RegScavenger *RS = nullptr) const override; + +  unsigned getFrameRegister(const MachineFunction &MF) const override; +}; +} + +#endif diff --git a/lib/Target/RISCV/RISCVRegisterInfo.td b/lib/Target/RISCV/RISCVRegisterInfo.td index f04de217bf0d..21be2e332e59 100644 --- a/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/lib/Target/RISCV/RISCVRegisterInfo.td @@ -8,83 +8,199 @@  //===----------------------------------------------------------------------===//  //===----------------------------------------------------------------------===// -//  Declarations that describe the RISC-V register file +//  Declarations that describe the RISC-V register files  //===----------------------------------------------------------------------===//  let Namespace = "RISCV" in { -  def sub_32 : SubRegIndex<32>; - -  class RISCVReg32<bits<5> Enc, string n, list<string> alt = []> : Register<n> { -    let HWEncoding{4-0} = Enc; -    let AltNames = alt; -  } +class RISCVReg<bits<5> Enc, string n, list<string> alt = []> : Register<n> { +  let HWEncoding{4-0} = Enc; +  let AltNames = alt; +} -  // RISCV64 registers don't define an AsmName or AltName. If they specified -  // names aliasing the RISCVReg32 registers, the generation of the default -  // MatchRegisterName/MatchRegisterAltName would fail. When necessary, -  // RISCVAsmParser will need to convert a register number from a RISCVReg32 -  // to the equivalent RISCVReg64. -  class RISCVReg64<RISCVReg32 subreg> : Register<""> { -    let HWEncoding{4-0} = subreg.HWEncoding{4-0}; -    let SubRegs = [subreg]; -    let SubRegIndices = [sub_32]; -  } +class RISCVReg32<bits<5> Enc, string n, list<string> alt = []> : Register<n> { +  let HWEncoding{4-0} = Enc; +  let AltNames = alt; +} -  def ABIRegAltName : RegAltNameIndex; +// Because RISCVReg64 register have AsmName and AltNames that alias with their +// 32-bit sub-register, RISCVAsmParser will need to coerce a register number +// from a RISCVReg32 to the equivalent RISCVReg64 when appropriate. +def sub_32 : SubRegIndex<32>; +class RISCVReg64<RISCVReg32 subreg> : Register<""> { +  let HWEncoding{4-0} = subreg.HWEncoding{4-0}; +  let SubRegs = [subreg]; +  let SubRegIndices = [sub_32]; +  let AsmName = subreg.AsmName; +  let AltNames = subreg.AltNames;  } +def ABIRegAltName : RegAltNameIndex; +} // Namespace = "RISCV" +  // Integer registers  let RegAltNameIndices = [ABIRegAltName] in { -  def X0_32    : RISCVReg32<0, "x0", ["zero"]>, DwarfRegNum<[0]>; -  def X1_32    : RISCVReg32<1, "x1", ["ra"]>, DwarfRegNum<[1]>; -  def X2_32    : RISCVReg32<2, "x2", ["sp"]>, DwarfRegNum<[2]>; -  def X3_32    : RISCVReg32<3, "x3", ["gp"]>, DwarfRegNum<[3]>; -  def X4_32    : RISCVReg32<4, "x4", ["tp"]>, DwarfRegNum<[4]>; -  def X5_32    : RISCVReg32<5, "x5", ["t0"]>, DwarfRegNum<[5]>; -  def X6_32    : RISCVReg32<6, "x6", ["t1"]>, DwarfRegNum<[6]>; -  def X7_32    : RISCVReg32<7, "x7", ["t2"]>, DwarfRegNum<[7]>; -  def X8_32    : RISCVReg32<8, "x8", ["s0"]>, DwarfRegNum<[8]>; -  def X9_32    : RISCVReg32<9, "x9", ["s1"]>, DwarfRegNum<[9]>; -  def X10_32   : RISCVReg32<10,"x10", ["a0"]>, DwarfRegNum<[10]>; -  def X11_32   : RISCVReg32<11,"x11", ["a1"]>, DwarfRegNum<[11]>; -  def X12_32   : RISCVReg32<12,"x12", ["a2"]>, DwarfRegNum<[12]>; -  def X13_32   : RISCVReg32<13,"x13", ["a3"]>, DwarfRegNum<[13]>; -  def X14_32   : RISCVReg32<14,"x14", ["a4"]>, DwarfRegNum<[14]>; -  def X15_32   : RISCVReg32<15,"x15", ["a5"]>, DwarfRegNum<[15]>; -  def X16_32   : RISCVReg32<16,"x16", ["a6"]>, DwarfRegNum<[16]>; -  def X17_32   : RISCVReg32<17,"x17", ["a7"]>, DwarfRegNum<[17]>; -  def X18_32   : RISCVReg32<18,"x18", ["s2"]>, DwarfRegNum<[18]>; -  def X19_32   : RISCVReg32<19,"x19", ["s3"]>, DwarfRegNum<[19]>; -  def X20_32   : RISCVReg32<20,"x20", ["s4"]>, DwarfRegNum<[20]>; -  def X21_32   : RISCVReg32<21,"x21", ["s5"]>, DwarfRegNum<[21]>; -  def X22_32   : RISCVReg32<22,"x22", ["s6"]>, DwarfRegNum<[22]>; -  def X23_32   : RISCVReg32<23,"x23", ["s7"]>, DwarfRegNum<[23]>; -  def X24_32   : RISCVReg32<24,"x24", ["s8"]>, DwarfRegNum<[24]>; -  def X25_32   : RISCVReg32<25,"x25", ["s9"]>, DwarfRegNum<[25]>; -  def X26_32   : RISCVReg32<26,"x26", ["s10"]>, DwarfRegNum<[26]>; -  def X27_32   : RISCVReg32<27,"x27", ["s11"]>, DwarfRegNum<[27]>; -  def X28_32   : RISCVReg32<28,"x28", ["t3"]>, DwarfRegNum<[28]>; -  def X29_32   : RISCVReg32<29,"x29", ["t4"]>, DwarfRegNum<[29]>; -  def X30_32   : RISCVReg32<30,"x30", ["t5"]>, DwarfRegNum<[30]>; -  def X31_32   : RISCVReg32<31,"x31", ["t6"]>, DwarfRegNum<[31]>; +  def X0  : RISCVReg<0, "x0", ["zero"]>, DwarfRegNum<[0]>; +  def X1  : RISCVReg<1, "x1", ["ra"]>, DwarfRegNum<[1]>; +  def X2  : RISCVReg<2, "x2", ["sp"]>, DwarfRegNum<[2]>; +  def X3  : RISCVReg<3, "x3", ["gp"]>, DwarfRegNum<[3]>; +  def X4  : RISCVReg<4, "x4", ["tp"]>, DwarfRegNum<[4]>; +  def X5  : RISCVReg<5, "x5", ["t0"]>, DwarfRegNum<[5]>; +  def X6  : RISCVReg<6, "x6", ["t1"]>, DwarfRegNum<[6]>; +  def X7  : RISCVReg<7, "x7", ["t2"]>, DwarfRegNum<[7]>; +  def X8  : RISCVReg<8, "x8", ["s0"]>, DwarfRegNum<[8]>; +  def X9  : RISCVReg<9, "x9", ["s1"]>, DwarfRegNum<[9]>; +  def X10 : RISCVReg<10,"x10", ["a0"]>, DwarfRegNum<[10]>; +  def X11 : RISCVReg<11,"x11", ["a1"]>, DwarfRegNum<[11]>; +  def X12 : RISCVReg<12,"x12", ["a2"]>, DwarfRegNum<[12]>; +  def X13 : RISCVReg<13,"x13", ["a3"]>, DwarfRegNum<[13]>; +  def X14 : RISCVReg<14,"x14", ["a4"]>, DwarfRegNum<[14]>; +  def X15 : RISCVReg<15,"x15", ["a5"]>, DwarfRegNum<[15]>; +  def X16 : RISCVReg<16,"x16", ["a6"]>, DwarfRegNum<[16]>; +  def X17 : RISCVReg<17,"x17", ["a7"]>, DwarfRegNum<[17]>; +  def X18 : RISCVReg<18,"x18", ["s2"]>, DwarfRegNum<[18]>; +  def X19 : RISCVReg<19,"x19", ["s3"]>, DwarfRegNum<[19]>; +  def X20 : RISCVReg<20,"x20", ["s4"]>, DwarfRegNum<[20]>; +  def X21 : RISCVReg<21,"x21", ["s5"]>, DwarfRegNum<[21]>; +  def X22 : RISCVReg<22,"x22", ["s6"]>, DwarfRegNum<[22]>; +  def X23 : RISCVReg<23,"x23", ["s7"]>, DwarfRegNum<[23]>; +  def X24 : RISCVReg<24,"x24", ["s8"]>, DwarfRegNum<[24]>; +  def X25 : RISCVReg<25,"x25", ["s9"]>, DwarfRegNum<[25]>; +  def X26 : RISCVReg<26,"x26", ["s10"]>, DwarfRegNum<[26]>; +  def X27 : RISCVReg<27,"x27", ["s11"]>, DwarfRegNum<[27]>; +  def X28 : RISCVReg<28,"x28", ["t3"]>, DwarfRegNum<[28]>; +  def X29 : RISCVReg<29,"x29", ["t4"]>, DwarfRegNum<[29]>; +  def X30 : RISCVReg<30,"x30", ["t5"]>, DwarfRegNum<[30]>; +  def X31 : RISCVReg<31,"x31", ["t6"]>, DwarfRegNum<[31]>;  } -foreach Index = 0-31 in { -  def X#Index#_64 : RISCVReg64<!cast<RISCVReg32>("X"#Index#"_32")>, DwarfRegNum<[Index]>; +def XLenVT : ValueTypeByHwMode<[RV32, RV64, DefaultMode], +                               [i32,  i64,  i32]>; + +// The order of registers represents the preferred allocation sequence. +// Registers are listed in the order caller-save, callee-save, specials. +def GPR : RegisterClass<"RISCV", [XLenVT], 32, (add +    (sequence "X%u", 10, 17), +    (sequence "X%u", 5, 7), +    (sequence "X%u", 28, 31), +    (sequence "X%u", 8, 9), +    (sequence "X%u", 18, 27), +    (sequence "X%u", 0, 4) +  )> { +  let RegInfos = RegInfoByHwMode< +      [RV32,              RV64,              DefaultMode], +      [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} + +// The order of registers represents the preferred allocation sequence. +// Registers are listed in the order caller-save, callee-save, specials. +def GPRNoX0 : RegisterClass<"RISCV", [XLenVT], 32, (add +    (sequence "X%u", 10, 17), +    (sequence "X%u", 5, 7), +    (sequence "X%u", 28, 31), +    (sequence "X%u", 8, 9), +    (sequence "X%u", 18, 27), +    (sequence "X%u", 1, 4) +  )> { +  let RegInfos = RegInfoByHwMode< +      [RV32,              RV64,              DefaultMode], +      [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>;  } -// We currently define separate register classes for the 32-bit and 64-bit -// GPRs. Once variable-sized register classes -// <http://lists.llvm.org/pipermail/llvm-dev/2016-September/105027.html> or -// similar are implemented, we can just use one 'GPR' class for most -// instruction definitions. +def GPRNoX0X2 : RegisterClass<"RISCV", [XLenVT], 32, (add +    (sequence "X%u", 10, 17), +    (sequence "X%u", 5, 7), +    (sequence "X%u", 28, 31), +    (sequence "X%u", 8, 9), +    (sequence "X%u", 18, 27), +    X1, X3, X4 +  )> { +  let RegInfos = RegInfoByHwMode< +      [RV32,              RV64,              DefaultMode], +      [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} + +def GPRC : RegisterClass<"RISCV", [XLenVT], 32, (add +    (sequence "X%u", 10, 15), +    (sequence "X%u", 8, 9) +  )> { +  let RegInfos = RegInfoByHwMode< +      [RV32,              RV64,              DefaultMode], +      [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} + +def SP : RegisterClass<"RISCV", [XLenVT], 32, (add X2)> { +  let RegInfos = RegInfoByHwMode< +      [RV32,              RV64,              DefaultMode], +      [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} + +// Floating point registers +let RegAltNameIndices = [ABIRegAltName] in { +  def F0_32  : RISCVReg32<0, "f0", ["ft0"]>, DwarfRegNum<[32]>; +  def F1_32  : RISCVReg32<1, "f1", ["ft1"]>, DwarfRegNum<[33]>; +  def F2_32  : RISCVReg32<2, "f2", ["ft2"]>, DwarfRegNum<[34]>; +  def F3_32  : RISCVReg32<3, "f3", ["ft3"]>, DwarfRegNum<[35]>; +  def F4_32  : RISCVReg32<4, "f4", ["ft4"]>, DwarfRegNum<[36]>; +  def F5_32  : RISCVReg32<5, "f5", ["ft5"]>, DwarfRegNum<[37]>; +  def F6_32  : RISCVReg32<6, "f6", ["ft6"]>, DwarfRegNum<[38]>; +  def F7_32  : RISCVReg32<7, "f7", ["ft7"]>, DwarfRegNum<[39]>; +  def F8_32  : RISCVReg32<8, "f8", ["fs0"]>, DwarfRegNum<[40]>; +  def F9_32  : RISCVReg32<9, "f9", ["fs1"]>, DwarfRegNum<[41]>; +  def F10_32 : RISCVReg32<10,"f10", ["fa0"]>, DwarfRegNum<[42]>; +  def F11_32 : RISCVReg32<11,"f11", ["fa1"]>, DwarfRegNum<[43]>; +  def F12_32 : RISCVReg32<12,"f12", ["fa2"]>, DwarfRegNum<[44]>; +  def F13_32 : RISCVReg32<13,"f13", ["fa3"]>, DwarfRegNum<[45]>; +  def F14_32 : RISCVReg32<14,"f14", ["fa4"]>, DwarfRegNum<[46]>; +  def F15_32 : RISCVReg32<15,"f15", ["fa5"]>, DwarfRegNum<[47]>; +  def F16_32 : RISCVReg32<16,"f16", ["fa6"]>, DwarfRegNum<[48]>; +  def F17_32 : RISCVReg32<17,"f17", ["fa7"]>, DwarfRegNum<[49]>; +  def F18_32 : RISCVReg32<18,"f18", ["fs2"]>, DwarfRegNum<[50]>; +  def F19_32 : RISCVReg32<19,"f19", ["fs3"]>, DwarfRegNum<[51]>; +  def F20_32 : RISCVReg32<20,"f20", ["fs4"]>, DwarfRegNum<[52]>; +  def F21_32 : RISCVReg32<21,"f21", ["fs5"]>, DwarfRegNum<[53]>; +  def F22_32 : RISCVReg32<22,"f22", ["fs6"]>, DwarfRegNum<[54]>; +  def F23_32 : RISCVReg32<23,"f23", ["fs7"]>, DwarfRegNum<[55]>; +  def F24_32 : RISCVReg32<24,"f24", ["fs8"]>, DwarfRegNum<[56]>; +  def F25_32 : RISCVReg32<25,"f25", ["fs9"]>, DwarfRegNum<[57]>; +  def F26_32 : RISCVReg32<26,"f26", ["fs10"]>, DwarfRegNum<[58]>; +  def F27_32 : RISCVReg32<27,"f27", ["fs11"]>, DwarfRegNum<[59]>; +  def F28_32 : RISCVReg32<28,"f28", ["ft8"]>, DwarfRegNum<[60]>; +  def F29_32 : RISCVReg32<29,"f29", ["ft9"]>, DwarfRegNum<[61]>; +  def F30_32 : RISCVReg32<30,"f30", ["ft10"]>, DwarfRegNum<[62]>; +  def F31_32 : RISCVReg32<31,"f31", ["ft11"]>, DwarfRegNum<[63]>; + +  foreach Index = 0-31 in { +    def F#Index#_64 : RISCVReg64<!cast<RISCVReg32>("F"#Index#"_32")>, +      DwarfRegNum<[!add(Index, 32)]>; +  } +} + +// The order of registers represents the preferred allocation sequence, +// meaning caller-save regs are listed before callee-save. +def FPR32 : RegisterClass<"RISCV", [f32], 32, (add +    (sequence "F%u_32", 0, 7), +    (sequence "F%u_32", 10, 17), +    (sequence "F%u_32", 28, 31), +    (sequence "F%u_32", 8, 9), +    (sequence "F%u_32", 18, 27) +)>; + +def FPR32C : RegisterClass<"RISCV", [f32], 32, (add +  (sequence "F%u_32", 10, 15), +  (sequence "F%u_32", 8, 9) +)>; -// TODO: once codegen is implemented, registers should be listed in an order -// reflecting the preferred register allocation sequence. -def GPR : RegisterClass<"RISCV", [i32], 32, (add -  (sequence "X%u_32", 0, 31) +// The order of registers represents the preferred allocation sequence, +// meaning caller-save regs are listed before callee-save. +def FPR64 : RegisterClass<"RISCV", [f64], 64, (add +    (sequence "F%u_64", 0, 7), +    (sequence "F%u_64", 10, 17), +    (sequence "F%u_64", 28, 31), +    (sequence "F%u_64", 8, 9), +    (sequence "F%u_64", 18, 27)  )>; -def GPR64 : RegisterClass<"RISCV", [i64], 64, (add -  (sequence "X%u_64", 0, 31) +def FPR64C : RegisterClass<"RISCV", [f64], 64, (add +  (sequence "F%u_64", 10, 15), +  (sequence "F%u_64", 8, 9)  )>; diff --git a/lib/Target/RISCV/RISCVSubtarget.cpp b/lib/Target/RISCV/RISCVSubtarget.cpp new file mode 100644 index 000000000000..b221ea84a33c --- /dev/null +++ b/lib/Target/RISCV/RISCVSubtarget.cpp @@ -0,0 +1,48 @@ +//===-- RISCVSubtarget.cpp - RISCV Subtarget Information ------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the RISCV specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "RISCVSubtarget.h" +#include "RISCV.h" +#include "RISCVFrameLowering.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscv-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "RISCVGenSubtargetInfo.inc" + +void RISCVSubtarget::anchor() {} + +RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies(StringRef CPU, +                                                                StringRef FS, +                                                                bool Is64Bit) { +  // Determine default and user-specified characteristics +  std::string CPUName = CPU; +  if (CPUName.empty()) +    CPUName = Is64Bit ? "generic-rv64" : "generic-rv32"; +  ParseSubtargetFeatures(CPUName, FS); +  if (Is64Bit) { +    XLenVT = MVT::i64; +    XLen = 64; +  } +  return *this; +} + +RISCVSubtarget::RISCVSubtarget(const Triple &TT, const std::string &CPU, +                               const std::string &FS, const TargetMachine &TM) +    : RISCVGenSubtargetInfo(TT, CPU, FS), +      FrameLowering(initializeSubtargetDependencies(CPU, FS, TT.isArch64Bit())), +      InstrInfo(), RegInfo(getHwMode()), TLInfo(TM, *this) {} diff --git a/lib/Target/RISCV/RISCVSubtarget.h b/lib/Target/RISCV/RISCVSubtarget.h new file mode 100644 index 000000000000..928ba5815a22 --- /dev/null +++ b/lib/Target/RISCV/RISCVSubtarget.h @@ -0,0 +1,85 @@ +//===-- RISCVSubtarget.h - Define Subtarget for the RISCV -------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the RISCV specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_RISCV_RISCVSUBTARGET_H +#define LLVM_LIB_TARGET_RISCV_RISCVSUBTARGET_H + +#include "RISCVFrameLowering.h" +#include "RISCVISelLowering.h" +#include "RISCVInstrInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "RISCVGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class RISCVSubtarget : public RISCVGenSubtargetInfo { +  virtual void anchor(); +  bool HasStdExtM = false; +  bool HasStdExtA = false; +  bool HasStdExtF = false; +  bool HasStdExtD = false; +  bool HasStdExtC = false; +  bool HasRV64 = false; +  unsigned XLen = 32; +  MVT XLenVT = MVT::i32; +  RISCVFrameLowering FrameLowering; +  RISCVInstrInfo InstrInfo; +  RISCVRegisterInfo RegInfo; +  RISCVTargetLowering TLInfo; +  SelectionDAGTargetInfo TSInfo; + +  /// Initializes using the passed in CPU and feature strings so that we can +  /// use initializer lists for subtarget initialization. +  RISCVSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS, +                                                  bool Is64Bit); + +public: +  // Initializes the data members to match that of the specified triple. +  RISCVSubtarget(const Triple &TT, const std::string &CPU, +                 const std::string &FS, const TargetMachine &TM); + +  // Parses features string setting specified subtarget options. The +  // definition of this function is auto-generated by tblgen. +  void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + +  const RISCVFrameLowering *getFrameLowering() const override { +    return &FrameLowering; +  } +  const RISCVInstrInfo *getInstrInfo() const override { return &InstrInfo; } +  const RISCVRegisterInfo *getRegisterInfo() const override { +    return &RegInfo; +  } +  const RISCVTargetLowering *getTargetLowering() const override { +    return &TLInfo; +  } +  const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { +    return &TSInfo; +  } +  bool hasStdExtM() const { return HasStdExtM; } +  bool hasStdExtA() const { return HasStdExtA; } +  bool hasStdExtF() const { return HasStdExtF; } +  bool hasStdExtD() const { return HasStdExtD; } +  bool hasStdExtC() const { return HasStdExtC; } +  bool is64Bit() const { return HasRV64; } +  MVT getXLenVT() const { return XLenVT; } +  unsigned getXLen() const { return XLen; } +}; +} // End llvm namespace + +#endif diff --git a/lib/Target/RISCV/RISCVTargetMachine.cpp b/lib/Target/RISCV/RISCVTargetMachine.cpp index 744d7b8aaa3a..e12168b73999 100644 --- a/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -11,6 +11,7 @@  //  //===----------------------------------------------------------------------===// +#include "RISCV.h"  #include "RISCVTargetMachine.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/CodeGen/Passes.h" @@ -29,7 +30,7 @@ extern "C" void LLVMInitializeRISCVTarget() {  static std::string computeDataLayout(const Triple &TT) {    if (TT.isArch64Bit()) { -    return "e-m:e-i64:64-n32:64-S128"; +    return "e-m:e-p:64:64-i64:64-i128:128-n64-S128";    } else {      assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");      return "e-m:e-p:32:32-i64:64-n32-S128"; @@ -43,18 +44,46 @@ static Reloc::Model getEffectiveRelocModel(const Triple &TT,    return *RM;  } +static CodeModel::Model getEffectiveCodeModel(Optional<CodeModel::Model> CM) { +  if (CM) +    return *CM; +  return CodeModel::Small; +} +  RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT,                                         StringRef CPU, StringRef FS,                                         const TargetOptions &Options,                                         Optional<Reloc::Model> RM, -                                       CodeModel::Model CM, -                                       CodeGenOpt::Level OL) +                                       Optional<CodeModel::Model> CM, +                                       CodeGenOpt::Level OL, bool JIT)      : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, -                        getEffectiveRelocModel(TT, RM), CM, OL), -      TLOF(make_unique<TargetLoweringObjectFileELF>()) { +                        getEffectiveRelocModel(TT, RM), +                        getEffectiveCodeModel(CM), OL), +      TLOF(make_unique<TargetLoweringObjectFileELF>()), +      Subtarget(TT, CPU, FS, *this) {    initAsmInfo();  } +namespace { +class RISCVPassConfig : public TargetPassConfig { +public: +  RISCVPassConfig(RISCVTargetMachine &TM, PassManagerBase &PM) +      : TargetPassConfig(TM, PM) {} + +  RISCVTargetMachine &getRISCVTargetMachine() const { +    return getTM<RISCVTargetMachine>(); +  } + +  bool addInstSelector() override; +}; +} +  TargetPassConfig *RISCVTargetMachine::createPassConfig(PassManagerBase &PM) { -  return new TargetPassConfig(*this, PM); +  return new RISCVPassConfig(*this, PM); +} + +bool RISCVPassConfig::addInstSelector() { +  addPass(createRISCVISelDag(getRISCVTargetMachine())); + +  return false;  } diff --git a/lib/Target/RISCV/RISCVTargetMachine.h b/lib/Target/RISCV/RISCVTargetMachine.h index d13e574c9bf8..02361dddebf7 100644 --- a/lib/Target/RISCV/RISCVTargetMachine.h +++ b/lib/Target/RISCV/RISCVTargetMachine.h @@ -15,6 +15,7 @@  #define LLVM_LIB_TARGET_RISCV_RISCVTARGETMACHINE_H  #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "RISCVSubtarget.h"  #include "llvm/CodeGen/SelectionDAGTargetInfo.h"  #include "llvm/IR/DataLayout.h"  #include "llvm/Target/TargetMachine.h" @@ -22,12 +23,17 @@  namespace llvm {  class RISCVTargetMachine : public LLVMTargetMachine {    std::unique_ptr<TargetLoweringObjectFile> TLOF; +  RISCVSubtarget Subtarget;  public:    RISCVTargetMachine(const Target &T, const Triple &TT, StringRef CPU,                       StringRef FS, const TargetOptions &Options, -                     Optional<Reloc::Model> RM, CodeModel::Model CM, -                     CodeGenOpt::Level OL); +                     Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, +                     CodeGenOpt::Level OL, bool JIT); + +  const RISCVSubtarget *getSubtargetImpl(const Function &) const override { +    return &Subtarget; +  }    TargetPassConfig *createPassConfig(PassManagerBase &PM) override; diff --git a/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp b/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp index 34932c259156..0f369d960fe1 100644 --- a/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp +++ b/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp @@ -24,7 +24,7 @@ Target &getTheRISCV64Target() {  extern "C" void LLVMInitializeRISCVTargetInfo() {    RegisterTarget<Triple::riscv32> X(getTheRISCV32Target(), "riscv32", -                                    "32-bit RISC-V"); +                                    "32-bit RISC-V", "RISCV");    RegisterTarget<Triple::riscv64> Y(getTheRISCV64Target(), "riscv64", -                                    "64-bit RISC-V"); +                                    "64-bit RISC-V", "RISCV");  }  | 
