On Fri, 23 Oct 2026, Richard Biener wrote:
> I still believe it's dangerous to simply change {and,or}_comparisons_1
> since at least the maybe_fold_and_comparisons caller calls it from
> a context where TRUTH_ANDIF_EXPR is correct which is why I suggested
> (ISTR I did ...) to pass down the kind from callers and investigate/adjust
> all ultimate callers.

I see your point. I reworked the patch, it is now more invasive but
hopefully does better job overall.
v2 adds a tree_code argument to maybe_fold_and_comparisons
and maybe_fold_or_comparisons, threads it through the recursion down
to combine_comparisons, and has each caller pass the code that
matches how it evaluates the two comparisons:

  ifcombine                       TRUTH_ANDIF_EXPR (as now)
  reassoc, scalar and vec_cond    TRUTH_AND_EXPR / TRUTH_OR_EXPR
  if-conv fold_or_predicates      TRUTH_OR_EXPR
  uninit predicate analysis       TRUTH_ANDIF_EXPR (as now; it only
                                  uses the value)

Where De Morgan's law turns an AND into an OR in the recursion, the
code switches to the matching OR code (ANDIF <-> ORIF, AND <-> OR).
maybe_fold_or_comparisons also retries with the two comparisons
swapped; that is only valid when both are evaluated, so it now does
that only for TRUTH_OR_EXPR.

> I'm also not sure either TRUTH_ANDIF_EXPR or TRUTH_AND_EXPR is
> conservatively correct?

Each is exact for its own evaluation, and neither is safe for the
other.  combine_comparisons requires the combined comparison to trap
for a NaN exactly when the original evaluation does:

- TRUTH_AND_EXPR: both comparisons run on the same operands, so the
  original traps when either one traps.  combine_comparisons requires
  trap == (ltrap || rtrap).

- TRUTH_ANDIF_EXPR: the second comparison runs only when the first is
  true, so it sees a NaN only if the first is true for unordered
  operands.  That is the rtrap = false adjustment.  combine_comparisons
  also refuses a merge where only the second one traps.

Using ANDIF on comparisons that are both evaluated drops an
exception: reassoc turned (a == b) & (a <= b) into a quiet a == b.
Using AND on comparisons that are really short-circuited adds one:
ORDERED (a, b) && a < b would become a < b.  This is the example in
the comment in combine_comparisons.  That is why the code has to come
from the caller rather than being fixed in and_comparisons_1.

For ifcombine, nothing changes in practice.  When the inner condition
can trap, ifcombine calls combine_comparisons itself.  It reaches
maybe_fold_and_comparisons only for an inner condition that cannot
trap, and there the two codes give the same answer.  It now says
TRUTH_ANDIF_EXPR explicitly.

v2 follows.

Igor


Reply via email to