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