RE: [PATCH 1/1] aarch64: Improve pfirst and brk* intrinsic folding

Tamar Christina <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <VI0PR08MB10392A05586602291F63B06C6FFA72@VI0PR08MB10392.eurprd08.prod.outlook.com>
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
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.