Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -33,6 +33,8 @@ MCAsmLexer &getLexer() const { return Parser.getLexer(); } const MCSubtargetInfo &STI; + SMLoc getLoc() const { return getParser().getTok().getLoc(); } + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, @@ -51,6 +53,7 @@ OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands); + OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); bool parseOperand(OperandVector &Operands); @@ -137,6 +140,28 @@ return (isConstantImm() && isInt<12>(getConstantImm())); } + bool isimm20() const { + return (isConstantImm() && isUInt<20>(getConstantImm())); + } + + bool isimm4() const { + return (isConstantImm() && isUInt<4>(getConstantImm())); + } + + bool isimm5() const { + return (isConstantImm() && isUInt<5>(getConstantImm())); + } + + bool issimm21maskb0() const { + return (isConstantImm() && isInt<21>(getConstantImm()) && + getConstantImm() % 2 == 0); + } + + bool issimm13maskb0() const { + return (isConstantImm() && isInt<13>(getConstantImm()) && + getConstantImm() % 2 == 0); + } + /// 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 @@ -257,9 +282,28 @@ } return Error(ErrorLoc, "invalid operand for instruction"); case Match_Invalidsimm12: - SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "immediate must be an integer in the range [-2048, 2047]"); + case Match_Invalidimm4: + ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "immediate must be an integer in the range [0, 15]"); + case Match_Invalidimm5: + ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "immediate must be an integer in the range [0, 31]"); + case Match_Invalidimm20: + ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, + "immediate must be an integer in the range [0, 1048575]"); + case Match_Invalidsimm21maskb0: + ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "immediate must be a multiple of 2 bytes in the " + "range [-1048576, 1048574]"); + case Match_Invalidsimm13maskb0: + ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error( + ErrorLoc, + "immediate must be a multiple of 2 bytes in the range [-4096, 4094]"); } llvm_unreachable("Unknown match type detected!"); @@ -326,6 +370,32 @@ return MatchOperand_Success; } +RISCVAsmParser::OperandMatchResultTy +RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { + if (getLexer().getKind() != AsmToken::LParen) { + Error(getLoc(), "expected '('"); + return MatchOperand_ParseFail; + } + + Parser.Lex(); // Eat '(' + Operands.push_back(RISCVOperand::CreateToken("(", getLoc())); + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "expected register"); + return MatchOperand_ParseFail; + } + + if (getLexer().getKind() != AsmToken::RParen) { + Error(getLoc(), "expected ')'"); + return MatchOperand_ParseFail; + } + + Parser.Lex(); // Eat ')' + Operands.push_back(RISCVOperand::CreateToken(")", getLoc())); + + 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. @@ -335,8 +405,13 @@ 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().getKind() == AsmToken::LParen) { + return parseMemOpBaseReg(Operands) != MatchOperand_Success; + } return false; + } // Finally we have exhausted all options and must declare defeat. Error(Parser.getTok().getLoc(), "unknown operand"); Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -20,10 +20,78 @@ let DiagnosticType = !strconcat("Invalid", name); } +def imm4 : Operand { + let ParserMatchClass = ImmediateAsmOperand<"imm4">; +} + +def imm5 : Operand { + let ParserMatchClass = ImmediateAsmOperand<"imm5">; +} + def simm12 : Operand { let ParserMatchClass = ImmediateAsmOperand<"simm12">; } +def imm20 : Operand { + let ParserMatchClass = ImmediateAsmOperand<"imm20">; +} + +def simm21maskb0 : Operand { + let ParserMatchClass = ImmediateAsmOperand<"simm21maskb0">; +} + +def simm13maskb0 : Operand { + let ParserMatchClass = ImmediateAsmOperand<"simm13maskb0">; +} + +def LUI : FU<0b0110111, (outs GPR:$rd), (ins imm20:$imm20), + "lui\t$rd, $imm20", []>; + + +def AUIPC : FU<0b0010111, (outs GPR:$rd), (ins imm20:$imm20), + "auipc\t$rd, $imm20", []>; + +def JAL : FUJ<0b1101111, (outs GPR:$rd), (ins simm21maskb0:$imm21), + "jal\t$rd, $imm21", []>; + +def JALR : FI<0b1100111, 0b000, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), + "jalr\t$rd, $rs1, $imm12", []>; + +class Bcc funct3, string OpcodeStr> : + FSB<0b1100011, funct3, (outs), (ins GPR:$rs1, GPR:$rs2, simm13maskb0:$imm13), + !strconcat(OpcodeStr, "\t$rs1, $rs2, $imm13"), []> { +} + +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 funct3, string OpcodeStr> : + FI<0b0000011, funct3, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), + !strconcat(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 funct3, string OpcodeStr> : + FS<0b0100011, funct3, (outs), (ins GPR:$rs1, GPR:$rs2, simm12:$imm12), + !strconcat(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 funct3, string OpcodeStr> : FI<0b0010011, funct3, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12), !strconcat(OpcodeStr, "\t$rd, $rs1, $imm12"), []> @@ -37,6 +105,19 @@ def ORI : ALU_ri<0b110, "ori">; def ANDI : ALU_ri<0b111, "andi">; +// TODO: how to handle difference in the instruction for RV32I and RV64I. +// Should take an imm6 shamt and check in MatchAndEmitInstruction + +class SHIFT32_ri funct3, bit arithshift, string OpcodeStr> : + FI32Shift<0b0010011, funct3, arithshift, (outs GPR:$rd), (ins GPR:$rs1, imm5:$shamt), + !strconcat(OpcodeStr, "\t$rd, $rs1, $shamt"), []> +{ +} + +def SLLI : SHIFT32_ri<0b001, 0, "slli">; +def SRLI : SHIFT32_ri<0b101, 0, "srli">; +def SRAI : SHIFT32_ri<0b101, 1, "srai">; + class ALU_rr funct3, bits<7> funct7, string OpcodeStr> : FR<0b0110011, funct3, funct7, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), !strconcat(OpcodeStr, "\t$rd, $rs1, $rs2"), []> @@ -54,3 +135,45 @@ def OR : ALU_rr<0b110, 0b0000000, "or">; def AND : ALU_rr<0b111, 0b0000000, "and">; +def FENCE : RISCVInst<(outs), (ins imm4:$pred, imm4:$succ), "fence\t$pred, $succ", []> +{ + bits<4> pred; + bits<4> succ; + + let Opcode = 0b0001111; + let Inst{19-7} = 0; + let Inst{23-20} = succ; + let Inst{27-24} = pred; + let Inst{31-28} = 0; +} + +def FENCEI : RISCVInst<(outs), (ins), "fence.i", []> { + let Opcode = 0b0001111; + let Inst{11-7} = 0; + let Inst{14-12} = 0b001; + let Inst{31-15} = 0; +} + +let rs1=0, rd=0 in { + def SCALL : FI<0b1110011, 0b000, (outs), (ins), "scall", []> { + let imm12=0; + } + def SBREAK : FI<0b1110011, 0b000, (outs), (ins), "sbreak", []> { + let imm12=1; + } +} + +class RD_r csrid, string OpcodeStr> : + FI<0b1110011, 0b010, (outs GPR:$rd), (ins), + !strconcat(OpcodeStr, "\t$rd"), []> +{ + let rs1 = 0; + let imm12 = csrid; +} + +def RDCYCLE : RD_r<0b110000000000, "rdcycle">; +def RDCYCLEH : RD_r<0b110010000000, "rdcycleh">; +def RDTIME : RD_r<0b110000000001, "rdtime">; +def RDTIMEH : RD_r<0b110010000001, "rdtimeh">; +def RDINSTRET : RD_r<0b110000000010, "rdinstret">; +def RDINSTRETH : RD_r<0b110010000010, "rdinstreth">; Index: test/MC/RISCV/rv32i-invalid.s =================================================================== --- test/MC/RISCV/rv32i-invalid.s +++ test/MC/RISCV/rv32i-invalid.s @@ -1,9 +1,41 @@ # RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s # Out of range immediates +## simm12 ori a0, a1, -2049 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-2048, 2047] andi ra, sp, 2048 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [-2048, 2047] +## imm20 +lui a0, -1 # CHECK: :[[@LINE]]:9: error: immediate must be an integer in the range [0, 1048575] +lui s0, 1048576 # CHECK: :[[@LINE]]:9: error: immediate must be an integer in the range [0, 1048575] +auipc zero, -0xf # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [0, 1048575] + +## simm21maskb0 +jal gp, -1048578 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, -1048577 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, 1048575 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, 1048576 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] +jal gp, 1 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] + +## simm13maskb0 +beq t0, t1, -4098 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bne t0, t1, -4097 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +blt t0, t1, 4095 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bge t0, t1, 4096 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bltu t0, t1, 13 # CHECK: :[[@LINE]]:14: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] +bgeu t0, t1, -13 # CHECK: :[[@LINE]]:14: error: immediate must be a multiple of 2 bytes in the range [-4096, 4094] + +## imm5 +slli a0, a0, 32 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31] +srli a0, a0, -1 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31] +srai a0, a0, -19 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 31] + +## imm4 +fence -1, 0 # CHECK: :[[@LINE]]:7: error: immediate must be an integer in the range [0, 15] +fence 0, -1 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [0, 15] +fence 16, 0 # CHECK: :[[@LINE]]:7: error: immediate must be an integer in the range [0, 15] +fence 0, 16 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [0, 15] + # Invalid mnemonics subs t0, t2, t1 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic nandi t0, zero, 0 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic Index: test/MC/RISCV/rv32i-valid.s =================================================================== --- test/MC/RISCV/rv32i-valid.s +++ test/MC/RISCV/rv32i-valid.s @@ -1,6 +1,43 @@ # RUN: llvm-mc %s -triple=riscv32 -show-encoding | FileCheck %s # RUN: llvm-mc %s -triple=riscv64 -show-encoding | FileCheck %s +lui a0, 2 # CHECK: encoding: [0x37,0x25,0x00,0x00] +lui s11, (0x87000000>>12) # CHECK: encoding: [0xb7,0x0d,0x00,0x87] +lui t0, 1048575 # CHECK: encoding: [0xb7,0xf2,0xff,0xff] +lui gp, 0 # CHECK: encoding: [0xb7,0x01,0x00,0x00] + +auipc a0, 2 # CHECK: encoding: [0x17,0x25,0x00,0x00] +auipc s11, (0x87000000>>12) # CHECK: encoding: [0x97,0x0d,0x00,0x87] +auipc t0, 1048575 # CHECK: encoding: [0x97,0xf2,0xff,0xff] +auipc gp, 0 # CHECK: encoding: [0x97,0x01,0x00,0x00] + +jal a2, 1048574 # CHECK: encoding: [0x6f,0xf6,0xff,0x7f] +jal a3, 256 # CHECK: encoding: [0xef,0x06,0x00,0x10] + +jalr a0, a1, -2048 # CHECK: encoding: [0x67,0x85,0x05,0x80] +jalr t2, t1, 2047 # CHECK: encoding: [0xe7,0x03,0xf3,0x7f] +jalr sp, zero, 256 # CHECK: encoding: [0x67,0x01,0x00,0x10] + +beq s1, s1, 102 # CHECK: encoding: [0x63,0x83,0x94,0x06] +bne a4, a5, -4096 # CHECK: encoding: [0x63,0x10,0xf7,0x80] +blt sp, gp, 4094 # CHECK: encoding: [0xe3,0x4f,0x31,0x7e] +bge s2, ra, -224 # CHECK: encoding: [0xe3,0x50,0x19,0xf2] +bltu zero, zero, 0 # CHECK: encoding: [0x63,0x60,0x00,0x00] +bgeu s8, sp, 512 # CHECK: encoding: [0x63,0x70,0x2c,0x20] + + +lb s3, 4(ra) # CHECK: encoding: [0x83,0x89,0x40,0x00] +lb s3, +4(ra) # CHECK: encoding: [0x83,0x89,0x40,0x00] +lh t1, -2048(zero) # CHECK: encoding: [0x03,0x13,0x00,0x80] +lh sp, 2047(a0) # CHECK: encoding: [0x03,0x11,0xf5,0x7f] +lw a0, 97(a2) # CHECK: encoding: [0x03,0x25,0x16,0x06] +lbu s5, 0(s6) # CHECK: encoding: [0x83,0x4a,0x0b,0x00] +lhu t3, 255(t3) # CHECK: encoding: [0x03,0x5e,0xfe,0x0f] + +sb a0, 2047(a2) # CHECK: encoding: [0xa3,0x0f,0xa6,0x7e] +sh t3, -2048(t5) # CHECK: encoding: [0x23,0x10,0xcf,0x81] +sw ra, 999(zero) # CHECK: encoding: [0xa3,0x23,0x10,0x3e] + addi ra, sp, 2 # CHECK: encoding: [0x93,0x00,0x21,0x00] slti a0, a2, -20 # CHECK: encoding: [0x13,0x25,0xc6,0xfe] sltiu s2, s3, 0x50 # CHECK: encoding: [0x13,0xb9,0x09,0x05] @@ -9,6 +46,10 @@ andi ra, sp, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f] andi x1, x2, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f] +slli t3, t3, 31 # CHECK: encoding: [0x13,0x1e,0xfe,0x01] +srli a0, a4, 0 # CHECK: encoding: [0x13,0x55,0x07,0x00] +srai a2, sp, 15 # CHECK: encoding: [0x13,0x56,0xf1,0x40] + add ra, zero, zero # CHECK: encoding: [0xb3,0x00,0x00,0x00] add x1, x0, x0 # CHECK: encoding: [0xb3,0x00,0x00,0x00] sub t0, t2, t1 # CHECK: encoding: [0xb3,0x82,0x63,0x40] @@ -21,3 +62,19 @@ sra t0, s2, zero # CHECK: encoding: [0xb3,0x52,0x09,0x40] or s10, t1, ra # CHECK: encoding: [0x33,0x6d,0x13,0x00] and a0, s2, s3 # CHECK: encoding: [0x33,0x75,0x39,0x01] + +# TODO: gnu assembler supports fence with no arguments +fence 0, 15 # CHECK: encoding: [0x0f,0x00,0xf0,0x00] +fence 15, 0 # CHECK: encoding: [0x0f,0x00,0x00,0x0f] +fence 4, 9 # CHECK: encoding: [0x0f,0x00,0x90,0x04] +fence.i # CHECK: encoding: [0x0f,0x10,0x00,0x00] + +scall # CHECK: encoding: [0x73,0x00,0x00,0x00] +sbreak # CHECK: encoding: [0x73,0x00,0x10,0x00] + +rdcycle s0 # CHECK: encoding: [0x73,0x24,0x00,0xc0] +rdcycleh s1 # CHECK: encoding: [0xf3,0x24,0x00,0xc8] +rdtime s2 # CHECK: encoding: [0x73,0x29,0x10,0xc0] +rdtimeh s3 # CHECK: encoding: [0xf3,0x29,0x10,0xc8] +rdinstret s4 # CHECK: encoding: [0x73,0x2a,0x20,0xc0] +rdinstreth s5 # CHECK: encoding: [0xf3,0x2a,0x20,0xc8]