[PATCH 02/11] target/arm: Implement MIN/MAX (immediate)

Richard Henderson posted 11 patches 3 months, 2 weeks ago
Maintainers: Laurent Vivier <laurent@vivier.eu>, Peter Maydell <peter.maydell@linaro.org>
[PATCH 02/11] target/arm: Implement MIN/MAX (immediate)
Posted by Richard Henderson 3 months, 2 weeks ago
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/translate-a64.c | 44 ++++++++++++++++++++++++++++++++++
 target/arm/tcg/a64.decode      | 10 ++++++++
 2 files changed, 54 insertions(+)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index dbf47595db..b70ae5befd 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -4552,6 +4552,50 @@ TRANS(SUB_i, gen_rri, a, 1, 1, tcg_gen_sub_i64)
 TRANS(ADDS_i, gen_rri, a, 0, 1, a->sf ? gen_add64_CC : gen_add32_CC)
 TRANS(SUBS_i, gen_rri, a, 0, 1, a->sf ? gen_sub64_CC : gen_sub32_CC)
 
+/*
+ * Min/Max (immediate)
+ */
+
+static void gen_wrap3_i32(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, NeonGenTwoOpFn fn)
+{
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    TCGv_i32 t2 = tcg_temp_new_i32();
+
+    tcg_gen_extrl_i64_i32(t1, n);
+    tcg_gen_extrl_i64_i32(t2, m);
+    fn(t1, t1, t2);
+    tcg_gen_extu_i32_i64(d, t1);
+}
+
+static void gen_smax32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+    gen_wrap3_i32(d, n, m, tcg_gen_smax_i32);
+}
+
+static void gen_smin32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+    gen_wrap3_i32(d, n, m, tcg_gen_smin_i32);
+}
+
+static void gen_umax32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+    gen_wrap3_i32(d, n, m, tcg_gen_umax_i32);
+}
+
+static void gen_umin32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+    gen_wrap3_i32(d, n, m, tcg_gen_umin_i32);
+}
+
+TRANS_FEAT(SMAX_i, aa64_cssc, gen_rri, a, 0, 0,
+           a->sf ? tcg_gen_smax_i64 : gen_smax32_i64)
+TRANS_FEAT(SMIN_i, aa64_cssc, gen_rri, a, 0, 0,
+           a->sf ? tcg_gen_smin_i64 : gen_smin32_i64)
+TRANS_FEAT(UMAX_i, aa64_cssc, gen_rri, a, 0, 0,
+           a->sf ? tcg_gen_umax_i64 : gen_umax32_i64)
+TRANS_FEAT(UMIN_i, aa64_cssc, gen_rri, a, 0, 0,
+           a->sf ? tcg_gen_umin_i64 : gen_umin32_i64)
+
 /*
  * Add/subtract (immediate, with tags)
  */
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 8c798cde2b..c1811b0274 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -156,6 +156,16 @@ MOVZ            . 10 100101 .. ................ .....   @movw_32
 MOVK            . 11 100101 .. ................ .....   @movw_64
 MOVK            . 11 100101 .. ................ .....   @movw_32
 
+# Min/Max (immediate)
+
+@minmaxi_s      sf:1 .. ........... imm:s8 rn:5 rd:5    &rri_sf
+@minmaxi_u      sf:1 .. ........... imm:8  rn:5 rd:5    &rri_sf
+
+SMAX_i          . 00 1000111 0000 ........ ..... .....  @minmaxi_s
+SMIN_i          . 00 1000111 0010 ........ ..... .....  @minmaxi_s
+UMAX_i          . 00 1000111 0001 ........ ..... .....  @minmaxi_u
+UMIN_i          . 00 1000111 0011 ........ ..... .....  @minmaxi_u
+
 # Bitfield
 
 &bitfield       rd rn sf immr imms
-- 
2.43.0
Re: [PATCH 02/11] target/arm: Implement MIN/MAX (immediate)
Posted by Peter Maydell 3 months ago
On Sun, 3 Aug 2025 at 02:41, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/tcg/translate-a64.c | 44 ++++++++++++++++++++++++++++++++++
>  target/arm/tcg/a64.decode      | 10 ++++++++
>  2 files changed, 54 insertions(+)
>
> diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
> index dbf47595db..b70ae5befd 100644
> --- a/target/arm/tcg/translate-a64.c
> +++ b/target/arm/tcg/translate-a64.c
> @@ -4552,6 +4552,50 @@ TRANS(SUB_i, gen_rri, a, 1, 1, tcg_gen_sub_i64)
>  TRANS(ADDS_i, gen_rri, a, 0, 1, a->sf ? gen_add64_CC : gen_add32_CC)
>  TRANS(SUBS_i, gen_rri, a, 0, 1, a->sf ? gen_sub64_CC : gen_sub32_CC)
>
> +/*
> + * Min/Max (immediate)
> + */
> +
> +static void gen_wrap3_i32(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, NeonGenTwoOpFn fn)
> +{
> +    TCGv_i32 t1 = tcg_temp_new_i32();
> +    TCGv_i32 t2 = tcg_temp_new_i32();
> +
> +    tcg_gen_extrl_i64_i32(t1, n);
> +    tcg_gen_extrl_i64_i32(t2, m);
> +    fn(t1, t1, t2);
> +    tcg_gen_extu_i32_i64(d, t1);
> +}
> +
> +static void gen_smax32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
> +{
> +    gen_wrap3_i32(d, n, m, tcg_gen_smax_i32);
> +}
> +
> +static void gen_smin32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
> +{
> +    gen_wrap3_i32(d, n, m, tcg_gen_smin_i32);
> +}
> +
> +static void gen_umax32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
> +{
> +    gen_wrap3_i32(d, n, m, tcg_gen_umax_i32);
> +}
> +
> +static void gen_umin32_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
> +{
> +    gen_wrap3_i32(d, n, m, tcg_gen_umin_i32);
> +}
> +
> +TRANS_FEAT(SMAX_i, aa64_cssc, gen_rri, a, 0, 0,
> +           a->sf ? tcg_gen_smax_i64 : gen_smax32_i64)
> +TRANS_FEAT(SMIN_i, aa64_cssc, gen_rri, a, 0, 0,
> +           a->sf ? tcg_gen_smin_i64 : gen_smin32_i64)
> +TRANS_FEAT(UMAX_i, aa64_cssc, gen_rri, a, 0, 0,
> +           a->sf ? tcg_gen_umax_i64 : gen_umax32_i64)
> +TRANS_FEAT(UMIN_i, aa64_cssc, gen_rri, a, 0, 0,
> +           a->sf ? tcg_gen_umin_i64 : gen_umin32_i64)

We end up doing the zero-extension twice for the 32-bit case,
once in gen_wrap3_i32(), and once in gen_rri().  Does the
extra one get optimized away ?

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Re: [PATCH 02/11] target/arm: Implement MIN/MAX (immediate)
Posted by Richard Henderson 3 months ago
On 8/15/25 23:18, Peter Maydell wrote:
> We end up doing the zero-extension twice for the 32-bit case,
> once in gen_wrap3_i32(), and once in gen_rri().  Does the
> extra one get optimized away ?

Yes.  That's what the z_mask stuff in tcg/optimize.c is for.


r~