2026-09-13
Modern x86 and ARM cores don't always execute the instructions you wrote. During decode, the front-end scans for fusible pairs — two adjacent instructions that share a data dependency and can be treated as one internal operation. The result: fewer µops flowing down the pipeline, less pressure on the reorder buffer, and one extra instruction retired per cycle for free.
There are two flavors:
CMP + Jcc — a compare followed by a conditional branch. Intel has fused this since Core 2 (2006); AMD since Bulldozer. The compare's flag result never enters the pipeline as a separate operation — the branch unit consumes it directly.ADD [rax], rbx (load-op-store) decodes into multiple µops, but the front-end tracks them as one "fused domain" entry through the ROB. They only split into separate µops at the scheduler, where the load, add, and store issue to different execution ports. This keeps ROB usage low without sacrificing scheduling flexibility.Concrete example: consider a tight loop cmp rcx, 100 / jl loop. Without fusion, that's 2 µops per iteration. With macro-op fusion, it's 1 µop — the branch predictor, ROB entry, and retirement slot all handle it as one operation. On a 4-wide decoder, this effectively widens the useful issue rate. Compilers know this: GCC and LLVM place compares immediately before their branches, not separated by unrelated ops, specifically to preserve fusibility.
Rules of thumb: fusion typically requires the two instructions be in the same 16-byte or 32-byte fetch window, adjacent in program order, and match a hardcoded pattern list. Intel's fusible-pair list includes TEST/AND + Jcc, CMP/ADD/SUB + Jcc, and DEC/INC + Jcc. Miss the window boundary by one byte and fusion silently fails — a real reason `.p2align` directives appear before hot loops in optimized code.
The catch: fusion only helps when the pattern actually matches. Move a MOV between your CMP and JL and you've broken it. This is why micro-architectural tuning guides read like arcane spellbooks — the difference between 1 IPC and 4 IPC in a hot loop can come down to whether your compare-branch pair straddles a 32-byte boundary.
