来自uint8_t *数组的uint16_t的little-endian加载的gcc / clang优化

时间:2012-05-31 19:07:21

标签: c gcc clang compiler-optimization

鉴于以下内容:

#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位加载)?负载对齐?

1 个答案:

答案 0 :(得分:2)

我不编写编译器,但我可以很好地猜测:

编译器使用的标准优化技术都不会影响foo中的代码。要检测它是否等同于bar,需要进行特定的优化以发现此特定模式,并输出“改进的”代码。

那么,为什么没有具体的优化呢?可能是通常的原因:

  

“投资回报率不足”

换句话说,编写,调试和维护优化所花费的时间 - 以及用于检查此模式的每一行源的额外编译时间 - 将淹没从中获得的任何好处。

当然,你已经htons/ntohs了。我只是用那些。

  

载荷对齐?

这是一个有趣的,我不得不查一查。如果您的传入指针'x'没有字对齐,那么bar会在许多架构上崩溃,而foo仍应有效。

然而,x86架构允许未对齐的加载,因此即使对于未对齐的x值,这两个函数也应该有效。