[gcc r17-2979] fold-const, match.pd: Improve ptr_difference_const optimizations

Jakub Jelinek via Gcc-cvs <[email protected]> Wed, 5 Aug 2026 10:16:39 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:141edd02af705696f89ff9a804879dc51834898d

commit r17-2979-g141edd02af705696f89ff9a804879dc51834898d
Author: Jakub Jelinek <[email protected]>
Date:   Wed Aug 5 12:15:24 2026 +0200

    fold-const, match.pd: Improve ptr_difference_const optimizations
    
    As mentioned in https://gcc.gnu.org/pipermail/gcc-patches/2026-July/725438.html
    at least the
          /* Convert (T1)(X p+ Y) into ((T1)X p+ Y), for pointer type, when the new
             cast (T1)X will fold away.  We assume that this happens when X itself
             is a cast.  */
    fold-const.cc (fold_unary) optimization is highly undesirable in the C++ FE
    (at least before the cp_fold_function/gimplification).  In the above patch
    I've tried to disable some optimizations (and Jason suggested to disable
    them even slightly less), but still that can at least in theory (but with
    the above patch in practice too) result in regressions, in particular in
    POINTER_DIFF_EXPR constant evaluation.
    In that testcase, we end up with
    (((((int*)(& x)) + 12) - (((int*)(& x)) + 4)) / 4)
    and the current ptr_difference_const match.pd optimizations aren't
    prepared to handle that.
    
    The following patch fixes that by adding STRIP_NOPS (exp); to
    split_address_to_core_and_offset which ptr_difference_const uses
    and then just throwing some ADDR_EXPR requirements in the simplification
    patterns - ptr_difference_const will return true if it is something it can
    handle, and it doesn't have to be just ADDR_EXPR, it can be also
    POINTER_PLUS_EXPR with constant offset, or nop conversions around either of those
    or nop conversions around first POINTER_PLUS_EXPR operand.
    
    In some cases after dropping the ADDR_EXPR parts I could throw away one
    pattern because two adjusted patterns were identical, in one case (minus
    with casts meant for subtraction of pointers cast to intptr_t/uintptr_t)
    I had to add another tree_nop_conversion_p check, so that e.g. floating
    point difference x - x which can't be folded away because it could trap
    isn't attempted to be folded (as build_int_cst for floating point would
    ICE).
    
    And/or should I try even harder, handle not just SSA_NAME with ADDR_EXPR
    as def_stmt, but also with nop conversions or POINTER_PLUS, and in case
    of pointer plus perhaps even recurse and add the two bitpos/offsets
    together?
    
    2026-08-05  Jakub Jelinek  <[email protected]>
    
            * fold-const.cc (split_address_to_core_and_offset): Use STRIP_NOPS.
            * match.pd ((&a + b) !=/== (&a[1] + c) -> (&a[0] - &a[1]) + b !=/== c):
            Don't require captures to be ADDR_EXPR.
            ((&a+b) - (&a[1] + c) -> sizeof(a[0]) + (b - c)): Likewise.
            ((p + b) - &p->d -> offsetof (*p, d) + b): Likewise.
            (Try folding difference of addresses): Likewise.  Remove
            redundant simplifications because of that.
    
    Reviewed-by: Richard Biener <[email protected]>

Diff:
---
 gcc/fold-const.cc |  2 ++
 gcc/match.pd      | 41 ++++++++++++++++-------------------------
 2 files changed, 18 insertions(+), 25 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index e1793ac89f25..64d0e7208ce8 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -16166,6 +16166,8 @@ split_address_to_core_and_offset (tree exp,
   poly_int64 bitsize;
   location_t loc = EXPR_LOCATION (exp);
 
+  STRIP_NOPS (exp);
+
   if (TREE_CODE (exp) == SSA_NAME)
     if (gassign *def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (exp)))
       if (gimple_assign_rhs_code (def) == ADDR_EXPR)
diff --git a/gcc/match.pd b/gcc/match.pd
index 2545d62b4ab4..9bd6d2f7e077 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3089,12 +3089,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* (&a + b) !=/== (&a[1] + c) -> (&a[0] - &a[1]) + b !=/== c */
 (for neeq (ne eq)
  (simplify
-  (neeq:c (pointer_plus @2 @3) ADDR_EXPR@0)
+  (neeq:c (pointer_plus @2 @3) @0)
    (with { poly_int64 diff; tree inner_type = TREE_TYPE (@3);}
     (if (ptr_difference_const (@0, @2, &diff))
      (neeq { build_int_cst_type (inner_type, diff); } @3))))
  (simplify
-  (neeq (pointer_plus ADDR_EXPR@0 @1) (pointer_plus ADDR_EXPR@2 @3))
+  (neeq (pointer_plus @0 @1) (pointer_plus @2 @3))
    (with { poly_int64 diff; tree inner_type = TREE_TYPE (@1);}
     (if (ptr_difference_const (@0, @2, &diff))
      (neeq (plus { build_int_cst_type (inner_type, diff); } @1) @3)))))
@@ -3310,38 +3310,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Try folding difference of addresses.  */
 (simplify
- (minus (convert ADDR_EXPR@0) (convert (pointer_plus @1 @2)))
- (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
+ (minus (convert @0) (convert (pointer_plus @1 @2)))
+ (if (tree_nop_conversion_p (type, TREE_TYPE (@0))
+      && tree_nop_conversion_p (type, TREE_TYPE (@1)))
   (with { poly_int64 diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     (minus { build_int_cst_type (type, diff); } (convert @2))))))
 (simplify
- (minus (convert (pointer_plus @0 @2)) (convert ADDR_EXPR@1))
- (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
+ (minus (convert (pointer_plus @0 @2)) (convert @1))
+ (if (tree_nop_conversion_p (type, TREE_TYPE (@0))
+      && tree_nop_conversion_p (type, TREE_TYPE (@1)))
   (with { poly_int64 diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     (plus (convert @2) { build_int_cst_type (type, diff); })))))
 (simplify
- (minus (convert ADDR_EXPR@0) (convert @1))
- (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
-  (with { poly_int64 diff; }
-   (if (ptr_difference_const (@0, @1, &diff))
-    { build_int_cst_type (type, diff); }))))
-(simplify
- (minus (convert @0) (convert ADDR_EXPR@1))
- (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
-  (with { poly_int64 diff; }
-   (if (ptr_difference_const (@0, @1, &diff))
-    { build_int_cst_type (type, diff); }))))
-(simplify
- (pointer_diff (convert?@2 ADDR_EXPR@0) (convert1?@3 @1))
- (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
-      && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+ (minus (convert @0) (convert @1))
+ (if (tree_nop_conversion_p (type, TREE_TYPE (@0))
+      && tree_nop_conversion_p (type, TREE_TYPE (@1))
+      && tree_nop_conversion_p (type, ptr_type_node))
   (with { poly_int64 diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     { build_int_cst_type (type, diff); }))))
 (simplify
- (pointer_diff (convert?@2 @0) (convert1?@3 ADDR_EXPR@1))
+ (pointer_diff (convert?@2 @0) (convert1?@3 @1))
  (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
       && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
   (with { poly_int64 diff; }
@@ -3350,18 +3341,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* (&a+b) - (&a[1] + c) -> sizeof(a[0]) + (b - c) */
 (simplify
- (pointer_diff (pointer_plus ADDR_EXPR@0 @1) (pointer_plus ADDR_EXPR@2 @3))
+ (pointer_diff (pointer_plus @0 @1) (pointer_plus @2 @3))
  (with { poly_int64 diff; }
    (if (ptr_difference_const (@0, @2, &diff))
     (plus { build_int_cst_type (type, diff); } (convert (minus @1 @3))))))
 /* (p + b) - &p->d -> offsetof (*p, d) + b */
 (simplify
- (pointer_diff (pointer_plus @0 @1) ADDR_EXPR@2)
+ (pointer_diff (pointer_plus @0 @1) @2)
  (with { poly_int64 diff; }
    (if (ptr_difference_const (@0, @2, &diff))
     (plus { build_int_cst_type (type, diff); } (convert @1)))))
 (simplify
- (pointer_diff ADDR_EXPR@0 (pointer_plus @1 @2))
+ (pointer_diff @0 (pointer_plus @1 @2))
  (with { poly_int64 diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     (minus { build_int_cst_type (type, diff); } (convert @2)))))