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