-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support partial vector extension instructions #545
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Benchmarks
Benchmark suite | Current: 4da7057 | Previous: 1627a4b | Ratio |
---|---|---|---|
Dhrystone |
1340 Average DMIPS over 10 runs |
1333 Average DMIPS over 10 runs |
0.99 |
Coremark |
949.671 Average iterations/sec over 10 runs |
952.577 Average iterations/sec over 10 runs |
1.00 |
This comment was automatically generated by workflow using github-action-benchmark.
|
||
/* standard uncompressed instruction */ | ||
const uint32_t index = (insn & INSN_6_2) >> 2; | ||
static inline bool op_000000(rv_insn_t *ir, const uint32_t insn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
op_000000
looks misleading. Can you improve its naming scheme?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming scheme is based on the function6
field listed in riscv-v-spec/inst-table.adoc. Since each function6
may include OPI
, OPM
, or OPF
functions, often corresponding to unrelated operations. I chose to name them directly based on the function6
for consistency.
This might seem unclear without additional context. To improve clarity, I could add comments explaining the naming convention for each op_function6
. Would this address your concern?
Could we create an CI like using ROSCOF for this? |
I'm not familiar with ROSCOF, but I'll look into it and give it a try. |
Suggest using |
Thank you all for your feedback and suggestions! I will fix the typos, add a newline at the end of files, and remove any unnecessary elements. I also noticed that the current code does not fully meet the contributing guidelines, so I will make sure to address those issues. In addition, I will add more detailed comments in Since some of the code was misplaced from the beginning, and as @eleanorLYJ mentioned, there are non-compliant comments in an early commit, I’m considering I’d appreciate your guidance. Thank you! |
This comment was marked as resolved.
This comment was marked as resolved.
src/rv32_template.c
Outdated
} \ | ||
} | ||
|
||
#define VMV_LOOP(des, op1, op2, op, SHIFT, MASK, i, j, itr, vm) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may I ask where this is one used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The VMV_LOOP
macro is used in the implementation of vmv_v_i
(at src/rv32_template.c
, line 6366), as the riscv-vector-tests frequently utilize vmv_v_i
to clear bits in vector registers during each test. This serves as a quick implementation for the vmv_v_i
instruction.
Additionally, I noticed that the implementations of vmv_v_*
(representing vmv_v_v
, vmv_v_x
, and vmv_v_i
) can be refactored to reuse existing macros such as VV_LOOP
, VX_LOOP
, VI_LOOP
, and their _LEFT
variants (collectively referred to as V*_LOOP
and V*_LOOP_LEFT
). I will remove the VMV_LOOP
and related _LEFT
macros accordingly. Thank you for pointing this out!
if (decode_funct3(insn) != 0b010) { | ||
uint8_t eew = decode_eew(insn); | ||
ir->eew = 8 << eew; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding validation for eew
value before using it in shift operations. The decode_eew()
function can return -1 for invalid values, which could lead to undefined behavior when used in 8 << eew
.
Code suggestion
Check the AI-generated fix before applying
if (decode_funct3(insn) != 0b010) { | |
uint8_t eew = decode_eew(insn); | |
ir->eew = 8 << eew; | |
if (decode_funct3(insn) != 0b010) { | |
uint8_t eew = decode_eew(insn); | |
if (eew < 0) { | |
return false; | |
} | |
ir->eew = 8 << eew; |
Code Review Run #47f569
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
{ | ||
ir->vs2 = decode_rs2(insn); | ||
ir->imm = decode_v_imm(insn); | ||
ir->vd = decode_rd(insn); | ||
ir->vm = decode_vm(insn); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider validating the input parameters before accessing them. The decode_vitype
function directly accesses instruction fields without any validation of ir
or insn
parameters.
Code suggestion
Check the AI-generated fix before applying
{ | |
ir->vs2 = decode_rs2(insn); | |
ir->imm = decode_v_imm(insn); | |
ir->vd = decode_rd(insn); | |
ir->vm = decode_vm(insn); | |
} | |
{ | |
if (!ir) { | |
return; | |
} | |
ir->vs2 = decode_rs2(insn); | |
ir->imm = decode_v_imm(insn); | |
ir->vd = decode_rd(insn); | |
ir->vm = decode_vm(insn); | |
} |
Code Review Run #47f569
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
/* FIXME: Implement the decoding for vmv<nr>r. */ | ||
case 4: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The vmv<nr>r
instruction decoding is marked with a FIXME comment but has no implementation. This could lead to undefined behavior when this instruction is encountered.
Code suggestion
Check the AI-generated fix before applying
/* FIXME: Implement the decoding for vmv<nr>r. */ | |
case 4: | |
/* Not implemented */ | |
return false; | |
case 4: |
Code Review Run #47f569
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
static inline bool op_101110(rv_insn_t *ir, const uint32_t insn) | ||
{ | ||
switch (decode_funct3(insn)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider consolidating similar switch-case patterns across functions op_101110
through op_111100
. Many functions follow a similar pattern of decoding vector instructions with repeated code structure.
Code suggestion
Check the AI-generated fix before applying
static inline bool op_101110(rv_insn_t *ir, const uint32_t insn) | |
{ | |
switch (decode_funct3(insn)) { | |
static inline bool decode_vector_op(rv_insn_t *ir, const uint32_t insn, const rv_vec_op_t *op_table, size_t table_size) | |
{ | |
uint32_t funct3 = decode_funct3(insn); | |
if (funct3 >= table_size) { | |
return false; | |
} | |
const rv_vec_op_t *op = &op_table[funct3]; | |
if (!op->decode_fn) { | |
return false; | |
} | |
op->decode_fn(ir, insn); | |
ir->opcode = op->opcode; | |
return true; | |
} |
Code Review Run #47f569
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
Add decode stage for RISC-V "V" Vector extension instructions from version 1.0, excluding VXUNARY0, VRFUNARY0, VWFUNARY0, VFUNARY1, vmv<nr>r, and VFUNARY0. This commit focuses on the decode stage to ensure correct instructions parsing before proceeding to the execution stage. Verification is currently done through hand-written code. Modify Makefile to support VLEN configuration, via make ENABLE_EXT_V=1 VLEN=<value>. The default value for VLEN is set to 128. The current implementation only supports VLEN=128. Enabling ENABLE_EXT_V=1 will also enable ENABLE_EXT_F=1, as vector load/ store instruction shares the same opcode with load_fp and store_fp.
Add support for vset{i}vl{i} instructions following the RISC-V vector extension version 1.0. Simplify avlmax calculation by directly computing avlmax = lmul * vlen / sew instead of converting to floating-point as described in the specification.
Implement vle8_v, vle16_v, vle32_v, vse8_v, vse16_v, vse32_v. Using loop unrolling technique to handle a word at a time. The implementation assumes VLEN = 128. There are two types of illegal instructions: 1. When eew is narrower than csr_vl. Set vill in vtype to 1 and other bits to 0, set csr_vl to 0. 2. When LMUL > 1 and trying to access a vector register that is larger than 31. Use assert to handle this case.
To emulate vector registers of length VLEN using an array of uint32_t, we first handle different SEW values (8, 16, 32) using sew_*b_handler. Inside the handler, the V*_LOOP macro expands to process different VL values and operand types, along with its corresponding V*_LOOP_LEFT. The goal is to maximize code reuse by defining individual operations next to their respective vector instructions, which can be easily applied using the OPT() macro. V*_LOOP execution steps: 1. Copy the operand op1 (op2). 2. Align op1 to the right. 3. Perform the specified operation between op1 and op2. 4. Mask the result according to the corresponding SEW. 5. Shift the result left to align with the corresponding position. 6. Accumulate the result. In vector register groups, registers should follow the pattern v2*n, v2*n+1 when lmul = 2, etc. The current implementation allows using any vector registers except those exceeding v31. For vector masking, if the corresponding mask bit is 0, the value of the destination vector register is preserved. The process is as follows: 1. Copy the destination register. 2. Clear the bits corresponding to VL. 3. Store the computed result in ans. 4. Update the destination register with ans. If ir->vm == 0, vector masking is activated.
vssub_vv, | ||
{ | ||
for (int i = 0; i < 4; i++) { | ||
rv->V[rv_reg_zero][i] = 0; | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider refactoring the repetitive vector register initialization pattern. The same code block for (int i = 0; i < 4; i++) { rv->V[rv_reg_zero][i] = 0; }
appears in multiple vector operations which could be extracted into a helper function.
Code suggestion
Check the AI-generated fix before applying
vssub_vv, | |
{ | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
}, | |
static inline void init_vector_reg_zero(riscv_t *rv) { | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
} | |
vssub_vv, | |
{ | |
init_vector_reg_zero(rv); | |
}, |
Code Review Run #005f29
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
#define op_sll(a, b) \ | ||
((a) << ((b) & ((8 << ((rv->csr_vtype >> 3) & 0b111)) - 1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The shift amount calculation in op_sll
macro may need bounds checking to prevent undefined behavior when shifting by amounts >= bit width. Consider adding explicit bounds check.
Code suggestion
Check the AI-generated fix before applying
#define op_sll(a, b) \ | |
((a) << ((b) & ((8 << ((rv->csr_vtype >> 3) & 0b111)) - 1))) | |
#define op_sll(a, b) do { \ | |
int _shift = (b) & ((8 << ((rv->csr_vtype >> 3) & 0b111)) - 1); \ | |
_shift = _shift >= sizeof(a) * 8 ? sizeof(a) * 8 - 1 : _shift; \ | |
((a) << _shift); } while(0) |
Code Review Run #005f29
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
RVOP( | ||
vlseg8e8_v, | ||
{ | ||
for (int i = 0; i < 4; i++) { | ||
rv->V[rv_reg_zero][i] = 0; | ||
} | ||
}, | ||
GEN({/* no operation */})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider consolidating the repeated vector register initialization code blocks into a reusable helper function to reduce code duplication. Each vector instruction implementation currently contains identical initialization logic.
Code suggestion
Check the AI-generated fix before applying
RVOP( | |
vlseg8e8_v, | |
{ | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
}, | |
GEN({/* no operation */})) | |
static void init_vector_reg_zero(riscv_t *rv) { | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
} | |
RVOP( | |
vlseg8e8_v, | |
{ | |
init_vector_reg_zero(rv); | |
}, | |
GEN({/* no operation */})) |
Code Review Run #005f29
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
RVOP( | ||
vadc_vvm, | ||
{ | ||
for (int i = 0; i < 4; i++) { | ||
rv->V[rv_reg_zero][i] = 0; | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider refactoring the repeated code pattern that sets rv->V[rv_reg_zero][i] = 0
across multiple vector operations. This pattern appears in multiple RVOP definitions and could be extracted into a helper function to improve maintainability.
Code suggestion
Check the AI-generated fix before applying
RVOP( | |
vadc_vvm, | |
{ | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
}, | |
static inline void zero_vector_register(riscv_t *rv) { | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
} | |
RVOP( | |
vadc_vvm, | |
{ | |
zero_vector_register(rv); | |
}, |
Code Review Run #005f29
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
RVOP( | ||
vaaddu_vv, | ||
{ | ||
for (int i = 0; i < 4; i++) { | ||
rv->V[rv_reg_zero][i] = 0; | ||
} | ||
}, | ||
GEN({/* no operation */})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider refactoring the repeated code block that sets rv->V[rv_reg_zero][i] = 0
across multiple vector operations. This pattern appears in almost every vector operation implementation which could be consolidated into a helper function.
Code suggestion
Check the AI-generated fix before applying
RVOP( | |
vaaddu_vv, | |
{ | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
}, | |
GEN({/* no operation */})) | |
static inline void zero_vector_reg(riscv_t *rv) { | |
for (int i = 0; i < 4; i++) { | |
rv->V[rv_reg_zero][i] = 0; | |
} | |
} | |
RVOP( | |
vaaddu_vv, | |
{ | |
zero_vector_reg(rv); | |
}, | |
GEN({/* no operation */})) |
Code Review Run #005f29
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
uint8_t eew = decode_eew(insn); | ||
ir->eew = 8 << eew; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error handling for invalid eew
values. Currently, if decode_eew()
returns an invalid value, it could lead to undefined behavior when calculating ir->eew = 8 << eew
.
Code suggestion
Check the AI-generated fix before applying
uint8_t eew = decode_eew(insn); | |
ir->eew = 8 << eew; | |
uint8_t eew = decode_eew(insn); | |
if (eew > 3) { | |
return false; | |
} | |
ir->eew = 8 << eew; |
Code Review Run #005f29
Is this a valid issue, or was it incorrectly flagged by the Agent?
- it was incorrectly flagged
In |
@@ -306,6 +306,87 @@ static inline uint16_t c_decode_cbtype_imm(const uint16_t insn) | |||
} | |||
#endif /* RV32_HAS(EXT_C) */ | |||
|
|||
#if RV32_HAS(EXT_V) /* RV32_HAS(EXT_V) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace the comment /* RV32_HAS(EXT_V) */
with something like "Vector extension."
@@ -1971,67 +2384,2039 @@ static inline bool op_cfsw(rv_insn_t *ir, const uint32_t insn) | |||
#define op_cflwsp OP_UNIMP | |||
#endif /* RV32_HAS(EXT_C) && RV32_HAS(EXT_F) */ | |||
|
|||
/* handler for all unimplemented opcodes */ | |||
static inline bool op_unimp(rv_insn_t *ir UNUSED, uint32_t insn UNUSED) | |||
#if RV32_HAS(EXT_V) /* RV32_HAS(EXT_V) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. Refine the comment.
@@ -2988,3 +2988,5129 @@ RVOP( | |||
})) | |||
|
|||
#endif | |||
|
|||
#if RV32_HAS(EXT_V) | |||
#define LEN ((VLEN) >> (5)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Carefully define LEN
, which may lead to redefinitions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase the latest matser
branch, which resolves the recent CI failures.
Add support for the RISC-V "V" Vector Extension. This pull request implements decoding for 585 out of 616 version 1.0 spec vector instructions, with partial interpreter implementation.
The decoding method for vector instructions, including vector configuration and load/store instructions, follows the approach used in
rv32emu
. The newrvv_jumptable
is introduced to handle remaining arithmetic instructions.The interpreter implementation is tested using the riscv-vector-tests repository, with current limitations, as outlined in the repo. Included partial support for vector load/store instructions and single-width arithmetic instructions. The architecture now supports different settings for
sew
,lmul
, and vector masking.Vector instructions passing the tests include:
vle8.v
,vle16.v
,vle32.v
vse8.v
,vse16.v
,vse32.v
vadd.vv
,vadd.vx
,vadd.vi
vsub.vv
,vsub.vx
,vsub.vi
,vand.vv
,vand.vx
,vand.vi
vor.vv
,vor.vx
,vor.vi
vxor.vv
,vxor.vx
,vxor.vi
vsll.vv
,vsll.vx
,vsll.vi
vmul.vv
,vmul.vx
,vmul.vi
Close #504
Summary by Bito
Major implementation of RISC-V Vector Extension support, adding comprehensive instruction decoding for vector operations including load/store, arithmetic, and floating-point instructions. Introduces vector configuration settings, register handling, and constant optimization support. Implements 585 out of 616 version 1.0 spec vector instructions with support for various data widths (8-bit to 64-bit) and addressing modes.Unit tests added: False
Estimated effort to review (1-5, lower is better): 5