On Wed, 13 May 2026, Raphael Moreira Zinsly wrote:

> This is a follow up of
> https://gcc.gnu.org/pipermail/gcc-patches/2025-June/687919.html
> I had it in my queue but due to other priorities it got postponed
> 
> -- >8 --
> 
> This patch allows us to use the "splat the sign bit" idiom to
> efficiently select between 0 and 2^n-1.
> With that we can avoid branches and we got a shorter sequence than
> using conditional-zero instructions.
> 
> The PLUS 2^n-1 sequence appears particularly for signed division
> by a power of two.
> 
> gcc/ChangeLog:
>       * match.pd
>       (A < 0 ? ARG1 OP 2^n-1 : ARG1): New pattern.
>       (A < 0 ? ARG0 : ARG0 OP 2^n-1): New pattern.
> 
> gcc/testsuite/ChangeLog:
>       * gcc.dg/tree-ssa/phi-opt-49.c: New test.
>       * gcc.target/sh/pr59533-1.c: Fix expected output.
> ---
>  gcc/match.pd                               | 15 +++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/phi-opt-49.c | 36 ++++++++++++++++++++++
>  gcc/testsuite/gcc.target/sh/pr59533-1.c    | 12 ++++----
>  3 files changed, 57 insertions(+), 6 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-49.c
> 
> diff --git a/gcc/match.pd b/gcc/match.pd
> index b037b1a2876..f32f53d910e 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -12099,3 +12099,18 @@ and,
>   (if (INTEGRAL_TYPE_P (type))
>     (with { tree itype = TREE_TYPE (@2); }
>      (convert (minus @2 (convert:itype @1))))))
> +
> +/* Simplify (a < 0) ? ARG1 OP CONST : ARG1 to ((a < 0) ? 0 : CONST) OP ARG1
> +   when CONST is a 2^n-1 constant.  */
> +(for op (plus bit_ior bit_xor)
> + (simplify
> +  (cond (lt @0 integer_zerop@1) (op:c @2 INTEGER_CST@3) @2)

No :c necessary on 'op'

> +   (if (wi::exact_log2 (wi::to_wide (@3) + 1) != -1)

Why is it cheap to splat the sign bit?  If it's cheap to splat
the sign bit it's cheap to select between zero and a constant:
<splat-sign-bit-to-full-width> & COSTANT.

That you leave in the (cond ...) hints strongly in that it's
an oddly special "canonicalization" and that it is really
a target dependent RTL thing?

> +    (op:c (cond (lt @0 @1) @3 { build_zero_cst (type); }) @2))))

:c doesn't do anything in the result (I wonder why we don't diagnose it 
...)  Please re-use a captured (lt @0 @1).

Similar below.

> +
> +/* Same for (a < 0) ? ARG0 : ARG0 OP CONST.  */
> +(for op (plus bit_ior bit_xor)
> + (simplify
> +  (cond (lt @0 integer_zerop@1) @2 (op:c @2 INTEGER_CST@3))
> +   (if (wi::exact_log2 (wi::to_wide (@3) + 1) != -1)
> +    (op:c (cond (lt @0 @1) { build_zero_cst (type); }  @3) @2))))
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-49.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-49.c
> new file mode 100644
> index 00000000000..61d2c8ca615
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-49.c
> @@ -0,0 +1,36 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-phiopt4" } */
> +
> +long f1(long c, long a)
> +{
> +  return c < 0 ? a : a + 7;
> +}
> +
> +long f2(long c, long a)
> +{
> +  return c < 0 ? a + 7 : a;
> +}
> +
> +long f3(long c, long a)
> +{
> +  return c < 0 ? a : a | 15;
> +}
> +
> +long f4(long c, long a)
> +{
> +  return c < 0 ? a | 15 : a;
> +}
> +
> +long f5(long c, long a)
> +{
> +  return c < 0 ? a : a ^ 31;
> +}
> +
> +long f6(long c, long a)
> +{
> +  return c < 0 ? a ^ 31 : a;
> +}
> +
> +/* { dg-final { scan-tree-dump-not "if" "phiopt4" } } */
> +/* { dg-final { scan-assembler-not "blt" } } */
> +/* { dg-final { scan-assembler-not "bge" } } */
> diff --git a/gcc/testsuite/gcc.target/sh/pr59533-1.c 
> b/gcc/testsuite/gcc.target/sh/pr59533-1.c
> index b0469859df5..660cf1024c6 100644
> --- a/gcc/testsuite/gcc.target/sh/pr59533-1.c
> +++ b/gcc/testsuite/gcc.target/sh/pr59533-1.c
> @@ -2,19 +2,19 @@
>  /* { dg-do compile }  */
>  /* { dg-options "-O1" } */
>  
> -/* { dg-final { scan-assembler-times "shll" 1 } }  */
> -/* { dg-final { scan-assembler-times "movt" 5 } }  */
> +/* { dg-final { scan-assembler-times "shll" 5 } }  */
> +/* { dg-final { scan-assembler-times "movt" 9 } }  */
>  /* { dg-final { scan-assembler-times "rotcl" 1 } }  */
>  /* { dg-final { scan-assembler-times "and" 3 } }  */
>  /* { dg-final { scan-assembler-times "extu.b" 5 } }  */
>  
> -/* { dg-final { scan-assembler-times "cmp/pz" 27 { target { ! sh2a } } } }  
> */
> +/* { dg-final { scan-assembler-times "cmp/pz" 23 { target { ! sh2a } } } }  
> */
>  /* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } }  */
> -/* { dg-final { scan-assembler-times "subc" 16 { target { ! sh2a } } } }  */
> +/* { dg-final { scan-assembler-times "subc" 12 { target { ! sh2a } } } }  */
>  
> -/* { dg-final { scan-assembler-times "cmp/pz" 25 { target { sh2a } } } }  */
> +/* { dg-final { scan-assembler-times "cmp/pz" 21 { target { sh2a } } } }  */
>  /* { dg-final { scan-assembler-times "addc" 6 { target { sh2a } } } }  */
> -/* { dg-final { scan-assembler-times "subc" 14 { target { sh2a } } } }  */
> +/* { dg-final { scan-assembler-times "subc" 10 { target { sh2a } } } }  */
>  /* { dg-final { scan-assembler-times "bld" 2 { target { sh2a } } } }  */
>  
>  int
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to