On 10/13/26 2:36 PM, Richard Biener wrote:
On Tue, Oct 13, 2026 at 10:45 AM Vineet Gupta <[email protected]> wrote:
With -ffuse-ops-with-volatile-access general_operand accepts volatile
MEMs during combine. For "int a = x; int b = y; return a < b;" with
volatile x and y, combine first merges the load of y into the compare
and then the load of x, giving (compare (mem/v x) (mem/v y)). The
Why does this pass recog when it later needs reloading?
For posterity and someone like me in the future pondering this exact
question (sorry I couldn't help myself: after all I'm gcc md for the
confused guy and still mostly confused) - but not trying to preach to
the choir.
The x86 compare pattern currently is:
(define_insn "*cmp<mode>_1"
[(set (reg FLAGS_REG)
(compare (match_operand:SWI 0 "nonimmediate_operand" "<r>m,<r>")
^^^^^^ #1 ^^^^^^^ ^^^ #2 ^^^
(match_operand:SWI 1 "<general_operand>" "<r><i>,<r><m>")))]
^^^^^^ #1 ^^^^^^^ ^^^ #2 ^^^
"ix86_match_ccmode (insn, CCmode)" #3
"cmp{<imodesuffix>}\t{%1, %0|%0, %1}")
recog matches the predicates (#1) and the pattern condition (#3), but
ignores the constraints (#2) which are only needed at the time of
Register allocation (LRA).
combine calls recog() and the predicates allow (compare (mem x) (mem
y)), although the constraints don't allow a mem+mem combination (m is
present in 2 different alternates, not same).
LRA validates the constraints: neither alternative allows two mem
operands so it picks alternative 0, which allows memory for op 0, and
moves op 1 into a register with an extra instruction placed before the
compare - that's the classic LRA "reload" operation.
This was all good and fine for non volatiles where additional load,
possibly reordered, didn't matter. But this breaks for volatiles,
specially after -ffuse-ops-with-volatile-access. Before that, combine
runs with volatile_ok == 0 and general_operand rejected volatile MEMs.
Thx,
-Vineet