Skip to content

Implement RVV floating-point scalar moves - #769

Open
alanhc wants to merge 1 commit into
sysprog21:masterfrom
alanhc:rvv-vfmv
Open

alanhc wants to merge 1 commit into
sysprog21:masterfrom
alanhc:rvv-vfmv

Conversation

@alanhc

@alanhc alanhc commented Sep 10, 2026

Copy link
Copy Markdown

Implements the floating-point scalar moves from #734.

Adds vfmv.f.s and vfmv.s.f (V 1.0 §16.3) at the VWFUNARY0 and VRFUNARY0
sites of funct6=0x10, both previously rejected with a FIXME so they would
not be misdecoded as vmv.x.s / vmv.s.x.

Both transfer element 0 between a vector register and an f register and
ignore LMUL. Two spec details are easy to miss:

  • vfmv.f.s performs its operation even when vstart >= vl or vl is 0;
  • vfmv.s.f writes nothing when vstart >= vl, which with vl == 0 covers
    every vstart.

The masked encodings of both are reserved, and the sub-opcode field must be
zero; the decode tests cover those rejections and confirm vmv.x.s still
decodes from the same funct6.

Smoke coverage includes the vl == 0 case, which a mutation that drops the
vstart < vl guard is caught by.

make check passes; the build was checked in the default, EXT_V,
JIT+EXT_V and EXT_V-without-EXT_F configurations. clang-format 20.1.7
clean.


Summary by cubic

Implements the RVV floating-point scalar moves vfmv.f.s and vfmv.s.f (V 1.0 §16.3). These transfer element 0 between a vector register and an f register, ignoring LMUL; previously their encodings were rejected to avoid misdecoding as vmv.x.s / vmv.s.x, and now they decode and execute.

Implementation notes

  • vfmv.f.s performs its operation even when vstart >= vl or vl == 0.
  • vfmv.s.f writes nothing when vstart >= vl, and with vl == 0 that covers every vstart.
  • Both instructions require SEW=32; masked encodings are reserved and rejected.
  • Added constopt entries and smoke tests covering the vl == 0 case.

Written for commit 8b0a2a7. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/decode_v.c">

<violation number="1" location="src/decode_v.c:882">
P2: In an RV32E+V build, valid upper floating-point registers are rejected for these new moves. The post-decode RV32E check treats `op_010000` operands as integer registers, even though these fields are floating-point registers; extend that check to recognize these vector FP moves.</violation>
</file>

<file name="src/rv32_v_template.c">

<violation number="1" location="src/rv32_v_template.c:6852">
P2: When `vta=1`, `vfmv.s.f` overwrites all tail elements with `0xffffffff`, although this scalar move must update only `vd[0]` and leave every other element unchanged regardless of `vta`. Remove the tail-fill block.</violation>
</file>

<file name="tests/rvv-smoke.S">

<violation number="1" location="tests/rvv-smoke.S:101">
P3: `vfmv_src` is an unused test fixture: the smoke test stages the same values directly into `vfmv_out` and never references this label. Remove the dead data or load the vector from it.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/decode_v.c
return false;
if (!decode_vm(insn) || decode_rs1(insn))
return false;
decode_mtype(ir, insn);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: In an RV32E+V build, valid upper floating-point registers are rejected for these new moves. The post-decode RV32E check treats op_010000 operands as integer registers, even though these fields are floating-point registers; extend that check to recognize these vector FP moves.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/decode_v.c, line 882:

<comment>In an RV32E+V build, valid upper floating-point registers are rejected for these new moves. The post-decode RV32E check treats `op_010000` operands as integer registers, even though these fields are floating-point registers; extend that check to recognize these vector FP moves.</comment>

<file context>
@@ -873,12 +873,15 @@ static inline bool op_010000(rv_insn_t *ir, const uint32_t insn)
-        return false;
+        if (!decode_vm(insn) || decode_rs1(insn))
+            return false;
+        decode_mtype(ir, insn);
+        ir->opcode = rv_insn_vfmv_f_s;
+        break;
</file context>

Comment thread src/rv32_v_template.c
uint8_t vta = (rv->csr_vtype >> 6) & 0x1;

rvv_set_elem(rv, ir->vd, 0, 32, rv->F[ir->rs1].v);
if (vta) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When vta=1, vfmv.s.f overwrites all tail elements with 0xffffffff, although this scalar move must update only vd[0] and leave every other element unchanged regardless of vta. Remove the tail-fill block.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/rv32_v_template.c, line 6852:

<comment>When `vta=1`, `vfmv.s.f` overwrites all tail elements with `0xffffffff`, although this scalar move must update only `vd[0]` and leave every other element unchanged regardless of `vta`. Remove the tail-fill block.</comment>

<file context>
@@ -6828,6 +6828,35 @@ static inline void rvv_exec_fp32_vf(riscv_t *rv,
+        uint8_t vta = (rv->csr_vtype >> 6) & 0x1;
+
+        rvv_set_elem(rv, ir->vd, 0, 32, rv->F[ir->rs1].v);
+        if (vta) {
+            for (uint32_t elem = rv->csr_vl; elem < vlmax; elem++)
+                rvv_set_elem(rv, ir->vd, elem, 32, 0xFFFFFFFFU);
</file context>

Comment thread tests/rvv-smoke.S
mulfix_rhs:
.byte 0x40, 0x80, 0x40, 0x20

vfmv_src:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: vfmv_src is an unused test fixture: the smoke test stages the same values directly into vfmv_out and never references this label. Remove the dead data or load the vector from it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/rvv-smoke.S, line 101:

<comment>`vfmv_src` is an unused test fixture: the smoke test stages the same values directly into `vfmv_out` and never references this label. Remove the dead data or load the vector from it.</comment>

<file context>
@@ -98,6 +98,9 @@ mulfix_lhs:
 mulfix_rhs:
     .byte 0x40, 0x80, 0x40, 0x20
 
+vfmv_src:
+    .word 0x40490fdb, 0x3f800000, 0xc0000000, 0x00000000
+
</file context>

Add vfmv.f.s and vfmv.s.f (V 1.0 section 16.3), which transfer element 0
between a vector register and an f register, ignoring LMUL.

Two details from the specification are easy to miss: vfmv.f.s performs its
operation even when vl is 0, while vfmv.s.f writes nothing when
vstart >= vl. The masked encodings of both are reserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant