[PATCH v2] tcg/risc-v: Fix clobbering of TCG_REG_TMP0 (t6) in vector code generation

zengzhijin@linux.spacemit.com posted 1 patch 1 month, 1 week ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/5D809A625CAA1DCC+20251229084747.1428-1-zengzhijin@linux.spacemit.com
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <Alistair.Francis@wdc.com>, Richard Henderson <richard.henderson@linaro.org>
tcg/riscv/tcg-target.c.inc | 10 +++++++---
tcg/riscv/tcg-target.h     |  1 +
2 files changed, 8 insertions(+), 3 deletions(-)
[PATCH v2] tcg/risc-v: Fix clobbering of TCG_REG_TMP0 (t6) in vector code generation
Posted by zengzhijin@linux.spacemit.com 1 month, 1 week ago
From: Zhijin Zeng <zengzhijin@linux.spacemit.com>

The RISC-V target currently uses register t6 as the destination for vsetvli and
vsetvl instructions to capture the resulting vector length (vl).

However, in the tcg_out_dupm_vec function, t6 is also used as a temporary
register. Since tcg_out_dup_vec may emit a vsetvli or vsetvl instruction
internally, the value previously written to t6 (e.g., by an earlier ld in
the same translation block) can be unintentionally overwritten.

This patch reserves the t3 register to be used as the destination for vsetvli
and vsetvl instructions.

Signed-off-by: Zhijin Zeng <zengzhijin@linux.spacemit.com>
---
 tcg/riscv/tcg-target.c.inc | 10 +++++++---
 tcg/riscv/tcg-target.h     |  1 +
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
index 31b9f7d87a..359021aa76 100644
--- a/tcg/riscv/tcg-target.c.inc
+++ b/tcg/riscv/tcg-target.c.inc
@@ -3022,10 +3022,12 @@ static void probe_frac_lmul_1(TCGType type, MemOp vsew)
         p->vset_insn = encode_vseti(OPC_VSETIVLI, TCG_REG_ZERO, avl, vtype);
     } else if (lmul_eq_avl) {
         /* rd != 0 and rs1 == 0 uses vlmax */
-        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_TMP0, TCG_REG_ZERO, vtype);
+        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_TMP3, TCG_REG_ZERO,
+                                   vtype);
     } else {
-        p->movi_insn = encode_i(OPC_ADDI, TCG_REG_TMP0, TCG_REG_ZERO, avl);
-        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_ZERO, TCG_REG_TMP0, vtype);
+        p->movi_insn = encode_i(OPC_ADDI, TCG_REG_TMP3, TCG_REG_ZERO, avl);
+        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_ZERO, TCG_REG_TMP3,
+                                   vtype);
     }
 }
 
@@ -3070,6 +3072,8 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP);
 
     if (cpuinfo & CPUINFO_ZVE64X) {
+        tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP3);
+
         switch (riscv_lg2_vlenb) {
         case TCG_TYPE_V64:
             tcg_target_available_regs[TCG_TYPE_V64] = ALL_VECTOR_REGS;
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
index 6dc77d944b..0f2dced8e2 100644
--- a/tcg/riscv/tcg-target.h
+++ b/tcg/riscv/tcg-target.h
@@ -55,6 +55,7 @@ typedef enum {
     TCG_REG_TMP0       = TCG_REG_T6,
     TCG_REG_TMP1       = TCG_REG_T5,
     TCG_REG_TMP2       = TCG_REG_T4,
+    TCG_REG_TMP3       = TCG_REG_T3,
 } TCGReg;
 
 #define TCG_REG_ZERO  TCG_REG_ZERO
-- 
2.43.0
Re: [PATCH v2] tcg/risc-v: Fix clobbering of TCG_REG_TMP0 (t6) in vector code generation
Posted by Richard Henderson 1 month ago
On 12/29/25 19:47, zengzhijin@linux.spacemit.com wrote:
> From: Zhijin Zeng <zengzhijin@linux.spacemit.com>
> 
> The RISC-V target currently uses register t6 as the destination for vsetvli and
> vsetvl instructions to capture the resulting vector length (vl).
> 
> However, in the tcg_out_dupm_vec function, t6 is also used as a temporary
> register. Since tcg_out_dup_vec may emit a vsetvli or vsetvl instruction
> internally, the value previously written to t6 (e.g., by an earlier ld in
> the same translation block) can be unintentionally overwritten.
> 
> This patch reserves the t3 register to be used as the destination for vsetvli
> and vsetvl instructions.
> 
> Signed-off-by: Zhijin Zeng <zengzhijin@linux.spacemit.com>

You don't need to reserve a new register.

There are only two places where a tmp register is live across set_vtype: dupm and dupi. 
Both of those places can be changed to use TCG_REG_TMP1 instead, with a comment.


r~
Re: [PATCH v2] tcg/risc-v: Fix clobbering of TCG_REG_TMP0 (t6) in vector code generation
Posted by Chao Liu 1 month, 1 week ago

On 12/29/2025 4:47 PM, zengzhijin@linux.spacemit.com wrote:
> From: Zhijin Zeng <zengzhijin@linux.spacemit.com>
> 
> The RISC-V target currently uses register t6 as the destination for vsetvli and
> vsetvl instructions to capture the resulting vector length (vl).
> 
> However, in the tcg_out_dupm_vec function, t6 is also used as a temporary
> register. Since tcg_out_dup_vec may emit a vsetvli or vsetvl instruction
> internally, the value previously written to t6 (e.g., by an earlier ld in
> the same translation block) can be unintentionally overwritten.
> 
> This patch reserves the t3 register to be used as the destination for vsetvli
> and vsetvl instructions.
> 
> Signed-off-by: Zhijin Zeng <zengzhijin@linux.spacemit.com>
> ---
>  tcg/riscv/tcg-target.c.inc | 10 +++++++---
>  tcg/riscv/tcg-target.h     |  1 +
>  2 files changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
> index 31b9f7d87a..359021aa76 100644
> --- a/tcg/riscv/tcg-target.c.inc
> +++ b/tcg/riscv/tcg-target.c.inc
> @@ -3022,10 +3022,12 @@ static void probe_frac_lmul_1(TCGType type, MemOp vsew)
>          p->vset_insn = encode_vseti(OPC_VSETIVLI, TCG_REG_ZERO, avl, vtype);
>      } else if (lmul_eq_avl) {
>          /* rd != 0 and rs1 == 0 uses vlmax */
> -        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_TMP0, TCG_REG_ZERO, vtype);
> +        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_TMP3, TCG_REG_ZERO,
> +                                   vtype);
>      } else {
> -        p->movi_insn = encode_i(OPC_ADDI, TCG_REG_TMP0, TCG_REG_ZERO, avl);
> -        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_ZERO, TCG_REG_TMP0, vtype);
> +        p->movi_insn = encode_i(OPC_ADDI, TCG_REG_TMP3, TCG_REG_ZERO, avl);
> +        p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_ZERO, TCG_REG_TMP3,
> +                                   vtype);
>      }
>  }
>  
> @@ -3070,6 +3072,8 @@ static void tcg_target_init(TCGContext *s)
>      tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP);
>  
>      if (cpuinfo & CPUINFO_ZVE64X) {
> +        tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP3);
> +
>          switch (riscv_lg2_vlenb) {
>          case TCG_TYPE_V64:
>              tcg_target_available_regs[TCG_TYPE_V64] = ALL_VECTOR_REGS;
> diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
> index 6dc77d944b..0f2dced8e2 100644
> --- a/tcg/riscv/tcg-target.h
> +++ b/tcg/riscv/tcg-target.h
> @@ -55,6 +55,7 @@ typedef enum {
>      TCG_REG_TMP0       = TCG_REG_T6,
>      TCG_REG_TMP1       = TCG_REG_T5,
>      TCG_REG_TMP2       = TCG_REG_T4,
> +    TCG_REG_TMP3       = TCG_REG_T3,
>  } TCGReg;
>  
>  #define TCG_REG_ZERO  TCG_REG_ZERO

LGTM. :)

Thanks,
Chao