From: Alex Bradbury Date: Thu, 7 Dec 2017 10:53:48 +0000 (+0000) Subject: [RISCV] MC layer support for the standard RV64I instructions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=06535b0f5a25e8e0d4220993ad2de5a0132cbbab;p=llvm [RISCV] MC layer support for the standard RV64I instructions git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@320024 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index ab5880a3646..588e39ee3cf 100644 --- a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -31,6 +31,7 @@ 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; @@ -91,6 +92,8 @@ struct RISCVOperand : public MCParsedAsmOperand { Immediate, } Kind; + bool IsRV64; + struct RegOp { unsigned RegNum; }; @@ -111,6 +114,7 @@ struct RISCVOperand : public MCParsedAsmOperand { public: RISCVOperand(const RISCVOperand &o) : MCParsedAsmOperand() { Kind = o.Kind; + IsRV64 = o.IsRV64; StartLoc = o.StartLoc; EndLoc = o.EndLoc; switch (Kind) { @@ -202,6 +206,16 @@ public: 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 isUImm5() const { int64_t Imm; RISCVMCExpr::VariantKind VK; @@ -259,6 +273,8 @@ public: 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!"); @@ -290,29 +306,33 @@ public: } } - static std::unique_ptr createToken(StringRef Str, SMLoc S) { + static std::unique_ptr createToken(StringRef Str, SMLoc S, + bool IsRV64) { auto Op = make_unique(Token); Op->Tok = Str; Op->StartLoc = S; Op->EndLoc = S; + Op->IsRV64 = IsRV64; return Op; } static std::unique_ptr createReg(unsigned RegNo, SMLoc S, - SMLoc E) { + SMLoc E, bool IsRV64) { auto Op = make_unique(Register); Op->Reg.RegNum = RegNo; Op->StartLoc = S; Op->EndLoc = E; + Op->IsRV64 = IsRV64; return Op; } static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, - SMLoc E) { + SMLoc E, bool IsRV64) { auto Op = make_unique(Immediate); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; + Op->IsRV64 = IsRV64; return Op; } @@ -482,6 +502,10 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, } 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_InvalidUImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); case Match_InvalidSImm12: @@ -562,16 +586,16 @@ OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands, } } if (HadParens) - Operands.push_back(RISCVOperand::createToken("(", FirstS)); + 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)); + Operands.push_back(RISCVOperand::createReg(RegNo, S, E, isRV64())); } if (HadParens) { getParser().Lex(); // Eat ')' - Operands.push_back(RISCVOperand::createToken(")", getLoc())); + Operands.push_back(RISCVOperand::createToken(")", getLoc(), isRV64())); } return MatchOperand_Success; @@ -605,7 +629,7 @@ OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { return parseOperandWithModifier(Operands); } - Operands.push_back(RISCVOperand::createImm(Res, S, E)); + Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); return MatchOperand_Success; } @@ -645,7 +669,7 @@ RISCVAsmParser::parseOperandWithModifier(OperandVector &Operands) { } const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, VK, getContext()); - Operands.push_back(RISCVOperand::createImm(ModExpr, S, E)); + Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, isRV64())); return MatchOperand_Success; } @@ -657,7 +681,7 @@ RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { } getParser().Lex(); // Eat '(' - Operands.push_back(RISCVOperand::createToken("(", getLoc())); + Operands.push_back(RISCVOperand::createToken("(", getLoc(), isRV64())); if (parseRegister(Operands) != MatchOperand_Success) { Error(getLoc(), "expected register"); @@ -670,7 +694,7 @@ RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { } getParser().Lex(); // Eat ')' - Operands.push_back(RISCVOperand::createToken(")", getLoc())); + Operands.push_back(RISCVOperand::createToken(")", getLoc(), isRV64())); return MatchOperand_Success; } @@ -700,7 +724,7 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { // First operand is token for instruction - Operands.push_back(RISCVOperand::createToken(Name, NameLoc)); + Operands.push_back(RISCVOperand::createToken(Name, NameLoc, isRV64())); // If there are no more operands, then finish if (getLexer().is(AsmToken::EndOfStatement)) diff --git a/lib/Target/RISCV/RISCV.td b/lib/Target/RISCV/RISCV.td index 3ebf76b8e59..88cf8c1831d 100644 --- a/lib/Target/RISCV/RISCV.td +++ b/lib/Target/RISCV/RISCV.td @@ -40,6 +40,8 @@ def HasStdExtD : Predicate<"Subtarget->hasStdExtD()">, def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; +def IsRV64 : Predicate<"Subtarget->is64Bit()">, + AssemblerPredicate<"Feature64Bit">; def RV64 : HwMode<"+64bit">; def RV32 : HwMode<"-64bit">; diff --git a/lib/Target/RISCV/RISCVInstrFormats.td b/lib/Target/RISCV/RISCVInstrFormats.td index ca368792340..83a62cdb52f 100644 --- a/lib/Target/RISCV/RISCVInstrFormats.td +++ b/lib/Target/RISCV/RISCVInstrFormats.td @@ -188,6 +188,23 @@ class RVInstI funct3, RISCVOpcode opcode, dag outs, dag ins, class RVInstIShift funct3, RISCVOpcode opcode, dag outs, dag ins, string opcodestr, string argstr> : RVInst { + 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 RVInstIShiftW funct3, RISCVOpcode opcode, + dag outs, dag ins, string opcodestr, string argstr> + : RVInst { bits<5> shamt; bits<5> rs1; bits<5> rd; diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td index cd500876c62..37e66a8faa6 100644 --- a/lib/Target/RISCV/RISCVInstrInfo.td +++ b/lib/Target/RISCV/RISCVInstrInfo.td @@ -69,6 +69,22 @@ def fencearg : Operand { let DecoderMethod = "decodeUImmOperand<4>"; } +def UImmLog2XLenAsmOperand : AsmOperandClass { + let Name = "UImmLog2XLen"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "InvalidUImmLog2XLen"; +} + +def uimmlog2xlen : Operand, ImmLeafis64Bit()) + 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, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<5>; let DecoderMethod = "decodeUImmOperand<5>"; @@ -161,7 +177,7 @@ class ALU_ri funct3, string opcodestr> let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in class Shift_ri funct3, string opcodestr> : RVInstIShift; let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in @@ -180,6 +196,17 @@ class CSR_ii funct3, string opcodestr> : (ins uimm12:$imm12, uimm5:$rs1), opcodestr, "$rd, $imm12, $rs1">; +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class ShiftW_ri funct3, string opcodestr> + : RVInstIShiftW; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class ALUW_rr funct7, bits<3> funct3, string opcodestr> + : RVInstR; + //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// @@ -279,6 +306,29 @@ 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] + //===----------------------------------------------------------------------===// // Pseudo-instructions and codegen patterns // @@ -293,9 +343,9 @@ class PatGprGpr : Pat<(OpNode GPR:$rs1, GPR:$rs2), (Inst GPR:$rs1, GPR:$rs2)>; class PatGprSimm12 : Pat<(OpNode GPR:$rs1, simm12:$imm12), (Inst GPR:$rs1, simm12:$imm12)>; -class PatGprUimm5 - : Pat<(OpNode GPR:$rs1, uimm5:$shamt), - (Inst GPR:$rs1, uimm5:$shamt)>; +class PatGprUimmLog2XLen + : Pat<(OpNode GPR:$rs1, uimmlog2xlen:$shamt), + (Inst GPR:$rs1, uimmlog2xlen:$shamt)>; /// Immediates @@ -315,11 +365,11 @@ def : PatGprSimm12; def : PatGprGpr; def : PatGprSimm12; def : PatGprGpr; -def : PatGprUimm5; +def : PatGprUimmLog2XLen; def : PatGprGpr; -def : PatGprUimm5; +def : PatGprUimmLog2XLen; def : PatGprGpr; -def : PatGprUimm5; +def : PatGprUimmLog2XLen; /// Setcc diff --git a/test/MC/RISCV/rv32i-invalid.s b/test/MC/RISCV/rv32i-invalid.s index d5f98e72626..938298e4347 100644 --- a/test/MC/RISCV/rv32i-invalid.s +++ b/test/MC/RISCV/rv32i-invalid.s @@ -111,8 +111,8 @@ slti a10, a2, 0x20 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction slt x32, s0, s0 # CHECK: :[[@LINE]]:5: error: invalid operand for instruction # RV64I mnemonics -addiw a0, sp, 100 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic -sraw t0, s2, zero # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic +addiw a0, sp, 100 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled +sraw t0, s2, zero # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled # Invalid operand types xori sp, 22, 220 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction diff --git a/test/MC/RISCV/rv64i-invalid.s b/test/MC/RISCV/rv64i-invalid.s new file mode 100644 index 00000000000..d35fada3874 --- /dev/null +++ b/test/MC/RISCV/rv64i-invalid.s @@ -0,0 +1,20 @@ +# RUN: not llvm-mc -triple riscv64 < %s 2>&1 | FileCheck %s + +# Out of range immediates +## uimm5 +slliw a0, a0, 32 # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 31] +srliw a0, a0, -1 # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 31] +sraiw a0, a0, -19 # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 31] + +## simm12 +addiw a0, a1, -2049 # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [-2048, 2047] +ld ra, 2048(sp) # CHECK: :[[@LINE]]:8: error: immediate must be an integer in the range [-2048, 2047] + +# Illegal operand modifier +## uimm5 +slliw a0, a0, %lo(1) # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 31] +srliw a0, a0, %lo(a) # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 31] +sraiw a0, a0, %hi(2) # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 31] + +## simm12 +addiw a0, a1, %hi(foo) # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [-2048, 2047] diff --git a/test/MC/RISCV/rv64i-valid.s b/test/MC/RISCV/rv64i-valid.s new file mode 100644 index 00000000000..d33b1d1ef43 --- /dev/null +++ b/test/MC/RISCV/rv64i-valid.s @@ -0,0 +1,98 @@ +# RUN: llvm-mc %s -triple=riscv64 -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s + +# CHECK-INST: lwu zero, 4(ra) +# CHECK: encoding: [0x03,0xe0,0x40,0x00] +lwu x0, 4(x1) +# CHECK-INST: lwu sp, 4(gp) +# CHECK: encoding: [0x03,0xe1,0x41,0x00] +lwu x2, +4(x3) +# CHECK-INST: lwu tp, -2048(t0) +# CHECK: encoding: [0x03,0xe2,0x02,0x80] +lwu x4, -2048(x5) +# CHECK-INST: lwu t1, -2048(t2) +# CHECK: encoding: [0x03,0xe3,0x03,0x80] +lwu x6, %lo(2048)(x7) +# CHECK-INST: lwu s0, 2047(s1) +# CHECK: encoding: [0x03,0xe4,0xf4,0x7f] +lwu x8, 2047(x9) + +# CHECK-INST: ld a0, -2048(a1) +# CHECK: encoding: [0x03,0xb5,0x05,0x80] +ld x10, -2048(x11) +# CHECK-INST: ld a2, -2048(a3) +# CHECK: encoding: [0x03,0xb6,0x06,0x80] +ld x12, %lo(2048)(x13) +# CHECK-INST: ld a4, 2047(a5) +# CHECK: encoding: [0x03,0xb7,0xf7,0x7f] +ld x14, 2047(x15) + +# CHECK-INST: sd a6, -2048(a7) +# CHECK: encoding: [0x23,0xb0,0x08,0x81] +sd x16, -2048(x17) +# CHECK-INST: sd s2, -2048(s3) +# CHECK: encoding: [0x23,0xb0,0x29,0x81] +sd x18, %lo(2048)(x19) +# CHECK-INST: sd s4, 2047(s5) +# CHECK: encoding: [0xa3,0xbf,0x4a,0x7f] +sd x20, 2047(x21) + +# CHECK-INST: slli s6, s7, 45 +# CHECK: encoding: [0x13,0x9b,0xdb,0x02] +slli x22, x23, 45 +# CHECK-INST: srli s8, s9, 0 +# CHECK: encoding: [0x13,0xdc,0x0c,0x00] +srli x24, x25, 0 +# CHECK-INST: srai s10, s11, 31 +# CHECK: encoding: [0x13,0xdd,0xfd,0x41] +srai x26, x27, 31 + +# CHECK-INST: addiw t3, t4, -2048 +# CHECK: encoding: [0x1b,0x8e,0x0e,0x80] +addiw x28, x29, -2048 +# CHECK-INST: addiw t5, t6, 2047 +# CHECK: encoding: [0x1b,0x8f,0xff,0x7f] +addiw x30, x31, 2047 + +# CHECK-INST: slliw zero, ra, 0 +# CHECK: encoding: [0x1b,0x90,0x00,0x00] +slliw zero, ra, 0 +# CHECK-INST: slliw sp, gp, 31 +# CHECK: encoding: [0x1b,0x91,0xf1,0x01] +slliw sp, gp, 31 +# CHECK-INST: srliw tp, t0, 0 +# CHECK: encoding: [0x1b,0xd2,0x02,0x00] +srliw tp, t0, 0 +# CHECK-INST: srliw t1, t2, 31 +# CHECK: encoding: [0x1b,0xd3,0xf3,0x01] +srliw t1, t2, 31 +# CHECK-INST: sraiw s0, s1, 0 +# CHECK: encoding: [0x1b,0xd4,0x04,0x40] +sraiw s0, s1, 0 +# CHECK-INST: sraiw a0, a1, 31 +# CHECK: encoding: [0x1b,0xd5,0xf5,0x41] +sraiw a0, a1, 31 + +# CHECK-INST: addw a2, a3, a4 +# CHECK: encoding: [0x3b,0x86,0xe6,0x00] +addw a2, a3, a4 +# CHECK-INST: addw a5, a6, a7 +# CHECK: encoding: [0xbb,0x07,0x18,0x01] +addw a5, a6, a7 +# CHECK-INST: subw s2, s3, s4 +# CHECK: encoding: [0x3b,0x89,0x49,0x41] +subw s2, s3, s4 +# CHECK-INST: subw s5, s6, s7 +# CHECK: encoding: [0xbb,0x0a,0x7b,0x41] +subw s5, s6, s7 +# CHECK-INST: sllw s8, s9, s10 +# CHECK: encoding: [0x3b,0x9c,0xac,0x01] +sllw s8, s9, s10 +# CHECK-INST: srlw s11, t3, t4 +# CHECK: encoding: [0xbb,0x5d,0xde,0x01] +srlw s11, t3, t4 +# CHECK-INST: sraw t5, t6, zero +# CHECK: encoding: [0x3b,0xdf,0x0f,0x40] +sraw t5, t6, zero