2

鉴于以下情况:

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

4

1 回答 1

2

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

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

那么,为什么没有对此进行特定的优化呢?可能是通常的原因:

“投资回报不足”

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

而且,你当然已经htons/ntohs有了。我就用那些。

负载对齐?

这是一个有趣的,我不得不查一下。如果您的传入指针“x”不是字对齐的,那么bar会在许多架构上崩溃,但foo仍然可以工作。

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

于 2012-05-31T19:22:29.300 回答