Skip to content

Commit

Permalink
i#3544 RV64 vector part1: Added vector extension encoder/decoder supp…
Browse files Browse the repository at this point in the history
…ort (DynamoRIO#6810)

This is the first part of adding RISC-V vector (RVV) extension support
to the core.

RVV is a vector architecture similar to SVE, and its vector length
(VLEN) can vary from 64 up to 65536. For more information about RVV,
please refer to https://github.com/riscv/riscv-isa-manual.

The code itself is compiled and preliminarily tested on real hardware
with RVV (VLEN=256) support by running
https://github.com/riscv-non-isa/rvv-intrinsic-doc/blob/main/examples/rvv_strlen.c.

isl/v.txt is transformed from
https://github.com/riscv/riscv-opcodes/blob/master/rv_v by an off-tree
one-time python script.

Follow-up patches will address the following parts with RVV support:
- encoder/decoder unit tests;
- code cache context switch;
- clean-call;
- signal context;
- scatter/gather emulation;
- sample clients and dr$sim;
- and maybe more.

Issue: DynamoRIO#3544
  • Loading branch information
ksco authored May 14, 2024
1 parent 23ba134 commit f1ce1bc
Show file tree
Hide file tree
Showing 5 changed files with 754 additions and 5 deletions.
194 changes: 194 additions & 0 deletions core/ir/riscv64/codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,96 @@ decode_icrs1___opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *or
return true;
}

/* Decode the zimm immediate field in vsetivli instruction (V extension):
* |31 30|29 20|19 15|14 12|11 7|6 0|
* | ... | zimm10 | zimm | ... | rd | opcode |
* ^------^
*/
static bool
decode_zimm_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *orig_pc,
int idx, instr_t *out)
{
uint32_t imm = GET_FIELD(inst, 19, 15);
opnd_t opnd = opnd_create_immed_uint(imm, op_sz);
instr_set_src(out, idx, opnd);
return true;
}

/* Decode the zimm10 immediate field in vsetivli instruction (V extension):
* |31 30|29 20|19 15|14 12|11 7|6 0|
* | ... | zimm10 | zimm | ... | rd | opcode |
* ^--------^
*/
static bool
decode_zimm10_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *orig_pc,
int idx, instr_t *out)
{
uint32_t imm = GET_FIELD(inst, 29, 20);
opnd_t opnd = opnd_create_immed_uint(imm, op_sz);
instr_set_src(out, idx, opnd);
return true;
}

/* Decode the zimm11 immediate field in vsetvli instruction (V extension):
* |31|30 20|19 15|14 12|11 7|6 0|
* | | zimm11 | rs1 | ... | rd | opcode |
* ^--------^
*/
static bool
decode_zimm11_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *orig_pc,
int idx, instr_t *out)
{
uint32_t imm = GET_FIELD(inst, 30, 20);
opnd_t opnd = opnd_create_immed_uint(imm, op_sz);
instr_set_src(out, idx, opnd);
return true;
}

/* Decode the vm (vector mask) immediate field in vector instructions (V extension):
* |31 26| 25 |24 0|
* | ... | vm | ... |
* ^----^
*/
static bool
decode_vm_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *orig_pc, int idx,
instr_t *out)
{
uint32_t imm = GET_FIELD(inst, 25, 25);
opnd_t opnd = opnd_create_immed_uint(imm, op_sz);
instr_set_src(out, idx, opnd);
return true;
}

/* Decode the nf (nfields) immediate field in vector instructions (V extension):
* |31 29|28 0|
* | nf | ... |
* ^------^
*/
static bool
decode_nf_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *orig_pc, int idx,
instr_t *out)
{
uint32_t imm = GET_FIELD(inst, 31, 29);
opnd_t opnd = opnd_create_immed_uint(imm, op_sz);
instr_set_src(out, idx, opnd);
return true;
}

/* Decode the simm5 immediate field in vector instructions (V extension):
* |31 26| 25 |24 20|19 15|14 12|11 7|6 0|
* | funct6 | vm | vs2 | simm5 | ... | vd | opcode |
* ^-------^
*/
static bool
decode_simm5_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *orig_pc,
int idx, instr_t *out)
{
uint32_t imm = GET_FIELD(inst, 19, 15);
opnd_t opnd = opnd_create_immed_uint(imm, op_sz);
instr_set_src(out, idx, opnd);
return true;
}

/* Array of operand decode functions indexed by riscv64_fld_t.
*
* NOTE: After benchmarking, perhaps this could be placed in the same section as
Expand Down Expand Up @@ -1266,6 +1356,16 @@ opnd_dec_func_t opnd_decoders[] = {
[RISCV64_FLD_IIMM_0] = decode_iimm_0_opnd,
[RISCV64_FLD_ICRS1] = decode_icrs1_opnd,
[RISCV64_FLD_ICRS1__] = decode_icrs1___opnd,
[RISCV64_FLD_ZIMM] = decode_zimm_opnd,
[RISCV64_FLD_ZIMM10] = decode_zimm10_opnd,
[RISCV64_FLD_ZIMM11] = decode_zimm11_opnd,
[RISCV64_FLD_VM] = decode_vm_opnd,
[RISCV64_FLD_NF] = decode_nf_opnd,
[RISCV64_FLD_SIMM5] = decode_simm5_opnd,
[RISCV64_FLD_VD] = decode_rd_opnd,
[RISCV64_FLD_VS1] = decode_rs1_opnd,
[RISCV64_FLD_VS2] = decode_rs2_opnd,
[RISCV64_FLD_VS3] = decode_rd_opnd,
[RISCV64_FLD_I_S_RS1_DISP] = decode_v_s_rs1_disp_opnd,
};

Expand Down Expand Up @@ -2531,6 +2631,90 @@ encode_v_s_rs1_disp_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out,
return true;
}

/* Encode the zimm immediate field in vsetivli instruction (V extension):
* |31 30|29 20|19 15|14 12|11 7|6 0|
* | ... | zimm10 | zimm | ... | rd | opcode |
* ^------^
*/
static bool
encode_zimm_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_info_t *di)
{
opnd_t opnd = instr_get_src(instr, idx);
uint32_t imm = opnd_get_immed_int(opnd);
*out |= SET_FIELD(imm, 19, 15);
return true;
}

/* Encode the zimm10 immediate field in vsetivli instruction (V extension):
* |31 30|29 20|19 15|14 12|11 7|6 0|
* | ... | zimm10 | zimm | ... | rd | opcode |
* ^--------^
*/
static bool
encode_zimm10_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_info_t *di)
{
opnd_t opnd = instr_get_src(instr, idx);
uint32_t imm = opnd_get_immed_int(opnd);
*out |= SET_FIELD(imm, 29, 20);
return true;
}

/* Encode the zimm11 immediate field in vsetvli instruction (V extension):
* |31|30 20|19 15|14 12|11 7|6 0|
* | | zimm11 | rs1 | ... | rd | opcode |
* ^--------^
*/
static bool
encode_zimm11_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_info_t *di)
{
opnd_t opnd = instr_get_src(instr, idx);
uint32_t imm = opnd_get_immed_int(opnd);
*out |= SET_FIELD(imm, 30, 20);
return true;
}

/* Encode the vm (vector mask) immediate field in vector instructions (V extension):
* |31 26| 25 |24 0|
* | ... | vm | ... |
* ^----^
*/
static bool
encode_vm_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_info_t *di)
{
opnd_t opnd = instr_get_src(instr, idx);
uint32_t imm = opnd_get_immed_int(opnd);
*out |= SET_FIELD(imm, 25, 25);
return true;
}

/* Encode the nf (nfields) immediate field in vector instructions (V extension):
* |31 29|28 0|
* | nf | ... |
* ^------^
*/
static bool
encode_nf_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_info_t *di)
{
opnd_t opnd = instr_get_src(instr, idx);
uint32_t imm = opnd_get_immed_int(opnd);
*out |= SET_FIELD(imm, 31, 29);
return true;
}

/* Encode the simm5 immediate field in vector instructions (V extension):
* |31 26| 25 |24 20|19 15|14 12|11 7|6 0|
* | funct6 | vm | vs2 | simm5 | ... | vd | opcode |
* ^-------^
*/
static bool
encode_simm5_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_info_t *di)
{
opnd_t opnd = instr_get_src(instr, idx);
int32_t imm = opnd_get_immed_int(opnd);
*out |= SET_FIELD(imm, 19, 15);
return true;
}

/* Array of operand encode functions indexed by riscv64_fld_t. */
opnd_enc_func_t opnd_encoders[] = {
[RISCV64_FLD_NONE] = encode_none_opnd,
Expand Down Expand Up @@ -2595,6 +2779,16 @@ opnd_enc_func_t opnd_encoders[] = {
[RISCV64_FLD_IIMM_0] = encode_implicit_opnd,
[RISCV64_FLD_ICRS1] = encode_implicit_opnd,
[RISCV64_FLD_ICRS1__] = encode_implicit_opnd,
[RISCV64_FLD_ZIMM] = encode_zimm_opnd,
[RISCV64_FLD_ZIMM10] = encode_zimm10_opnd,
[RISCV64_FLD_ZIMM11] = encode_zimm11_opnd,
[RISCV64_FLD_VM] = encode_vm_opnd,
[RISCV64_FLD_NF] = encode_nf_opnd,
[RISCV64_FLD_SIMM5] = encode_simm5_opnd,
[RISCV64_FLD_VD] = encode_rd_opnd,
[RISCV64_FLD_VS1] = encode_rs1_opnd,
[RISCV64_FLD_VS2] = encode_rs2_opnd,
[RISCV64_FLD_VS3] = encode_rd_opnd,
[RISCV64_FLD_I_S_RS1_DISP] = encode_implicit_opnd,
};

Expand Down
12 changes: 12 additions & 0 deletions core/ir/riscv64/codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ typedef enum {
RISCV64_ISA_EXT_ZIFENCEI,
RISCV64_ISA_EXT_XTHEADCMO,
RISCV64_ISA_EXT_XTHEADSYNC,
RISCV64_ISA_EXT_V,
RISCV64_ISA_EXT_CNT, /* Keep this last */
} riscv64_isa_ext_t;

Expand Down Expand Up @@ -256,6 +257,17 @@ typedef enum {
RISCV64_FLD_ICRS1,
RISCV64_FLD_ICRS1__,
RISCV64_FLD_I_S_RS1_DISP,
/* Vector extension fields. */
RISCV64_FLD_ZIMM,
RISCV64_FLD_ZIMM10,
RISCV64_FLD_ZIMM11,
RISCV64_FLD_VM,
RISCV64_FLD_NF,
RISCV64_FLD_SIMM5,
RISCV64_FLD_VD,
RISCV64_FLD_VS1,
RISCV64_FLD_VS2,
RISCV64_FLD_VS3,
RISCV64_FLD_CNT, /* Keep this last */
} riscv64_fld_t;

Expand Down
109 changes: 104 additions & 5 deletions core/ir/riscv64/codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ def __new__(cls, value: int, arg_name: str, is_dest: bool, is_implicit: bool,
'',
'The immediate field in PREFETCH instructions.'
)
# Fields in compressed instructions.
CRD = (25,
'rd',
True,
Expand Down Expand Up @@ -394,7 +395,6 @@ def __new__(cls, value: int, arg_name: str, is_dest: bool, is_implicit: bool,
'',
'The second input floating-point register in `CR`, `CSS` RVC formats (inst[6:2]).'
)
# Fields in compressed instructions.
CRD_ = (30,
'rd',
True,
Expand Down Expand Up @@ -719,6 +719,97 @@ def __new__(cls, value: int, arg_name: str, is_dest: bool, is_implicit: bool,
'imm(rs1)',
'The register-relative memory target location (reg+imm).'
)
# Vector extension fields.
ZIMM = (64,
'zimm',
False,
False,
False,
'OPSZ_5b',
'',
'The immediate field in the vsetivli instruction.'
)
ZIMM10 = (65,
'zimm10',
False,
False,
False,
'OPSZ_10b',
'',
'The vtypei field in the vsetivli instruction.'
)
ZIMM11 = (66,
'zimm11',
False,
False,
False,
'OPSZ_11b',
'',
'The vtypei field in the vsetvli instruction.'
)
VM = (67,
'vm',
False,
False,
False,
'OPSZ_1b',
'',
'The vm field in vector instructions.'
)
NF = (68,
'nf',
False,
False,
False,
'OPSZ_3b',
'',
'The nfields field in vector instructions.'
)
SIMM5 = (69,
'simm5',
False,
False,
False,
'OPSZ_5b',
'',
'The immediate field in vector instructions.'
)
VD = (70,
'Vd',
True,
False,
False,
'OPSZ_PTR',
'',
'The output vector register (inst[11:7]).'
)
VS1 = (71,
'vs1',
False,
False,
False,
'OPSZ_PTR',
'',
'The first input vector register (inst[19:15]).'
)
VS2 = (72,
'vs2',
False,
False,
False,
'OPSZ_PTR',
'',
'The second input vector register (inst[24:20]).'
)
VS3 = (73,
'vs3',
False,
False,
False,
'OPSZ_PTR',
'',
'The third input vector register (inst[11:7]).'
)

def __str__(self) -> str:
return self.name.lower().replace("fp", "(fp)")
Expand Down Expand Up @@ -856,13 +947,21 @@ def __fixup_uncompressed_inst(self, inst: Instruction):
rs3 = ((inst.match & inst.mask) >> 27) & 0x1f
if opc in [0b0000011, 0b0000111]: # LOAD instructions
dbg(f'fixup: {inst.name} {[f.name for f in inst.flds]}')
inst.flds[0] = Field.V_L_RS1_DISP
inst.flds.pop(1)
if opc == 0b0000111 and funct3 in [0b000, 0b101, 0b110, 0b111]:
# Vector load instructions have no imm part
inst.flds[-2] = Field.V_L_RS1_DISP
else:
inst.flds[0] = Field.V_L_RS1_DISP
inst.flds.pop(1)
dbg(f' -> {" " * len(inst.name)} {[f.name for f in inst.flds]}')
elif opc in [0b0100011, 0b0100111]: # STORE instructions
dbg(f'fixup: {inst.name} {[f.name for f in inst.flds]}')
inst.flds[2] = Field.V_S_RS1_DISP
inst.flds.pop(0)
if opc == 0b0100111 and funct3 in [0b000, 0b101, 0b110, 0b111]:
# Vector store instructions have no imm part
inst.flds[-2] = Field.V_S_RS1_DISP
else:
inst.flds[2] = Field.V_S_RS1_DISP
inst.flds.pop(0)
dbg(f' -> {" " * len(inst.name)} {[f.name for f in inst.flds]}')
elif opc == 0b0101111 and (funct3 == 0b010 or funct3 == 0b011):
if rs3 == 0x2: # LR.W/D instructions
Expand Down
Loading

0 comments on commit f1ce1bc

Please sign in to comment.