https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53805
--- Comment #14 from Richard Biener <rguenth at gcc dot gnu.org> --- Created attachment 65715 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65715&action=edit patch from LLM ✦ Root-Cause Analysis Two distinct problems caused f in obj/gcc/t.c (if (a > b) if (a < b) return 1; return 0;) to have its conditions folded away without preserving the IEEE invalid operation exception on NaNs: 1. fold-const.cc (combine_comparisons) incorrectly considered constants as trapping: Under flag_trapping_math, combine_comparisons verifies whether the combined comparison preserves traps: 1 bool trap = (compcode & COMPCODE_UNORD) == 0 2 && (compcode != COMPCODE_EQ) 3 && (compcode != COMPCODE_ORD); When combining conflicting comparisons such as a > b and a < b, compcode is COMPCODE_FALSE (0). Because 0 & COMPCODE_UNORD == 0, and 0 is neither COMPCODE_EQ (2) nor COMPCODE_ORD (7), trap evaluated to true. combine_comparisons concluded that constant 0 (false) trapped under the same conditions as a > b ((ltrap || rtrap) == trap), erroneously folding the combination into boolean_false_node instead of returning ERROR_MARK / NULL_TREE. This affected all callers including match.pd, gimple-fold.cc, tree-ssa-phiopt.cc, and tree-ssa-ifcombine.cc. 2. tree-ssa-ifcombine.cc (ifcombine_ifandif) mishandled trapping outer conditions and operand ordering: - Commit ea33efbbdcf guarded trapping combinations with if (gimple_could_trap_p (inner_cond)). If the outer condition could trap but the inner condition did not (e.g., if (a > b) if (a == b)), it bypassed the guard and fell through to general combination, eliminating outer_cond and its trap. - Inside the trapping combination block, res was not verified to be non-constant (TREE_CODE (res) != INTEGER_CST). Replacing trapping conditions with constants eliminates their basic blocks and IEEE exceptions. - In the general fallback path (maybe_fold_and_comparisons), inner_cond_code was passed before outer_cond_code, reversing the short-circuit evaluation order (inner && outer instead of outer && inner) and dropping traps when outer_cond was trapping. Applied Fixes (Separate Git Commits) Commit 1: e5437e31f25 fold-const: Do not treat COMPCODE_FALSE or COMPCODE_TRUE as trapping in combine_comparisons - Changes in gcc/fold-const.cc: Require compcode != COMPCODE_FALSE && compcode != COMPCODE_TRUE for trap to be true. - Testcase: gcc/testsuite/gcc.dg/tree-ssa/fp-trapping-and-1.c verifying that (a > b) & (a < b) retains both comparisons under -ftrapping-math. Commit 2: a00903b4a9b ifcombine: Handle trapping outer conditions and preserve operand order - Changes in gcc/tree-ssa-ifcombine.cc: - Check gimple_could_trap_p (inner_cond) || gimple_could_trap_p (outer_cond). - Disallow replacing trapping conditions when TREE_CODE (res) == INTEGER_CST. - Pass outer_cond before inner_cond to maybe_fold_and_comparisons. - Testcase: gcc/testsuite/gcc.dg/tree-ssa/fp-trapping-cmp-6.c verifying that ifcombine does not fold away if (a > b) if (a < b) or if (a > b) if (a == b). as said, I'm not sure whether we want it this way in combine_comparison or whether we should separate trapping from combining there to possibly preserve parts of the optimization.
