Re: [PATCH] target/arm: Fix SVE2 WHILEWR/WHILERW zero diff boundary case

Richard Henderson <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
On 8/6/26 00:47, [email protected] wrote:
> From: YanjunYang <[email protected]>
> 
> The trans_WHILE_ptr function incorrectly handles the case where the
> address difference divided by ESIZE results in zero. This happens when
> the address difference is less than ESIZE but greater than zero.
> 
> In this boundary case, the address difference is less than ESIZE, which
> means all elements are safe from conflicts. The previous code would set
> the predicate to all zeros, but the correct behavior is to set all
> elements to one.
> 
> Fix by checking if diff == 0 after the shift and setting diff to tmax
> (all elements true) in this case.
> 
> Fixes the following test cases:
>    whilewr p0.s, x9, x10  ; x9=8, x10=11 => p0=0xffffffff (all ones)
>    whilerw p0.s, x9, x10  ; x9=8, x10=11 => p0=0xffffffff (all ones)
> 
> Signed-off-by: YanjunYang <[email protected]>
> ---
>   target/arm/tcg/translate-sve.c | 4 ++++
>   1 file changed, 4 insertions(+)
> 
> diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
> index fc4cc8c479..33613ebf58 100644
> --- a/target/arm/tcg/translate-sve.c
> +++ b/target/arm/tcg/translate-sve.c
> @@ -3736,6 +3736,10 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a)
>           tcg_gen_movcond_i64(TCG_COND_GEU, diff, op0, op1, tmax, diff);
>       }
> 
> +    /* If diff == 0, the address difference is less than ESIZE,
> +       so all elements are safe from conflicts. */
> +    tcg_gen_movcond_i64(TCG_COND_EQ, diff, diff, tcg_constant_i64(0), tmax, diff);
> +
>       /* Bound to the maximum.  */
>       tcg_gen_umin_i64(diff, diff, tmax);
> 

For whilerw, we should replace the preceding test, which for some reason compares op0 == 
op1 directly instead of diff == 0 after the division.

For whilewr, we need 65-bit arithmetic for the straightforward solution, which I think 
means we need two comparisons, including this one.  Possibly clearer as

     diff = unsigned_saturating_sub(op1, op0)
     diff = diff >> esz
     diff = diff ? diff : max
     diff = umin(diff, max)

where unsigned_saturating_sub(x, y) -> umax(x, y) - y

Less clear, but possibly more efficient,

     diff = umin(diff - 1, max - 1) + 1;

instead of the direct comparison against 0.

I'll prepare a patch.  Thanks for the report.


r~
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.