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)