diff options
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 156 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 54 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 19 | ||||
-rw-r--r-- | llvm/lib/Target/RISCV/RISCVInstrInfo.td | 148 |
6 files changed, 378 insertions, 14 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index cb820379bbb..4b1eec9ec86 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVBaseInfo.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -30,6 +31,9 @@ struct RISCVOperand; class RISCVAsmParser : public MCTargetAsmParser { SMLoc getLoc() const { return getParser().getTok().getLoc(); } + 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, @@ -48,6 +52,7 @@ class RISCVAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands); + OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); bool parseOperand(OperandVector &Operands); @@ -125,10 +130,57 @@ public: return static_cast<const MCConstantExpr *>(Val)->getValue(); } + // 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; + } + + bool isUImm5() const { + return (isConstantImm() && isUInt<5>(getConstantImm())); + } + bool isSImm12() const { return (isConstantImm() && isInt<12>(getConstantImm())); } + bool isUImm12() const { + return (isConstantImm() && isUInt<12>(getConstantImm())); + } + + bool isSImm13Lsb0() const { + return (isConstantImm() && isShiftedInt<12, 1>(getConstantImm())); + } + + bool isUImm20() const { + return (isConstantImm() && isUInt<20>(getConstantImm())); + } + + bool isSImm21Lsb0() const { + return (isConstantImm() && isShiftedInt<20, 1>(getConstantImm())); + } + /// 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 @@ -208,6 +260,24 @@ public: 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)); + } }; } // end anonymous namespace. @@ -215,13 +285,19 @@ public: #define GET_MATCHER_IMPLEMENTATION #include "RISCVGenAsmMatcher.inc" +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; - SMLoc ErrorLoc; switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) { default: @@ -234,8 +310,8 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(IDLoc, "instruction use requires an option to be enabled"); case Match_MnemonicFail: return Error(IDLoc, "unrecognized instruction mnemonic"); - case Match_InvalidOperand: - ErrorLoc = IDLoc; + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; if (ErrorInfo != ~0U) { if (ErrorInfo >= Operands.size()) return Error(ErrorLoc, "too few operands for instruction"); @@ -245,10 +321,30 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, ErrorLoc = IDLoc; } return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_InvalidUImm5: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); case Match_InvalidSImm12: + return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 11), + (1 << 11) - 1); + 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, - "immediate must be an integer in the range [-2048, 2047]"); + return Error( + ErrorLoc, + "operand must be formed of letters selected in-order from 'iorw'"); + } } llvm_unreachable("Unknown match type detected!"); @@ -292,6 +388,10 @@ OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands) { } 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; @@ -300,16 +400,46 @@ OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { 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; } + } - const MCExpr *IdVal; - SMLoc S = getLoc(); - if (getParser().parseExpression(IdVal)) + Operands.push_back(RISCVOperand::createImm(Res, S, E)); + 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())); + + 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())); - SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); - Operands.push_back(RISCVOperand::createImm(IdVal, S, E)); return MatchOperand_Success; } @@ -322,8 +452,12 @@ bool RISCVAsmParser::parseOperand(OperandVector &Operands) { return false; // Attempt to parse token as an immediate - if (parseImmediate(Operands) == MatchOperand_Success) + 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"); diff --git a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp index e55658e3968..6bc4ea2cd0d 100644 --- a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp +++ b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "RISCVInstPrinter.h" +#include "MCTargetDesc/RISCVBaseInfo.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -53,3 +54,16 @@ void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 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'; +} diff --git a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h index f378c6f18da..3bb4fa37f15 100644 --- a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h +++ b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.h @@ -32,6 +32,7 @@ public: void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, const char *Modifier = nullptr); + void printFenceArg(const MCInst *MI, unsigned OpNo, raw_ostream &O); // Autogenerated by tblgen. void printInstruction(const MCInst *MI, raw_ostream &O); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h new file mode 100644 index 00000000000..c3bf3213a98 --- /dev/null +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -0,0 +1,54 @@ +//===-- 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" + +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, + InstFormatI = 2, + InstFormatS = 3, + InstFormatSB = 4, + InstFormatU = 5, + InstFormatOther = 6, + + InstFormatMask = 15 +}; +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 +}; +} +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index 9309d493cef..eb0beb028ad 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -55,6 +55,10 @@ 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; }; } // end anonymous namespace @@ -88,4 +92,19 @@ 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; + } + + llvm_unreachable("Unhandled expression!"); +} + #include "RISCVGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index 93d13f79390..78b1c907f33 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -13,17 +13,59 @@ include "RISCVInstrFormats.td" -class SImmAsmOperand<int width> - : AsmOperandClass { - let Name = "SImm" # width; +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<i32> { + let ParserMatchClass = FenceArg; + let PrintMethod = "printFenceArg"; +} + +def uimm5 : Operand<i32> { + let ParserMatchClass = UImmAsmOperand<5>; +} + def simm12 : Operand<i32> { let ParserMatchClass = SImmAsmOperand<12>; } +def uimm12 : Operand<i32> { + let ParserMatchClass = UImmAsmOperand<12>; +} + +// A 13-bit signed immediate where the least significant bit is zero. +def simm13_lsb0 : Operand<i32> { + let ParserMatchClass = SImmAsmOperand<13, "Lsb0">; + let EncoderMethod = "getImmOpValueAsr1"; +} + +def uimm20 : Operand<i32> { + let ParserMatchClass = UImmAsmOperand<20>; +} + +// A 21-bit signed immediate where the least significant bit is zero. +def simm21_lsb0 : Operand<i32> { + let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; + let EncoderMethod = "getImmOpValueAsr1"; +} + // 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 @@ -32,6 +74,52 @@ def simm12 : Operand<i32> { // like <http://lists.llvm.org/pipermail/llvm-dev/2016-September/105027.html> // is adopted. +def LUI : FU<0b0110111, (outs GPR:$rd), (ins uimm20:$imm20), + "lui\t$rd, $imm20", []>; + +def AUIPC : FU<0b0010111, (outs GPR:$rd), (ins uimm20:$imm20), + "auipc\t$rd, $imm20", []>; + +def JAL : FUJ<0b1101111, (outs GPR:$rd), (ins simm21_lsb0:$imm20), + "jal\t$rd, $imm20", []>; + +def JALR : FI<0b000, 0b1100111, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), + "jalr\t$rd, $rs1, $imm12", []>; + +class Bcc<bits<3> funct3, string OpcodeStr> : + FSB<funct3, 0b1100011, (outs), (ins GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12), + OpcodeStr#"\t$rs1, $rs2, $imm12", []> { +} + +def BEQ : Bcc<0b000, "beq">; +def BNE : Bcc<0b001, "bne">; +def BLT : Bcc<0b100, "blt">; +def BGE : Bcc<0b101, "bge">; +def BLTU : Bcc<0b110, "bltu">; +def BGEU : Bcc<0b111, "bgeu">; + +class LD_ri<bits<3> funct3, string OpcodeStr> : + FI<funct3, 0b0000011, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), + OpcodeStr#"\t$rd, ${imm12}(${rs1})", []> { + let mayLoad = 1; +} + +def LB : LD_ri<0b000, "lb">; +def LH : LD_ri<0b001, "lh">; +def LW : LD_ri<0b010, "lw">; +def LBU : LD_ri<0b100, "lbu">; +def LHU : LD_ri<0b101, "lhu">; + +class ST_ri<bits<3> funct3, string OpcodeStr> : + FS<funct3, 0b0100011, (outs), (ins GPR:$rs1, GPR:$rs2, simm12:$imm12), + OpcodeStr#"\t$rs2, ${imm12}(${rs1})", []> { + let mayStore = 1; +} + +def SB : ST_ri<0b000, "sb">; +def SH : ST_ri<0b001, "sh">; +def SW : ST_ri<0b010, "sw">; + class ALU_ri<bits<3> funct3, string OpcodeStr> : FI<funct3, 0b0010011, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), OpcodeStr#"\t$rd, $rs1, $imm12", []> @@ -45,6 +133,16 @@ def XORI : ALU_ri<0b100, "xori">; def ORI : ALU_ri<0b110, "ori">; def ANDI : ALU_ri<0b111, "andi">; +class SHIFT32_ri<bit arithshift, bits<3> funct3, string OpcodeStr> : + FI32Shift<arithshift, funct3, 0b0010011, (outs GPR:$rd), (ins GPR:$rs1, uimm5:$shamt), + OpcodeStr#"\t$rd, $rs1, $shamt", []> +{ +} + +def SLLI : SHIFT32_ri<0, 0b001, "slli">; +def SRLI : SHIFT32_ri<0, 0b101, "srli">; +def SRAI : SHIFT32_ri<1, 0b101, "srai">; + 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", []> @@ -62,3 +160,47 @@ def SRA : ALU_rr<0b0100000, 0b101, "sra">; def OR : ALU_rr<0b0000000, 0b110, "or">; def AND : ALU_rr<0b0000000, 0b111, "and">; +def FENCE : FI<0b000, 0b0001111, (outs), (ins fencearg:$pred, fencearg:$succ), + "fence\t$pred, $succ", []> { + bits<4> pred; + bits<4> succ; + + let rs1 = 0; + let rd = 0; + let imm12 = {0b0000,pred,succ}; +} + +def FENCEI : FI<0b001, 0b0001111, (outs), (ins), "fence.i", []> { + let rs1 = 0; + let rd = 0; + let imm12 = 0; +} + +let rs1=0, rd=0 in { + def ECALL : FI<0b000, 0b1110011, (outs), (ins), "ecall", []> { + let imm12=0; + } + def EBREAK : FI<0b000, 0b1110011, (outs), (ins), "ebreak", []> { + let imm12=1; + } +} + +class CSR_rr<bits<3> funct3, string OpcodeStr> : + FI<funct3, 0b1110011, (outs GPR:$rd), (ins uimm12:$imm12, GPR:$rs1), + OpcodeStr#"\t$rd, $imm12, $rs1", []> +{ +} + +def CSRRW : CSR_rr<0b001, "csrrw">; +def CSRRS : CSR_rr<0b010, "csrrs">; +def CSRRC : CSR_rr<0b011, "csrrc">; + +class CSR_ri<bits<3> funct3, string OpcodeStr> : + FI<funct3, 0b1110011, (outs GPR:$rd), (ins uimm12:$imm12, uimm5:$rs1), + OpcodeStr#"\t$rd, $imm12, $rs1", []> +{ +} + +def CSRRWI : CSR_ri<0b101, "csrrwi">; +def CSRRSI : CSR_ri<0b110, "csrrsi">; +def CSRRCI : CSR_ri<0b111, "csrrci">; |