148 changes: 145 additions & 3 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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", []>
Expand All @@ -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", []>
Expand All @@ -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">;
50 changes: 47 additions & 3 deletions llvm/test/MC/RISCV/rv32i-invalid.s
Original file line number Diff line number Diff line change
@@ -1,17 +1,61 @@
# RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s

# Out of range immediates
## fencearg
fence iorw, iore # CHECK: :[[@LINE]]:13: error: operand must be formed of letters selected in-order from 'iorw'
fence wr, wr # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw'
fence rw, rr # CHECK: :[[@LINE]]:11: error: operand must be formed of letters selected in-order from 'iorw'
fence 1, rw # CHECK: :[[@LINE]]:7: error: operand must be formed of letters selected in-order from 'iorw'

## uimm5
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]
csrrwi a1, 0x1, -1 # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31]
csrrsi t1, 999, 32 # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31]
csrrci x0, 43, -90 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31]

## uimm12
csrrw a0, -1, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
csrrs a0, 4096, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
csrrs a0, -0xf, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
csrrc a0, 0x1000, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
csrrwi a0, -50, 0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095]
csrrsi a0, 4097, a0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095]
csrrci a0, 0xffff, a0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 4095]

## 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]

## simm13_lsb0
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]

## uimm20
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]

## simm21_lsb0
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]

# Invalid mnemonics
subs t0, t2, t1 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic
nandi t0, zero, 0 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic

# Invalid register names
addi foo, sp, 10 # CHECK: :[[@LINE]]:6: error: unknown operand
slti a10, a2, 0x20 # CHECK: :[[@LINE]]:6: error: unknown operand
slt x32, s0, s0 # CHECK: :[[@LINE]]:5: error: unknown operand
addi foo, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction
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
Expand Down
150 changes: 150 additions & 0 deletions llvm/test/MC/RISCV/rv32i-valid.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,100 @@
# RUN: llvm-mc %s -triple=riscv64 -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s

# CHECK-INST: lui a0, 2
# CHECK: encoding: [0x37,0x25,0x00,0x00]
lui a0, 2
# CHECK-INST: lui s11, 552960
# CHECK: encoding: [0xb7,0x0d,0x00,0x87]
lui s11, (0x87000000>>12)
# CHECK-INST: lui t0, 1048575
# CHECK: encoding: [0xb7,0xf2,0xff,0xff]
lui t0, 1048575
# CHECK-INST: lui gp, 0
# CHECK: encoding: [0xb7,0x01,0x00,0x00]
lui gp, 0

# CHECK-INST: auipc a0, 2
# CHECK: encoding: [0x17,0x25,0x00,0x00]
auipc a0, 2
# CHECK-INST: auipc s11, 552960
# CHECK: encoding: [0x97,0x0d,0x00,0x87]
auipc s11, (0x87000000>>12)
# CHECK-INST: auipc t0, 1048575
# CHECK: encoding: [0x97,0xf2,0xff,0xff]
auipc t0, 1048575
# CHECK-INST: auipc gp, 0
# CHECK: encoding: [0x97,0x01,0x00,0x00]
auipc gp, 0

# CHECK-INST: jal a2, 1048574
# CHECK: encoding: [0x6f,0xf6,0xff,0x7f]
jal a2, 1048574
# CHECK-INST: jal a3, 256
# CHECK: encoding: [0xef,0x06,0x00,0x10]
jal a3, 256

# CHECK-INST: jalr a0, a1, -2048
# CHECK: encoding: [0x67,0x85,0x05,0x80]
jalr a0, a1, -2048
# CHECK-INST: jalr t2, t1, 2047
# CHECK: encoding: [0xe7,0x03,0xf3,0x7f]
jalr t2, t1, 2047
# CHECK-INST: jalr sp, zero, 256
# CHECK: encoding: [0x67,0x01,0x00,0x10]
jalr sp, zero, 256

# CHECK-INST: beq s1, s1, 102
# CHECK: encoding: [0x63,0x83,0x94,0x06]
beq s1, s1, 102
# CHECK-INST: bne a4, a5, -4096
# CHECK: encoding: [0x63,0x10,0xf7,0x80]
bne a4, a5, -4096
# CHECK-INST: blt sp, gp, 4094
# CHECK: encoding: [0xe3,0x4f,0x31,0x7e]
blt sp, gp, 4094
# CHECK-INST: bge s2, ra, -224
# CHECK: encoding: [0xe3,0x50,0x19,0xf2]
bge s2, ra, -224
# CHECK-INST: bltu zero, zero, 0
# CHECK: encoding: [0x63,0x60,0x00,0x00]
bltu zero, zero, 0
# CHECK-INST: bgeu s8, sp, 512
# CHECK: encoding: [0x63,0x70,0x2c,0x20]
bgeu s8, sp, 512

# CHECK-INST: lb s3, 4(ra)
# CHECK: encoding: [0x83,0x89,0x40,0x00]
lb s3, 4(ra)
# CHECK-INST: lb s3, 4(ra)
# CHECK: encoding: [0x83,0x89,0x40,0x00]
lb s3, +4(ra)
# CHECK-INST: lh t1, -2048(zero)
# CHECK: encoding: [0x03,0x13,0x00,0x80]
lh t1, -2048(zero)
# CHECK-INST: lh sp, 2047(a0)
# CHECK: encoding: [0x03,0x11,0xf5,0x7f]
lh sp, 2047(a0)
# CHECK-INST: lw a0, 97(a2)
# CHECK: encoding: [0x03,0x25,0x16,0x06]
lw a0, 97(a2)
# CHECK-INST: lbu s5, 0(s6)
# CHECK: encoding: [0x83,0x4a,0x0b,0x00]
lbu s5, 0(s6)
# CHECK-INST: lhu t3, 255(t3)
# CHECK: encoding: [0x03,0x5e,0xfe,0x0f]
lhu t3, 255(t3)

# CHECK-INST: sb a0, 2047(a2)
# CHECK: encoding: [0xa3,0x0f,0xa6,0x7e]
sb a0, 2047(a2)
# CHECK-INST: sh t3, -2048(t5)
# CHECK: encoding: [0x23,0x10,0xcf,0x81]
sh t3, -2048(t5)
# CHECK-INST: sw ra, 999(zero)
# CHECK: encoding: [0xa3,0x23,0x10,0x3e]
sw ra, 999(zero)

# CHECK-INST: addi ra, sp, 2
# CHECK: encoding: [0x93,0x00,0x21,0x00]
addi ra, sp, 2
Expand All @@ -25,6 +119,16 @@ andi ra, sp, 2047
# CHECK: encoding: [0x93,0x70,0xf1,0x7f]
andi x1, x2, 2047

# CHECK-INST: slli t3, t3, 31
# CHECK: encoding: [0x13,0x1e,0xfe,0x01]
slli t3, t3, 31
# CHECK-INST: srli a0, a4, 0
# CHECK: encoding: [0x13,0x55,0x07,0x00]
srli a0, a4, 0
# CHECK-INST: srai a2, sp, 15
# CHECK: encoding: [0x13,0x56,0xf1,0x40]
srai a2, sp, 15

# CHECK-INST: add ra, zero, zero
# CHECK: encoding: [0xb3,0x00,0x00,0x00]
add ra, zero, zero
Expand Down Expand Up @@ -61,3 +165,49 @@ or s10, t1, ra
# CHECK-INST: and a0, s2, s3
# CHECK: encoding: [0x33,0x75,0x39,0x01]
and a0, s2, s3

# CHECK-INST: fence iorw, iorw
# CHECK: encoding: [0x0f,0x00,0xf0,0x0f]
fence iorw, iorw
# CHECK-INST: fence io, rw
# CHECK: encoding: [0x0f,0x00,0x30,0x0c]
fence io, rw
# CHECK-INST: fence r, w
# CHECK: encoding: [0x0f,0x00,0x10,0x02]
fence r,w
# CHECK-INST: fence w, ir
# CHECK: encoding: [0x0f,0x00,0xa0,0x01]
fence w,ir

# CHECK-INST: fence.i
# CHECK: encoding: [0x0f,0x10,0x00,0x00]
fence.i

# CHECK-INST: ecall
# CHECK: encoding: [0x73,0x00,0x00,0x00]
ecall
# CHECK-INST: ebreak
# CHECK: encoding: [0x73,0x00,0x10,0x00]
ebreak

# CHECK-INST: csrrw t0, 4095, t1
# CHECK: encoding: [0xf3,0x12,0xf3,0xff]
csrrw t0, 0xfff, t1
# CHECK-INST: csrrs s0, 3072, zero
# CHECK: encoding: [0x73,0x24,0x00,0xc0]
csrrs s0, 0xc00, x0
# CHECK-INST: csrrs s3, 1, s5
# CHECK: encoding: [0xf3,0xa9,0x1a,0x00]
csrrs s3, 0x001, s5
# CHECK-INST: csrrc sp, 0, ra
# CHECK: encoding: [0x73,0xb1,0x00,0x00]
csrrc sp, 0x000, ra
# CHECK-INST: csrrwi a5, 0, 0
# CHECK: encoding: [0xf3,0x57,0x00,0x00]
csrrwi a5, 0x000, 0
# CHECK-INST: csrrsi t2, 4095, 31
# CHECK: encoding: [0xf3,0xe3,0xff,0xff]
csrrsi t2, 0xfff, 31
# CHECK-INST: csrrci t1, 320, 5
# CHECK: encoding: [0x73,0xf3,0x02,0x14]
csrrci t1, 0x140, 5