https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125970
--- Comment #4 from vekumar at gcc dot gnu.org ---
(In reply to cuilili from comment #3)
> For option -O2 -mtune=generic -march=x86-64-v3, commit causes a ~15%
> regression on the HINT benchmark. The commit converts the branch inc =
> (errio < errjo) + 1 in the hot loop into a cmov/setcc sequence.
>
> HINT's hot loop is memory-bound ("load a batch → little FP math → store a
> batch"), so its performance depends on MLP — keeping many memory accesses in
> flight so their latencies overlap.
>
> Branch version: the branch is well-predicted, so the CPU speculates past the
> compare and computes these addresses early → memory accesses issue ahead of
> time → high MLP, latencies hidden.
>
> cmov version: the cmov sequence itself is not expensive, but the selected
> value is used directly as a memory address index for the following accesses,
> it cannot be speculated. Address generation is pinned to the critical path
> (compare → setcc → cmov → lea), so the dependent accesses can no longer
> issue early. Overlap drops and MLP collapses.
>
> cmov version:
>
> comisd %xmm3,%xmm1
> seta %r10b
> cmova %r12d,%r15d
> movzbl %r10b,%r10d --- %r10 is used as an array index for the following
> stores.
> lea 0x1(%r10,%rsi,1),%r10d --- r10 ← r10+rsi+1 = index A
> movsd %xmm3,(%r9,%r10,8) --- store, uses index A
> mov %r11d,0x0(%rbp,%r10,4) --- store, uses index A
> lea (%rsi,%r15,1),%r10d --- r10 ← rsi+r15 = index B, new r10,
> break the dependency
> movsd %xmm1,(%r9,%r10,8) --- store, uses index B
> mov %ecx,0x0(%rbp,%r10,4) --- store, uses index B
> mov %esi,%r10d ---r10 ← esi new r10,breaks the dependency.
> movsd 0x8(%rax),%xmm9
> mulsd %xmm2,%xmm1
> ucomisd 0x10(%r9,%r10,8),%xmm4
> setp %r10b
> movzbl %r10b,%r10d
> cmovne %r12d,%r10d
> add %esi,%r10d
> -----------------------------------------------------------------------
>
> It is hard to add a heuristic:
>
> When the cmov's result feeds address computation, a misprediction is also
> more expensive than usual (speculative memory accesses on the wrong path
> must be squashed and redone). It is a trade-off that depends on
> predictability — cmov wins when the branch is poorly predicted, the branch
> wins when it is well-predicted — and static analysis cannot decide it
> without profile data.
>
> Root limitation: static prediction cannot reflect real run-time behavior.
>
> GCC's static branch-prediction probability for this branch:
>
> if (errio < errjo)
> goto <bb 7>; [50.00%]
> else
> goto <bb 6>; [50.00%]
>
> GCC estimate: 50% / 50%
> Reality (perf): 9.53% / 90.47% taken ratio — the branch is highly
> predictable. (~99% correctly predicted).
Yes this matches my observations. If we want to stop "cmov" generation, for
this case, I can think of high-level heuristics like the candidate cmov result
is used to further index in loads/stores or feeds another cmov in a loop.