Re: [PATCH v2] gimple-fold: fix follow_outer_ssa_edges for undefined overflow cases [PR126313]

Richard Biener <[email protected]> Sat, 1 Aug 2026 08:15:13 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>

> Am 01.08.2026 um 07:42 schrieb Andrea Pinski <[email protected]>:
> 
> ifcombine uses match and match will use in some cases the global
> range causing wrong code as the range of the ssa name might be based
> on the outer condition.
> The case in the bug report is:
> ```
> 
>  # RANGE [irange] int [0, 255] MASK 0xff VALUE 0x0
>  _2 = (int) a.0_1;
>  if (_2 > 1)
>    goto <bb 4>; [59.00%]
>  else
>    goto <bb 3>; [41.00%]
> 
>  <bb 3> [local count: 440234144]:
>  # RANGE [irange] int [0, 1] MASK 0x1 VALUE 0x0
>  _8 = (int) a.0_1;
>  if (_2 > _8)
>    goto <bb 4>; [50.00%]
>  else
>    goto <bb 5>; [50.00%]
> ```
> So this was `(_2 <= 1 && _2 <= _8) ? goto 5 else; goto 4;`
> This starts by combnining `_2 <= 1 && _2 <= _8` into `_2 <= min(1, _8)`.
> But since _8 has a range of [0,1], match invokes the pattern that was added
> in r14-868-gb06cfb62229f to giving `_2 <= (_8 & 1)` and then since _8 has a
> range of [0,1], that expression simpifies into `_2 < _8` which is wrong.
> as _2 is the same as _8. So we end up with not taking the condition any more.
> 
> The problem comes follow_outer_ssa_edges is used to save off the global range
> but we return early if the variable had a type where overflow is undefined as we
> can't temporary rewrite it. So the fix is to swap around the saving the off
> the global range before returning early.
> 
> Bootstrapped and tested on x86_64-linux-gnu with no regressions.

Ok

Richard 

>    PR tree-optimization/126313
> 
> gcc/ChangeLog:
> 
>    * gimple-fold.cc (follow_outer_ssa_edges): Swap around returning
>    for undefined overflow and saving off the global range.
> 
> gcc/testsuite/ChangeLog:
> 
>    * gcc.dg/torture/pr126313.c: New test.
> 
> Signed-off-by: Andrea Pinski <[email protected]>
> ---
> gcc/gimple-fold.cc                      | 13 ++++++------
> gcc/testsuite/gcc.dg/torture/pr126313.c | 27 +++++++++++++++++++++++++
> 2 files changed, 34 insertions(+), 6 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/torture/pr126313.c
> 
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index fdb9b419766..24041466108 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -7677,17 +7677,18 @@ follow_outer_ssa_edges (tree val)
>          && (def_bb == fosa_bb
>          || dominated_by_p (CDI_DOMINATORS, fosa_bb, def_bb))))
>    return val;
> -      /* We cannot temporarily rewrite stmts with undefined overflow
> -     behavior, so avoid expanding them.  */
> -      if ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (val))
> -       || POINTER_TYPE_P (TREE_TYPE (val)))
> -      && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (val)))
> -    return NULL_TREE;
>       flow_sensitive_info_storage storage;
>       storage.save_and_clear (val);
>       /* If the definition does not dominate fosa_bb temporarily reset
>     flow-sensitive info.  */
>       fosa_unwind->safe_push (std::make_pair (val, storage));
> +      /* We cannot temporarily rewrite stmts with undefined overflow
> +     behavior, so avoid expanding them. But still save off the
> +     flow-sensitive info as we might be using the ssa name as the leaf.  */
> +      if ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (val))
> +       || POINTER_TYPE_P (TREE_TYPE (val)))
> +      && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (val)))
> +    return NULL_TREE;
>       return val;
>     }
>   return val;
> diff --git a/gcc/testsuite/gcc.dg/torture/pr126313.c b/gcc/testsuite/gcc.dg/torture/pr126313.c
> new file mode 100644
> index 00000000000..f4b754775fd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr126313.c
> @@ -0,0 +1,27 @@
> +/* { dg-do run } */
> +/* PR tree-optimization/126313 */
> +unsigned char a = 3;
> +short b, c, d;
> +int e;
> +static inline
> +char(f)(signed char g, signed char p2) {
> +  return p2 == 0 || g && p2 == 1 ? 0 : g % p2;
> +}
> +static inline
> +unsigned i(short g) {
> +  d = g;
> +  return c;
> +}
> +static inline
> +void fn3(signed char g, int p2) {
> +  if (!(1 >= p2 && p2 <= g))
> +    e = b | i(f(1, p2) > 0xE151060F);
> +  else {
> +    { d = p2; }
> +  }
> +}
> +int main() {
> +  fn3(a, a);
> +  if (d != 0)
> +    __builtin_abort ();
> +}
> --
> 2.43.0
>