https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127786

--- Comment #5 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Igor Shevlyakov
<[email protected]>:

https://gcc.gnu.org/g:400a1d5536978e7392781151bd14aea85f9f90d1

commit r17-5641-g400a1d5536978e7392781151bd14aea85f9f90d1
Author: Igor Shevlyakov <[email protected]>
Date:   Thu Oct 22 20:18:15 2026 -0700

    gimple-fold: Let callers say whether comparisons short-circuit [PR127786]

    and_comparisons_1 and or_comparisons_1 pass TRUTH_ANDIF_EXPR and
    TRUTH_ORIF_EXPR to combine_comparisons, whatever the caller.  Under
    -ftrapping-math combine_comparisons keeps the result trapping on a NaN
    exactly when the original evaluation did.  It needs to know which
    comparisons that evaluation runs.  With TRUTH_AND_EXPR both run, so
    the original traps when either one traps.  With TRUTH_ANDIF_EXPR the
    second runs only when the first is true, so it sees a NaN only if the
    first is true for unordered operands.  Each code is exact for its
    own case and wrong for the other.  TRUTH_ANDIF_EXPR on operands that
    are both evaluated drops the exception of the second comparison,
    which is what reassoc does with BIT_AND_EXPR and BIT_IOR_EXPR:

    - !__builtin_isgreaterequal (a, b) | (a > b) became a quiet a != b,
      dropping the FE_INVALID that a > b raises for a NaN;
    - (a <= b) & (a == b) became a quiet a == b;
    - a < b || __builtin_isunordered (a, b), once phiopt has made both
      comparisons unconditional, became a quiet a u< b.

    TRUTH_AND_EXPR on short-circuited operands would add an exception
    instead: ORDERED (a, b) && a < b would become a < b.

    So add a CODE argument to maybe_fold_and_comparisons and
    maybe_fold_or_comparisons, pass it down to combine_comparisons, and
    have each caller say how it evaluates the comparisons:

    - ifcombine: TRUTH_ANDIF_EXPR, as before.  The inner condition is
      only evaluated when the outer one is true.
    - reassoc, both for scalar operands and for VEC_COND_EXPR conditions:
      TRUTH_AND_EXPR and TRUTH_OR_EXPR, since it combines the operands of
      a BIT_AND_EXPR or BIT_IOR_EXPR.
    - if-conversion's fold_or_predicates: TRUTH_OR_EXPR, since the
      if-converted code computes the block predicates unconditionally.
    - The uninitialized-use predicate analysis: TRUTH_ANDIF_EXPR, as
      before.  It only uses the value of the result, so this just keeps
      its behavior.

    The recursion keeps the code.  It swaps AND and OR, keeping the
    short-circuit, where De Morgan's law turns one into the other.
    maybe_fold_or_comparisons also tries the two comparisons in the other
    order.  That is only valid when both are evaluated, so it now does so
    only for TRUTH_OR_EXPR.  Every current OR caller passes TRUTH_OR_EXPR,
    so that only restricts the internal recursion reached from ifcombine
    through an inverted AND.

    A combination that folds to a constant, e.g. (a < b) & (a > b) -> 0,
    can still lose the exception, as x < x -> 0 does.

    Assisted-by: Claude Opus 5.5

            PR middle-end/127786

    gcc/ChangeLog:

            * gimple-fold.h (maybe_fold_and_comparisons)
            (maybe_fold_or_comparisons): Add a tree_code argument.
            * gimple-fold.cc (truth_andor_compl): New function.
            (and_comparisons_1, and_var_with_comparison)
            (and_var_with_comparison_1, or_comparisons_1)
            (or_var_with_comparison, or_var_with_comparison_1): Add a
            tree_code argument and pass it down; pass its complement when
            switching between AND and OR.
            (maybe_fold_and_comparisons): Add a tree_code argument and pass it
            to and_comparisons_1.
            (maybe_fold_or_comparisons): Likewise for or_comparisons_1.  Try
            the swapped order only for TRUTH_OR_EXPR.
            * tree-ssa-ifcombine.cc (ifcombine_ifandif): Pass TRUTH_ANDIF_EXPR.
            * gimple-predicate-analysis.cc (simplify_1b): Likewise.
            * tree-ssa-reassoc.cc (eliminate_redundant_comparison)
            (optimize_vec_cond_expr): Pass TRUTH_AND_EXPR or TRUTH_OR_EXPR.
            * tree-if-conv.cc (fold_or_predicates): Pass TRUTH_OR_EXPR.

    gcc/testsuite/ChangeLog:

            * gcc.dg/torture/cmp-of-cmp-fenv-2.c: New test.
            * gcc.dg/tree-ssa/fp-trapping-cmp-9.c: New test.

    Signed-off-by: Igor Shevlyakov <[email protected]>

Reply via email to