← board

Track O: in-tree xmm fusion for float expression temporaries

Why this, split from the big ticket

[[feature-opt-float-register-temporaries]] is the FULL fix: an xmm-resident float value model touching every float consumer (binops, compares, call args/returns, stores, writeln) — a multi-session arc. This ticket is the narrow subset that captures "probably most of the win" with a one-expression-tree blast radius and no cross-statement state. Do this first; the full value-model arc stays the someday version.

The gap (bench oracle)

bench/portable/mandelbrot.pas: pxx -O2 1.33s vs FPC -O2 0.32s = 4.2x, with an IDENTICAL checksum (74607393270 @1600x1200) — same work, worse codegen. Root: the x86-64 value model carries a Double as raw bits in RAX, so each float IR_BINOP emits 3 GPR↔XMM transfers + a stack round-trip:

eval left -> rax, push rax; eval right -> rax, mov rcx <- pop;
movq xmm1, rax; movq xmm0, rcx; <op>; movq rax, xmm0

The mandelbrot inner loop (zr*zr - zi*zi + cr, …) round-trips every temporary through memory + GPR.

Scope of THIS ticket

The -O3 entanglement

-O3 currently makes float WORSE (2.47s) — the W1 operand scheduler ([[project_o3_w1_operand_scheduler]]) pessimizes float chains. So landing this behind -O3 must NOT compose with W1's float pessimization: either make W1 xmm-aware or gate W1 off for float trees as part of this work. May be a quick standalone win on its own.

Acceptance

Non-goals

Log