Re: [PATCH] fold-const, match.pd: Improve ptr_difference_const optimizations

Richard Biener <[email protected]> Wed, 5 Aug 2026 11:44:03 +0200 (CEST)
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
On Tue, 4 Aug 2026, Jakub Jelinek wrote:

> Hi!
> 
> 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).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

> 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?

Not sure, GENERIC vs. GIMPLE was compensated by match patterns here,
if you now no longer fold from GENERIC we might be missing some
patterns (but then I don't see how STRIP_NOPS helps on GIMPLE).

Richard.

> 2026-08-04  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.
> 
> --- gcc/fold-const.cc.jj	2026-07-26 15:37:03.625407289 +0200
> +++ gcc/fold-const.cc	2026-08-04 16:06:17.012862597 +0200
> @@ -16166,6 +16166,8 @@ split_address_to_core_and_offset (tree e
>    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)
> --- gcc/match.pd.jj	2026-08-04 10:27:31.000000000 +0200
> +++ gcc/match.pd	2026-08-04 18:14:02.108482282 +0200
> @@ -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)))
> + (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
> - (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)))
> -  (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)))))
> 
> 	Jakub
> 
> 

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