给定:
#include <string.h>
bool test_data(void *data)
{
return memcmp(data, "abcd", 4) == 0;
}
编译器可以将其优化为:
test_data:
cmpl $1684234849, (%rdi)
sete %al
ret
这很好。但是如果我使用自己的
memcmp()
(而不是来自<string.h>
),编译器无法将其优化为单个cmpl
指令。相反,它会这样做:static int memcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char *p1 = s1, *p2 = s2;
size_t i;
for (i = 0; i < n; i++) {
int ret = p1[i] - p2[i];
if (ret)
return ret;
}
return 0;
}
bool test_data(void *data)
{
return memcmp(data, "abcd", 4) == 0;
}
test_data:
cmpb $97, (%rdi)
jne .L5
cmpb $98, 1(%rdi)
jne .L5
cmpb $99, 2(%rdi)
jne .L5
cmpb $100, 3(%rdi)
sete %al
ret
.L5:
xorl %eax, %eax
ret
链接: https://godbolt.org/z/Kfhchr45a
- 编译器为什么无法进一步优化它?
- 我做了什么阻碍了优化吗?
int main() { return test_data("abcd"); }
。它将主函数优化为movl $1, %eax
。 - David Wohlferdcmp
相比,这非常糟糕。 - Peter Cordesmemcmp
和memcpy
等函数提供特殊的内嵌函数。即使不使用内嵌函数,memcmp
通常也会在源代码中以汇编语言编写(例如,在x86架构的glibc源代码中,你会看到memcmp.S
而不是memcmp.c
)。 - Weijun Zhou-fno-builtin
选项,否则GCC会将memcmp
视为__builtin_memcmp
;这就是它如何将其转换为单个cmp
指令而不是call memcmp
。请注意,memcpy
/memcmp
的内联扩展与libc.so
和glibc源代码中手写的汇编实现完全不同。GCC有自己用于扩展"字符串"函数的模式。(至少在-O1
优化级别下)它曾经有时对strlen
使用repne scasb
,但后来停止了,因为对于大型缓冲区来说速度非常慢。 - Peter Cordes