问题
当自己的代码根本没有浮点或矢量运算,JVM在x86生成的机器代码为什么会用到XMM 寄存器?
基础知识
FPU 和矢量单元在现代 CPU 中随处可见,在许多情况下,它们为 FPU 特定的操作提供了一组备用寄存器。例如,Intel x86_64 中的 SSE 和 AVX 扩展具有一组额外的宽 XMM、YMM 和 ZMM 寄存器,可与更宽的指令结合使用。
虽然非矢量指令集通常与矢量和非矢量寄存器不正交(例如,我们不能在 x86_64 上将通用 IMUL 与 XMM 寄存器一起使用),但这些寄存器仍然提供了一个有趣的存储选项:我们可以将数据暂时存储在那里,即使该数据不用于矢量操作。
输入寄存器分配。寄存器分配器的职责是获取程序表示以及特定编译单元(例如方法)中程序所需的所有操作数,并将这些虚拟操作数映射到实际的机器寄存器 - 为它们分配寄存器。在许多实际程序中,给定程序位置的活动虚拟操作数的数量大于可用的机器寄存器数量。此时,寄存器分配器必须将一些操作数从寄存器中移到其他地方 - 例如堆栈上 - 即溢出操作数。
我们在 x86_64 上有 16 个通用寄存器(并非所有寄存器都可用),在大多数现代机器上还有 16 个 AVX 寄存器。我们可以溢出到 XMM 寄存器而不是堆栈吗?
实验
源码
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class FPUSpills {
int s00, s01, s02, s03, s04, s05, s06, s07, s08, s09;
int s10, s11, s12, s13, s14, s15, s16, s17, s18, s19;
int s20, s21, s22, s23, s24;
int d00, d01, d02, d03, d04, d05, d06, d07, d08, d09;
int d10, d11, d12, d13, d14, d15, d16, d17, d18, d19;
int d20, d21, d22, d23