Mar*_*377 10 optimization gcc instruction-set cpu-architecture instructions
有这个相关的问题:海湾合作委员会:游行与mtune有何不同?
但是,现有答案并没有比GCC手册本身更进一步.我们最多得到:
如果您使用
-mtune
,那么编译器将生成适用于其中任何一个的代码,但将支持在您指定的特定CPU上运行速度最快的指令序列.
和
该
-mtune=Y
选项调整生成的代码以在Y上运行得比在其可能运行的其他CPU上运行得更快.
但是GCC 如何支持一个特定的体系结构,在构建时,同时仍然能够在其他(通常是较旧的)体系结构上运行构建,虽然速度较慢?
我只知道有一件事(但我不是计算机科学家)才能做到这一点,而且那是一个CPU调度员.但是,(对我来说)似乎并不是mtune
在幕后生成调度程序,而是其他一些机制可能正在生效.
我觉得这样做有两个原因:
mtune
)并测试cpuid
在运行时检测支持的指令,而不是依赖于在构建时提供的命名体系结构.那么它如何运作呢?
Mar*_*oom 15
-mtune
不创建调度程序,它不需要一个:我们已经告诉编译器我们所针对的架构.
来自海湾合作委员会的文件:
-mtune = CPU型
调整cpu-type所有适用于生成代码的内容,但ABI和
可用指令集除外.
这意味着GCC不会使用仅在cpu-type 1上可用的指令,但它将生成在cpu-type上最佳运行的代码.
要理解这最后的陈述,有必要了解架构和微架构之间的区别.
该架构意味着ISA(指令集架构)并且不受其影响-mtune
.
微架构是架构在硬件中的实现方式.对于相等的指令集(读取:体系结构),由于实现的内部细节,代码序列可以在CPU(读取微架构)上最佳地运行而在另一个上不运行.这可以使代码序列仅在一个微架构上是最佳的.
在生成机器代码时,GCC通常可以自由选择如何订购指令以及使用哪种变体.
它将使用启发式方法生成一系列指令,这些指令在最常见的CPU上快速运行,有时它将牺牲100%的CPU x最佳解决方案,如果这会损害CPU y,z和w.
当我们使用-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;
}
Run Code Online (Sandbox Code Playgroud)
的a[i] += b[i];
被矢量化靶向SKYLAKE微架构或核2时(如果载体不重叠)是不同的:
SKYLAKE微架构
movups xmm0, XMMWORD PTR [rsi]
movups xmm2, XMMWORD PTR [rdi]
addps xmm0, xmm2
movups XMMWORD PTR [rdi], xmm0
movss xmm0, DWORD PTR [rdi]
Run Code Online (Sandbox Code Playgroud)
酷睿2
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]
Run Code Online (Sandbox Code Playgroud)
主要区别在于如何xmm
加载寄存器,在Core2上加载两个加载movlps
而movhps
不是使用单个加载movups
.
在Core2微架构上,两种负载方法更好,如果你看一下Agner Fog的指令表,你会看到它movups
被解码为4 uop并且具有2个周期的延迟,而每个周期movXps
为1 uop和1个周期潜伏.
这可能是因为当时128位访问被分成两个64位访问.
在Skylake上,情况正好相反:movups
表现优于两个movXps
.
所以我们必须拿起一个.
一般来说,GCC选择了第一个变种,因为Core2是一个古老的微架构,但我们可以用它来覆盖它-mtune
.
1与其他开关一起选择指令集.