Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么这个指令序列更快?_C++_Gcc_Assembly_X86_Clang - Fatal编程技术网

C++ 为什么这个指令序列更快?

C++ 为什么这个指令序列更快?,c++,gcc,assembly,x86,clang,C++,Gcc,Assembly,X86,Clang,我在比较GCC和clangoutput对浮点表达式的求值时,偶然发现了一个无法解释的性能差异 源代码 float evaluate(float a, float b) { return (a - b + 1.0f) * (a - b) * (a - b - 1.0f); } GCC 7.2(-std=c++1y-O2)生产 而Clang5.0.0(-std=c++1y-O2)产生了 GCC似乎更喜欢movaps而不是movss,即使在这种情况下movss就足够了。正如所指出的,这实际上

我在比较GCC和clangoutput对浮点表达式的求值时,偶然发现了一个无法解释的性能差异

源代码

float evaluate(float a, float b) {
    return (a - b + 1.0f) * (a - b) * (a - b - 1.0f);
}
GCC 7.2(-std=c++1y-O2)生产

而Clang5.0.0(-std=c++1y-O2)产生了

GCC似乎更喜欢
movaps
而不是
movss
,即使在这种情况下
movss
就足够了。正如所指出的,这实际上比使用
movaps
避免XMM寄存器的部分更新暂停更好

GCC使用三个而不是两个XMM寄存器

Clang使用两个常量并仅为其添加,而不是仅使用一个常量并使用subss从寄存器中减去一个常量

我画出了这些序列的指令级真实依赖关系,而Clang的则短了一级

性能方面,与我预期的完全不同,GCC版本大约快30%

我已经在Intel(Broadwell)和AMD(推土机)CPU上测试过,我不明白为什么GCC代码在这里会更快

原始基准使用了错误的内联asm代码。在创建了两个对象文件(一个带有GCC,一个是Clang),用于感兴趣的函数的C++代码,并用GCC链接到它们时,性能差异消失了。< /强> Peter Cordes暗示这可能是因为<代码> -O1 < /C> >省去<代码> .2AlcIn < /Cord>指令。
我查看了新基准测试方法的编译器输出,并断言
evaluate()
的两个实现具有与上述完全相同的代码,编译器实际上正在调用它们。

您使用了哪些优化标志来生成gcc/clang输出?gcc更彻底地利用寄存器执行一次加载,当clang执行两次加载时,您在这里测量吞吐量,因此依赖关系图的深度没有普通计数重要。顺便说一句,像这样的寄存器之间的mov在现代CPU上通常没有延迟。
movsxmm1,xmm0
合并到
xmm0
。使用
movaps
是复制包含任何FP值的xmm寄存器的最佳选择,即使只有低位元素有用。删除所有asm()后,依靠GCC和Clang生成自己的代码,并使用GCC和-O3链接这些对象文件,它们的吞吐量基本相同。将使用此更新问题。
evaluate(float, float):
  subss xmm0, xmm1
  movss xmm2, DWORD PTR .LC0[rip]
  movaps xmm1, xmm0
  addss xmm1, xmm2
  mulss xmm1, xmm0
  subss xmm0, xmm2
  mulss xmm0, xmm1
  ret
.LC0:
  .long 1065353216
.LCPI0_0:
  .long 1065353216 # float 1
.LCPI0_1:
  .long 3212836864 # float -1
evaluate(float, float): # @evaluate(float, float)
  subss xmm0, xmm1
  movss xmm1, dword ptr [rip + .LCPI0_0] # xmm1 = mem[0],zero,zero,zero
  addss xmm1, xmm0
  mulss xmm1, xmm0
  addss xmm0, dword ptr [rip + .LCPI0_1]
  mulss xmm0, xmm1
  ret