Geo*_*son 2 c performance x86 assembly gcc
如何哄骗GCC编译器在普通C中发出REPE CMPSB指令,而没有"asm"和"_emit"关键字,调用包含的库和编译器内在函数?
我尝试了一些像下面列出的C代码,但没有成功:
unsigned int repe_cmpsb(unsigned char *esi, unsigned char *edi, unsigned int ecx) {
for (; ((*esi == *edi) && (ecx != 0)); esi++, edi++, ecx--);
return ecx;
}
Run Code Online (Sandbox Code Playgroud)
请参阅GCC如何在此链接上编译它:https:
//godbolt.org/g/obJbpq
PS
我意识到无法保证编译器以某种方式编译C代码,但我还是想哄它以获得乐趣,只是为了看它有多聪明.
rep cmps不快; 例如,Haswell的每个计数吞吐量> = 2个周期,加上启动开销.(http://agner.org/optimize).你可以得到一个常规的一次一个字节循环,每个时钟进行1次比较(现代CPU可以每个时钟运行2次加载),即使你必须检查匹配和0终结器,如果你仔细地写它.
InstLatx64号码同意:Haswell可以管理每个字节1个周期rep cmpsb,但这是总带宽(即比较每个字符串1个字节的2个周期).
只有rep movs与rep stos有"快字符串"支持在当前的x86 CPU.(即,当对齐和缺少重叠时,内部使用更宽的加载/存储的微编码实现.)
现代CPU的"智能"之处在于使用SSE2 pcmpeqb/ pmovmskb.(但是gcc和clang不知道如何使用在循环输入之前未知的迭代计数来向量化循环;即它们不能对搜索循环进行向量化.但ICC可以.)
然而,由于某种原因,内嵌GCC将repz cmpsb用于strcmp对短期固定的字符串.据推测,它不知道任何更聪明的内联模式strcmp,并且启动开销可能仍然比动态库函数的函数调用开销更好.或许不是,我还没有测试过.无论如何,代码块中的代码大小与一堆固定字符串进行比较并不可怕.
#include <string.h>
int string_equal(const char *s) {
return 0 == strcmp(s, "test1");
}
Run Code Online (Sandbox Code Playgroud)
.LC0:
.string "test1"
string_cmp:
mov rsi, rdi
mov ecx, 6
mov edi, OFFSET FLAT:.LC0
repz cmpsb
setne al
movzx eax, al
ret
Run Code Online (Sandbox Code Playgroud)
如果你没有以某种方式对结果进行boolean化,gcc会使用seta/setb/sub/movzx生成-1/0/+1结果.(在IvyBridge之前导致Intel上的部分寄存器停顿,以及对其他CPU的错误依赖,因为它sub在setcc结果上使用32位,/ facepalm.幸运的是,大多数代码只需要strcmp的双向结果,而不是3-way ).
gcc只使用固定长度的字符串常量来执行此操作,否则它将不知道如何设置rcx.
结果完全不同memcmp:gcc做得很好,在这种情况下使用DWORD和WORD cmp,没有rep字符串指令.
int cmp_mem(const char *s) {
return 0 == memcmp(s, "test1", 6);
}
cmp DWORD PTR [rdi], 1953719668 # 0x74736574
je .L8
.L5:
mov eax, 1
xor eax, 1 # missed optimization here after the memcmp pattern; should just xor eax,eax
ret
.L8:
xor eax, eax
cmp WORD PTR [rdi+4], 49 # check last 2 bytes
jne .L5
xor eax, 1
ret
Run Code Online (Sandbox Code Playgroud)
控制此行为
手册说-mstringop-strategy=libcall应该强制库调用,但它不起作用.asm输出没有变化.
也没有-mno-inline-stringops-dynamically -mno-inline-all-stringops.
看来这部分海湾合作委员会文件已经过时了.我没有进一步调查更大的字符串文字,或固定大小但非常量字符串,或类似.