Vin*_*ent 6 c++ optimization assembly gcc bit-shift
请考虑以下代码:
#include <limits>
#include <cstdint>
using T = uint32_t; // or uint64_t
T shift(T x, T y, T n)
{
return (x >> n) | (y << (std::numeric_limits<T>::digits - n));
}
Run Code Online (Sandbox Code Playgroud)
根据godbolt,clang 3.8.1 为-O1,-O2,-O3生成以下汇编代码:
shift(unsigned int, unsigned int, unsigned int):
movb %dl, %cl
shrdl %cl, %esi, %edi
movl %edi, %eax
retq
Run Code Online (Sandbox Code Playgroud)
而gcc 6.2(即使有-mtune=haswell
)生成:
shift(unsigned int, unsigned int, unsigned int):
movl $32, %ecx
subl %edx, %ecx
sall %cl, %esi
movl %edx, %ecx
shrl %cl, %edi
movl %esi, %eax
orl %edi, %eax
ret
Run Code Online (Sandbox Code Playgroud)
这似乎远没有那么优化,因为SHRD在英特尔Sandybridge和后来非常快.无论如何重写函数以便编译器(尤其是gcc)进行优化并支持使用SHLD/SHRD汇编指令?
或者是否有任何gcc -mtune
或其他选项可以鼓励gcc更好地调整现代Intel CPU?
有了-march=haswell
它,它会发出BMI2 shlx/shrx,但仍然没有shrd.
不,我看不到让gcc使用该SHRD
指令的方法.
您可以通过更改-mtune
和-march
选项来操纵gcc生成的输出.
或者是否有任何gcc -mtune或其他选项可以鼓励gcc更好地调整现代Intel CPU?
是的,你可以让gcc生成BMI2代码:
例如:X86-64 GCC6.2 -O3 -march=znver1 //AMD Zen
生成:( Haswell时间).
code critical path latency reciprocal throughput
---------------------------------------------------------------
mov eax, 32 * 0.25
sub eax, edx 1 0.25
shlx eax, esi, eax 1 0.5
shrx esi, edi, edx * 0.5
or eax, esi 1 0.25
ret
TOTAL: 3 1.75
Run Code Online (Sandbox Code Playgroud)
与clang 3.8.1相比:
mov cl, dl 1 0.25
shrd edi, esi, cl 4 2
mov eax, edi * 0.25
ret
TOTAL 5 2.25
Run Code Online (Sandbox Code Playgroud)
鉴于依赖链在这里:SHRD
Haswell的速度较慢,与Sandybridge相关,在Skylake上较慢.序列
的倒数吞吐量更快shrx
.
所以这取决于,在后BMI处理器gcc产生更好的代码,前BMI clang胜利.
SHRD
在不同的处理器上有不同的时序,我可以看出为什么gcc并不过分喜欢它.
即使使用-Os
(优化大小)gcc仍然没有选择SHRD
.
*)不是时序的一部分,因为要么不在关键路径上,要么变成零延迟寄存器重命名.
归档时间: |
|
查看次数: |
546 次 |
最近记录: |