Hi Dylan,

> -----Original Message-----
> From: Dylan Rees <[email protected]>
> Sent: 10 August 2026 14:36
> To: [email protected]
> Cc: Dylan Rees <[email protected]>; [email protected];
> [email protected]; Tamar Christina <[email protected]>
> Subject: [PATCH 1/1] aarch64: Improve pfirst and brk* intrinsic folding
> 
> The fold method created for 'svbrk_unary_impl' to include some new
> folding cases and the expand method was amended for
> 'svpfirst_svpnext_impl'
> to optimise a specific case. Testcase expanded for 'brk*' folding and new
> testsuite added for 'pfirst' to verify behaviour.
> 
> gcc/ChangeLog:
> 
>       * config/aarch64/aarch64-sve-builtins-base.cc: fold method
>       created for 'svbrk_unary_impl'. Cases added for folding into
>       'ptrue' and 'pfalse' where appropriate and not folding where
>       unnecessary. Expand method of 'svpfirst_svpnext_impl' extended
>       to handle specific case where 'ptrue' should be emitted but in
>       a form where it can be recognised as a flag setting operation.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.target/aarch64/sve/pr121604_brk.c: Test extended.
>       * gcc.target/aarch64/sve/acle/general/pfirst_2.c: New test.
> ---
>  .../aarch64/aarch64-sve-builtins-base.cc      |  29 +++
>  .../aarch64/sve/acle/general/pfirst_2.c       |  67 +++++++
>  .../gcc.target/aarch64/sve/pr121604_brk.c     | 169 ++++++++++++++++--
>  3 files changed, 255 insertions(+), 10 deletions(-)
>  create mode 100644
> gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_2.c
> 
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> index 5d01d875a9d..b3dc6fbbdb3 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> @@ -346,6 +346,24 @@ class svbrk_unary_impl : public function_base
>  public:
>    constexpr svbrk_unary_impl (unspec unspec) : m_unspec (unspec) {}
> 
> +  gimple *
> +  fold (gimple_folder &f) const override
> +  {
> +    unsigned int arg_offset = f.pred == PRED_m ? 1 : 0;
> +    tree pg = gimple_call_arg (f.call, arg_offset);
> +    tree pn = gimple_call_arg (f.call, arg_offset + 1);

You can use 

tree pg = f.gp_value (f.call);

to simplify this as the function already knows where the gp is.

> +    if ((f.pred == PRED_z || f.pred == PRED_m)
> +     && is_ptrue (pg, f.type_suffix (0).element_bytes))
> +      {

And then pn can be extracted only where needed

tree pn = gimple_call_arg (f.call, f.gp_index + 1);

> +     if (is_ptrue (pn, f.type_suffix (0).element_bytes))
> +       return (m_unspec == UNSPEC_BRKA
> +         ? f.fold_to_vl_pred (1) : f.fold_to_pfalse ());

I think it's clearer written out. So

If (m_unspec == ..)
  return f.fold_to_..
return f.fold_to_

Patch is OK with those changes.

Thanks,
Tamar

> +     else if (is_pfalse (pn))
> +       return f.fold_to_ptrue ();
> +      }
> +    return nullptr;
> +  }
> +
>    rtx
>    expand (function_expander &e) const override
>    {
> @@ -2565,6 +2583,17 @@ public:
>    expand (function_expander &e) const override
>    {
>      machine_mode mode = e.vector_mode (0);
> +    if (m_unspec == UNSPEC_PFIRST
> +     && rtx_equal_p (e.args[0], CONSTM1_RTX (mode))
> +     && rtx_equal_p (e.args[1], CONST0_RTX (mode)))
> +      {
> +     rtx pattern = gen_int_mode (AARCH64_SV_VL1, SImode);
> +     rtvec vec = gen_rtvec (2, pattern, CONST0_RTX (mode));
> +     rtx ptrue = gen_rtx_CONST (VNx16BImode,
> +                                gen_rtx_UNSPEC (VNx16BImode, vec,
> +                                                UNSPEC_PTRUE));
> +     return force_reg (VNx16BImode, ptrue);
> +      }
>      e.add_ptrue_hint (0, mode);
>      return e.use_exact_insn (code_for_aarch64_sve (m_unspec, mode));
>    }
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_2.c
> b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_2.c
> new file mode 100644
> index 00000000000..3fba71c4cd0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_2.c
> @@ -0,0 +1,67 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +/* { dg-final { check-function-bodies "**" "" "" } } */
> +
> +#include <arm_sve.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +extern void foo (svbool_t);
> +extern void bar (svbool_t);
> +
> +/*
> +** test1:
> +**   b       bar
> +*/
> +__attribute__ ((noipa))
> +void test1 (svbool_t a)
> +{
> +    svbool_t res = svpfirst (svpfalse (), svpfalse ());
> +    if (svptest_any (res, a))
> +      foo (a);
> +    else
> +      bar (a);
> +}
> +
> +/*
> +** test2:
> +**   pfalse  p0\.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t test2 (svbool_t a)
> +{
> +    return svpfirst (svpfalse (), svpfalse ());
> +}
> +
> +/*
> +** test3:
> +**   ptrues  p3.b, vl1
> +**   ...
> +*/
> +__attribute__ ((noipa))
> +void test3 (svbool_t a)
> +{
> +    svbool_t res = svpfirst (svptrue_b8 (), svpfalse ());
> +    if (svptest_first (svptrue_b8 (), res))
> +      foo (a);
> +    else
> +      bar (a);
> +}
> +
> +/*
> +** test4:
> +**   ptrue   p0.b, vl1
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t test4 (svbool_t a)
> +{
> +return svpfirst (svptrue_b8 (), svpfalse ());
> +}
> +
> +#ifdef __cplusplus
> +}
> +#endif
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c
> b/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c
> index a474a20554d..ccb28d74833 100644
> --- a/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c
> @@ -5,21 +5,170 @@
>  #include <arm_sve.h>
> 
>  /*
> -** foo:
> -**   ptrue   p0\.b, all
> -**   brkb    p0\.b, p0/z, p0\.b
> +** f1m:
> +**   mov     p0.b, p1.b
>  **   ret
>  */
> -svbool_t foo () {
> -  return svbrkb_b_m (svpfalse (), svptrue_b8 (), svptrue_b8 ());
> +__attribute__ ((noipa))
> +svbool_t f1m (svbool_t a, svbool_t b)
> +{
> +    return svbrka_b_m (b, svpfalse_b(), a);
>  }
> 
>  /*
> -** bar:
> -**   ptrue   p0\.b, all
> -**   brka    p0\.b, p0/z, p0\.b
> +** f1z:
> +**   pfalse  p0.b
>  **   ret
>  */
> -svbool_t bar () {
> -  return svbrka_b_m (svpfalse (), svptrue_b8 (), svptrue_b8 ());
> +__attribute__ ((noipa))
> +svbool_t f1z (svbool_t a)
> +{
> +    return svbrka_b_z (svpfalse_b(), a);
>  }
> +
> +/*
> +** f2m:
> +**   ptrue   p3.b, all
> +**   brka    p1.b, p3/m, p0.b
> +**   mov     p0.b, p1.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t f2m (svbool_t a, svbool_t b)
> +{
> +    return svbrka_b_m (b, svptrue_b8(), a);
> +}
> +
> +/*
> +** f2z:
> +**   ptrue   p3.b, all
> +**   brka    p0.b, p3/z, p0.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t f2z (svbool_t a)
> +{
> +    return svbrka_b_z (svptrue_b8(), a);
> +}
> +
> +/*
> +** f3z:
> +**   ptrue   p0.b, vl1
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t f3z (svbool_t a)
> +{
> +    return svbrka_b_z (svptrue_b8(), svptrue_b8());
> +}
> +
> +/*
> +** f3m:
> +**   ptrue   p3.b, all
> +**   brka    p0.b, p3/m, p0.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t f3m (svbool_t a, svbool_t b)
> +{
> +    return svbrka_b_m (a, svptrue_b8(), a);
> +}
> +
> +/*
> +** f4m:
> +**   ptrue   p0.b, vl1
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t f4m (svbool_t a)
> +{
> +    return svbrka_b_m (a, svptrue_b8(), svptrue_b8 ());
> +}
> +
> +/*
> +** f4z:
> +**   ptrue   p0.b, all
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t f4z ()
> +{
> +    return svbrka_b_z (svptrue_b8(), svpfalse());
> +}
> +
> +/*
> +** g1z:
> +**   pfalse  p0.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t g1z (svbool_t a)
> +{
> +    return svbrkb_b_z (svpfalse_b(), a);
> +}
> +
> +/*
> +** g1m:
> +**   ptrue   p3.b, all
> +**   brkb    p0.b, p3/z, p0.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t g1m (svbool_t a)
> +{
> +    return svbrkb_b_m (svpfalse_b(), svptrue_b8(), a);
> +}
> +
> +/*
> +** g2z:
> +**   ptrue   p3.b, all
> +**   brkb    p0.b, p3/z, p0.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t g2z (svbool_t a)
> +{
> +    return svbrkb_b_z (svptrue_b8(), a);
> +}
> +
> +/*
> +** g2m:
> +**   ptrue   p0.b, all
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t g2m (svbool_t a)
> +{
> +    return svbrkb_b_m (a, svptrue_b8(), svpfalse ());
> +}
> +
> +/*
> +** g3m:
> +**   pfalse  p0.b
> +**   ret
> +*/
> +__attribute__ ((noipa))
> +svbool_t g3m (svbool_t a)
> +{
> +    return svbrkb_b_m (a, svptrue_b8(), svptrue_b8 ());
> +}
> +
> +int main ()
> +{
> +    svbool_t a = svptrue_pat_b16 (SV_VL4);
> +    svbool_t b = svptrue_pat_b16 (SV_VL5);
> +
> +    f1m (a, b);
> +    f1z (a);
> +    f2m (a, b);
> +    f2z (a);
> +    f3m (a, b);
> +    f3z (a);
> +    f4m (a);
> +    f4z ();
> +    g1z (a);
> +    g1m (a);
> +    g2z (a);
> +    g2m (a);
> +    g3m (a);
> +}
> \ No newline at end of file
> --
> 2.43.0

Reply via email to