On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
> The .vi emitters for add, reverse sub and saturating ops pass the
> whole replicated constant (e.g. 0x0505050505050505) to encode_vi()
> instead of a single element. This aborts debug builds on common
> vectorized guest code and is undefined behaviour in release builds.
> 
> Add vec_imm() to extract the VECE element, and use it.
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
> ---
>  tcg/riscv64/tcg-target.c.inc | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index 0e749ae296b8..a3d995e290b7 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -735,6 +735,12 @@ static void tcg_out_opc_vi_u(TCGContext *s, RISCVInsn 
> opc,
>      tcg_out32(s, encode_vi_u(opc, vd, imm, vs2, true));
>  }
>  
> +/* Constants are replicated by VECE; extract one element for .vi forms. */
> +static int64_t vec_imm(TCGArg arg, unsigned vece)
> +{
> +    return sextract64(arg, 0, 8 << vece);
> +}
> +
>  static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
>                                TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
>  {
> @@ -2788,12 +2794,13 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode 
> opc,
>          break;
>      case INDEX_op_add_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_sub_vec:
>          set_vtype_len_sew(s, type, vece);
>          if (const_args[1]) {
> -            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, a1);
> +            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, vec_imm(a1, vece));
>          } else {
>              tcg_out_opc_vv(s, OPC_VSUB_VV, a0, a1, a2);
>          }
> @@ -2824,19 +2831,23 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode 
> opc,
>          break;
>      case INDEX_op_ssadd_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_sssub_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_usadd_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_ussub_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_smax_vec:
>          set_vtype_len_sew(s, type, vece);

This is technically correct. That said, the goal of all this extra code 
is to satisfy the assert added in commit 006352d69f14 ("tcg/riscv64: 
Assert immediate in range for {i,s,u,vi}-type insns") not to fix the 
code generation which is correct as it only keeps the lower 5 bits of 
the immediate.

At this stage we already know that the immediate can be represented as a 
duplicated simm5 constant, so just dropping the assert could be a 
simpler way to fix the issue.

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
[email protected]                     http://aurel32.net

Reply via email to