[gcc r17-3225] match.pd: fold a round up spelled with inclusive or

Kyrylo Tkachov via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:75f572322c011229794476502f52a9ae530107f8

commit r17-3225-g75f572322c011229794476502f52a9ae530107f8
Author: Kyrylo Tkachov <[email protected]>
Date:   Mon Aug 10 20:39:14 2026 +0200

    match.pd: fold a round up spelled with inclusive or
    
    Linux spells a power-of-two round up as:
    
      ((x - 1) | (2^k - 1)) + 1
    
    For wrapping arithmetic, this is:
    
      (x + (2^k - 1)) & -(2^k)
    
    The latter form needs one fewer operation and exposes the zero low bits.
    Apply the identity to scalar and vector integral types.  Use :s on the
    inclusive-or expression so the fold does not add work when that value
    remains live.
    
      unsigned long round_up (unsigned long x)
      {
        return ((x - 1) | 4095) + 1;
      }
    
    aarch64 -O2:
    
    before:
    
            round_up:
                    sub     x0, x0, #1
                    orr     x0, x0, 4095
                    add     x0, x0, 1
                    ret
    
    after:
    
            round_up:
                    add     x0, x0, 4095
                    and     x0, x0, -4096
                    ret
    
    Bootstrapped and tested on aarch64-none-linux-gnu.
    
    gcc/ChangeLog:
    
            * match.pd (((X - 1) | C) + 1): New simplification.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/round-up-ior-1.c: New test.
            * gcc.dg/tree-ssa/round-up-ior-2.c: Likewise.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/match.pd                                   | 17 +++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-1.c | 34 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-2.c | 10 ++++++++
 3 files changed, 61 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index beea45357e22..eee44365ea37 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2072,6 +2072,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (bit_and (plus @0 @1)
 	    { build_uniform_cst
 		(type, wide_int_to_tree (etype, wi::bit_not (c))); }))))
+
+/* ((X - 1) | C) + 1 -> (X + C) & ~C, for C a low mask 2^k - 1.
+   Both forms round X up to a multiple of 2^k.  */
+(simplify
+ (plus (bit_ior:s (plus @0 integer_minus_onep)
+		   uniform_integer_cst_p@1)
+	integer_onep)
+ (with { tree cst = uniform_integer_cst_p (@1);
+	 tree etype = TREE_TYPE (cst);
+	 wide_int c = wi::to_wide (cst); }
+  (if (TYPE_OVERFLOW_WRAPS (type)
+	&& c != 0
+	&& wi::popcount (c + 1) == 1)
+   (bit_and (plus @0 @1)
+	    { build_uniform_cst
+		(type, wide_int_to_tree (etype, wi::bit_not (c))); }))))
+
 /* (x + y) - min (x, y) -> max (x, y)
    (x + y) - max (x, y) -> min (x, y)
    The sum of the minimum and the maximum is the sum of the operands.  */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-1.c b/gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-1.c
new file mode 100644
index 000000000000..991a429742c4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-1.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+typedef unsigned int v4ui __attribute__ ((vector_size (16)));
+
+unsigned long
+round_up (unsigned long x)
+{
+  return ((x - 1) | 4095) + 1;
+}
+
+unsigned long
+round_up_pages (unsigned long x)
+{
+  return (((x - 1) | 4095) + 1) >> 12;
+}
+
+v4ui
+round_up_vec (v4ui x)
+{
+  v4ui one = { 1, 1, 1, 1 };
+  v4ui mask = { 15, 15, 15, 15 };
+  return ((x - one) | mask) + one;
+}
+
+unsigned long
+keep (unsigned long x)
+{
+  return ((x - 1) | 4096) + 1;
+}
+
+/* { dg-final { scan-tree-dump-not "\\| 4095" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "\\|.*15" "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\\| 4096" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-2.c b/gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-2.c
new file mode 100644
index 000000000000..014aeed4c613
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/round-up-ior-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fwrapv -fdump-tree-optimized" } */
+
+int
+round_up (int x)
+{
+  return ((x - 1) | 15) + 1;
+}
+
+/* { dg-final { scan-tree-dump-not " \\| " "optimized" } } */
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.