-mtune
选项不会创建调度程序,因为我们已经告诉编译器我们的目标架构。从GCC文档可知,-mtune=cpu-type将优化生成的代码适应于指定的CPU类型,除了ABI和可用指令集之外的所有内容。这意味着 GCC 不会使用仅在特定 CPU 上可用的指令,但是它将生成在该 CPU 上运行最优的代码。
理解上述陈述需要了解架构和微体系结构之间的区别。架构涉及指令集架构(ISA),而它并不受 -mtune
的影响。微体系结构是指如何在硬件上实现架构。对于相同的指令集(即架构),由于实现的内部细节不同,代码序列可能在一种 CPU(即微体系结构)上运行得最优,但在另一种 CPU 上则不是。有时候,某个代码序列只能在某一微体系结构上运行得最优。
在生成机器代码时,GCC 通常可以自由选择指令的顺序和使用的变体。它会使用一种启发式方法生成一系列在最常见的 CPU 上运行快速的指令,有时为了不损害其他 CPU 的性能而牺牲某个特定 CPU 上的100%最优解。
当我们使用 -mtune=x
选项时,我们可以微调 GCC 以适应 CPU x,从而生成对该 CPU 来说是100%最优(从GCC角度来看)的代码。下面提供一个具体示例。
float bar(float a[4], float b[4])
{
for (int i = 0; i < 4; i++)
{
a[i] += b[i];
}
float r=0;
for (int i = 0; i < 4; i++)
{
r += a[i];
}
return r;
}
a[i] += b[i];
对于Skylake和Core2,如果向量不重叠,则矢量化方式不同:
Skylake
movups xmm0, XMMWORD PTR [rsi]
movups xmm2, XMMWORD PTR [rdi]
addps xmm0, xmm2
movups XMMWORD PTR [rdi], xmm0
movss xmm0, DWORD PTR [rdi]
Core2
pxor xmm0, xmm0
pxor xmm1, xmm1
movlps xmm0, QWORD PTR [rdi]
movlps xmm1, QWORD PTR [rsi]
movhps xmm1, QWORD PTR [rsi+8]
movhps xmm0, QWORD PTR [rdi+8]
addps xmm0, xmm1
movlps QWORD PTR [rdi], xmm0
movhps QWORD PTR [rdi+8], xmm0
movss xmm0, DWORD PTR [rdi]
主要区别在于如何加载一个
xmm
寄存器,在Core2上,使用
movlps
和
movhps
进行两次加载,而不是使用单个
movups
。
在Core2微架构中,这种两次加载的方式更好,如果你查看Agner Fog的指令表,你会发现
movups
被解码成4个微操作,并且具有2个时钟周期的延迟,而每个
movXps
是1个微操作和1个时钟周期的延迟。
这可能是因为当时128位访问被分成了两个64位访问。
在Skylake上相反的情况是真实的:
movups
比两个
movXps
执行得更好。
所以我们必须选择一个。
一般来说,GCC选择第一个变量,因为Core2是一种旧的微架构,但我们可以用-mtune
覆盖这个设置。
1指令集是通过其他开关选择的。
march
与mtune
之间的区别。虽然这些问题展示了mtune
的承诺,但这个问题特别询问编译器可以做什么来实现这些承诺。 - bolov