鉴于以下内容:
#include <stdint.h>
#include <stdio.h>
uint16_t foo(uint8_t* x)
{
uint16_t r = (x[1] << 8) | x[0];
return r;
}
uint16_t bar(uint8_t* x)
{
uint16_t r = ((uint16_t*) x)[0];
return r;
}
在x86_64上,GCC和Clang都产生类似于:
的代码foo: # @foo
.cfi_startproc
# BB#0: # %entry
movzbl (%rdi), %ecx
movzbl 1(%rdi), %eax
shll $8, %eax
orl %ecx, %eax
movzwl %ax, %eax
ret
bar: # @bar
.cfi_startproc
# BB#0: # %entry
movzwl (%rdi), %eax
ret
有没有理由为什么foo没有被优化为等于bar(即,执行单个16位加载)?负载对齐?
答案 0 :(得分:2)
我不编写编译器,但我可以很好地猜测:
编译器使用的标准优化技术都不会影响foo
中的代码。要检测它是否等同于bar
,需要进行特定的优化以发现此特定模式,并输出“改进的”代码。
那么,为什么没有具体的优化呢?可能是通常的原因:
“投资回报率不足”
换句话说,编写,调试和维护优化所花费的时间 - 以及用于检查此模式的每一行源的额外编译时间 - 将淹没从中获得的任何好处。
当然,你已经htons/ntohs
了。我只是用那些。
载荷对齐?
这是一个有趣的,我不得不查一查。如果您的传入指针'x'没有字对齐,那么bar
会在许多架构上崩溃,而foo
仍应有效。
然而,x86架构允许未对齐的加载,因此即使对于未对齐的x值,这两个函数也应该有效。