summaryrefslogtreecommitdiff
path: root/lib/Target/RISCV
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/RISCV')
-rw-r--r--lib/Target/RISCV/AsmParser/CMakeLists.txt3
-rw-r--r--lib/Target/RISCV/AsmParser/LLVMBuild.txt23
-rw-r--r--lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp946
-rw-r--r--lib/Target/RISCV/CMakeLists.txt19
-rw-r--r--lib/Target/RISCV/Disassembler/CMakeLists.txt3
-rw-r--r--lib/Target/RISCV/Disassembler/LLVMBuild.txt24
-rw-r--r--lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp274
-rw-r--r--lib/Target/RISCV/InstPrinter/CMakeLists.txt3
-rw-r--r--lib/Target/RISCV/InstPrinter/LLVMBuild.txt23
-rw-r--r--lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp86
-rw-r--r--lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h48
-rw-r--r--lib/Target/RISCV/LLVMBuild.txt8
-rw-r--r--lib/Target/RISCV/MCTargetDesc/CMakeLists.txt3
-rw-r--r--lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt2
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp155
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h110
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp40
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h52
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp115
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp99
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h75
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp24
-rw-r--r--lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h8
-rw-r--r--lib/Target/RISCV/RISCV.h37
-rw-r--r--lib/Target/RISCV/RISCV.td73
-rw-r--r--lib/Target/RISCV/RISCVAsmPrinter.cpp72
-rw-r--r--lib/Target/RISCV/RISCVCallingConv.td20
-rw-r--r--lib/Target/RISCV/RISCVFrameLowering.cpp201
-rw-r--r--lib/Target/RISCV/RISCVFrameLowering.h57
-rw-r--r--lib/Target/RISCV/RISCVISelDAGToDAG.cpp108
-rw-r--r--lib/Target/RISCV/RISCVISelLowering.cpp892
-rw-r--r--lib/Target/RISCV/RISCVISelLowering.h84
-rw-r--r--lib/Target/RISCV/RISCVInstrFormats.td196
-rw-r--r--lib/Target/RISCV/RISCVInstrFormatsC.td147
-rw-r--r--lib/Target/RISCV/RISCVInstrInfo.cpp77
-rw-r--r--lib/Target/RISCV/RISCVInstrInfo.h46
-rw-r--r--lib/Target/RISCV/RISCVInstrInfo.td631
-rw-r--r--lib/Target/RISCV/RISCVInstrInfoA.td77
-rw-r--r--lib/Target/RISCV/RISCVInstrInfoC.td419
-rw-r--r--lib/Target/RISCV/RISCVInstrInfoD.td174
-rw-r--r--lib/Target/RISCV/RISCVInstrInfoF.td222
-rw-r--r--lib/Target/RISCV/RISCVInstrInfoM.td36
-rw-r--r--lib/Target/RISCV/RISCVMCInstLower.cpp105
-rw-r--r--lib/Target/RISCV/RISCVRegisterInfo.cpp93
-rw-r--r--lib/Target/RISCV/RISCVRegisterInfo.h45
-rw-r--r--lib/Target/RISCV/RISCVRegisterInfo.td242
-rw-r--r--lib/Target/RISCV/RISCVSubtarget.cpp48
-rw-r--r--lib/Target/RISCV/RISCVSubtarget.h85
-rw-r--r--lib/Target/RISCV/RISCVTargetMachine.cpp41
-rw-r--r--lib/Target/RISCV/RISCVTargetMachine.h10
-rw-r--r--lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp4
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");
}