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.

Reply via email to