xchg reg,regmov instructions, but requires an extra register or
memory location. The AMD64 instruction set contains the
instruction xchg, which swaps the registers without extra
location.
More generally, there may be more than two registers whose values
have to be moved in a cyclic way. This also requires an extra
register or memory location and (for an n-register cycle)
n+1 mov instructions if performed using mov
instructions, or it can be achieved with n-1 xchg
instructions.
Mov instructions are supported very well in recent CPU
cores, with the cores usually being able to perform as many
independent (and often even dependent) moves as the register renamer
accepts instructions (e.g., if the register renamer accepts 8
instructions per cycle, 8 moves per cycle can be performed, usually
even dependent moves).
But how do xchg instructions perform? Should a
register allocator use them where they are convenient, or prefer to
use mov instructions and an extra register?
This page contains microbenchmarks and presents results for them on
various cores from Intel and AMD. The first set of microbenchmarks
perform 1G xchg instructions in a loop containing
28 xchg instructions (plus two instructions for the
loop).
One (independent) contains a sequence of
7 xchg instructions that are fully independent of each
other, all accessing different registers, followed by the same
sequence another three times. So the xchg instructions are as
independent as possible with 14 registers involved.
The other (dependent) contains a sequence of
14 xchg instructions where each subsequent instruction
uses one register of the previous instruction, implementing a
15-register cycle. This sequence is followed by the reversal of this
sequence, resulting in performing the 15-register cycle in the other
direction.
Here are the results in Gcycles on recent microarchitectures, i.e.,
a result of 0.25 means that the microarchitecture performs
4 xchg instructions per cycle. Smaller is better.
indep dep core family CPU 0.26 0.26 Zen5 AMD Ryzen AI Pro 350 0.35 0.35 Zen4 AMD Ryzen 8700G 0.35 0.35 Zen3 AMD Ryzen 5800X 0.61 1.50 Lion Cove Intel P Core Ultra 225 1.00 1.50 Golden Cove Intel P Core i3-1315U 0.82 1.50 Rocket Lake Intel P Xeon E-2388G 2.07 2.05 Skymont Intel E Core Ultra 225 3.45 3.45 Gracemont Intel E Core i3-1315U
Given the results of the dependent benchmark, it looks like the AMD
processors perform xchg in the register renamer,
consuming the resources of two ordinary instructions there (probably
because two result registers are involved).
On Intel microarchitectures, whether P-cores or E-cores, but
especially the latter, xchg seems to have gotten little
love.
Let's see how this affects cyclic moves between registers. The following microbenchmarks perform cyclic moves through 2-5 registers (cyc2-cyc5) in three different ways:
movs in case of reg, n-1 xchgs in case of
xchg).
cyc2 | cyc3 | cyc4 | cyc5 |core family CPU
mem reg xchg|mem reg xchg|mem reg xchg|mem reg xchg|
0.50 0.50 0.27|0.67 0.58 0.52|0.83 0.83 0.77|1.08 0.83 1.02|Zen5 AMD Ryzen AI Pro 350
1.00 0.51 0.36|1.00 0.68 0.69|1.00 0.85 1.03|1.01 1.01 1.36|Zen4 AMD Ryzen 8700G
1.00 0.51 0.42|1.00 0.68 0.70|1.00 0.92 1.03|1.02 1.01 1.36|Zen3 AMD Ryzen 5800X
0.50 0.40 0.68|0.54 0.56 1.28|0.67 0.66 1.97|0.81 0.81 4.21|Lion Cove Intel P Core Ultra 225
0.61 0.53 1.00|0.70 0.70 2.00|0.89 0.90 3.00|1.06 1.08 4.41|Golden Cove Intel P Core i3-1315U
0.82 0.67 1.00|0.87 0.83 2.00|1.08 1.08 3.00|1.22 1.22 4.66|Rocket Lake Intel P Xeon E-2388G
1.00 0.40 1.45|0.65 0.73 4.14|0.65 0.65 7.35|0.78 0.86 9.44|Skymont Intel E Core Ultra 225
0.67 0.67 3.08|0.83 0.83 6.73|1.03 1.03 10.63|1.23 1.23 13.77|Gracemont Intel E Core i3-1315U
On Zen5, even a 5-register cycle can be profitably implemented with
xchg when you have no spare register, a 4-register cycle
even when you have a spare register. For Zen4 and Zen3 cyc4 (for mem)
and cyc3 (for reg) are borderline cases, and for shorter cycles
xchg is better.
On Intel processors, xchg is so slow that it never is
profitable to use it. The slowness takes on extreme values in
the E-cores, with slowdowns by a factor >10 for cyc4 and cyc5.
| Name | Last modified | Size | Description | |
|---|---|---|---|---|
| Parent Directory | - | |||
| Makefile | 2026-10-13 10:42 | 864 | ||
| cyc5xchg | 2026-10-13 09:53 | 16K | ||
| cyc5reg | 2026-10-13 09:53 | 16K | ||
| cyc5 | 2026-10-13 09:53 | 16K | ||
| cyc4xchg | 2026-10-13 09:53 | 16K | ||
| cyc4reg | 2026-10-13 09:53 | 16K | ||
| cyc4 | 2026-10-13 09:53 | 16K | ||
| cyc3xchg | 2026-10-13 09:53 | 16K | ||
| cyc3reg | 2026-10-13 09:53 | 16K | ||
| cyc3 | 2026-10-13 09:53 | 16K | ||
| cyc2xchg | 2026-10-13 09:53 | 16K | ||
| cyc2reg | 2026-10-13 09:53 | 16K | ||
| cyc2 | 2026-10-13 09:53 | 16K | ||
| main.c | 2026-10-13 09:53 | 133 | ||
| cyc5xchg.s | 2026-10-13 09:53 | 1.0K | ||
| cyc5reg.s | 2026-10-13 09:53 | 1.0K | ||
| cyc5.s | 2026-10-13 09:53 | 1.1K | ||
| cyc4xchg.s | 2026-10-13 09:53 | 919 | ||
| cyc4reg.s | 2026-10-13 09:53 | 960 | ||
| cyc4.s | 2026-10-13 09:53 | 1.0K | ||
| cyc3xchg.s | 2026-10-13 09:53 | 821 | ||
| cyc3reg.s | 2026-10-13 09:53 | 863 | ||
| cyc3.s | 2026-10-13 09:53 | 923 | ||
| cyc2xchg.s | 2026-10-13 09:53 | 723 | ||
| cyc2reg.s | 2026-10-13 09:53 | 766 | ||
| cyc2.s | 2026-10-13 09:53 | 826 | ||
| dependent | 2026-10-12 09:41 | 16K | ||
| independent | 2026-10-12 09:41 | 16K | ||
| dependent.s | 2026-10-12 09:10 | 1.0K | ||
| bench | 2026-10-12 08:54 | 16K | ||
| independent.s | 2026-10-12 08:49 | 1.0K | ||