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