2026-08-31
The uop cache (Decoded Stream Buffer, DSB) stores decoded micro-ops so the CPU can skip the expensive x86 length-decode and translate stages. But its slots have fixed-width encoding constraints, and x86 instruction prefixes eat into that budget in ways that surprise even experienced developers.
Each DSB entry on Intel Skylake-family cores can hold up to 6 uops per 32-byte fetch window, but the encoding also has to store the original instruction pointer offset, immediate operands, displacement bytes, and any prefix bytes. When an instruction carries multiple prefixes — REX for 64-bit operand size, VEX for AVX encoding, EVEX for AVX-512, plus segment overrides or LOCK — the metadata overhead can push the instruction into a form that won't fit in a DSB slot at all. The instruction then falls back to the legacy decode path (MITE), and the whole 32-byte window may be evicted from the uop cache.
Concrete example: a hand-written crypto loop using AVX-512 with EVEX prefixes, masking ({k1}), and memory broadcasts ({1to8}) can carry 4-byte EVEX prefixes plus a 32-bit displacement. Intel's optimization manual documents that instructions requiring the MSROM path, or those with multi-byte immediates plus multi-byte displacements plus prefixes, may not enter the DSB. A tight AVX-512 loop that should run entirely from the uop cache at 6 uops/cycle instead falls back to legacy decode at ~4 uops/cycle from the complex decoder — a 33% frontend bandwidth loss on code that looks maximally optimized.
Rule of thumb: if an instruction has both an immediate operand (say, 32-bit) and a memory operand with a 32-bit displacement and a prefix, it consumes roughly:
That's 3 of your 6 slots for a single instruction. Two such instructions and the DSB line is full — you get 2 instructions per 32-byte window instead of 6, cutting effective frontend throughput by 3x.
Practical mitigation: use perf stat -e idq.dsb_uops,idq.mite_uops to see the DSB-to-MITE ratio. If MITE uops climb above ~10% of total, hunt for instructions with big immediates + big displacements + VEX/EVEX prefixes. Fixes: use register-indirect addressing, hoist constants into registers, or prefer VEX (3-byte) over EVEX (4-byte) when AVX-512 features aren't needed.
