工会比现代编译器的转变更有效吗?

Ada*_*vis 6 c performance shift compiler-optimization unions

考虑一下简单的代码:

UINT64 result;
UINT32 high, low;
...
result = ((UINT64)high << 32) | (UINT64)low;
Run Code Online (Sandbox Code Playgroud)

现代编译器会将其转换为真正的高位移位,还是将其优化为简单的副本到正确的位置?

如果没有,那么使用联合似乎比大多数人似乎使用的转变更有效.但是,让编译器优化它是理想的解决方案.

我想知道当他们需要额外的一点性能时我应该如何建议.

Mat*_*hew 4

我编写了以下(希望有效)测试:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

void func(uint64_t x);

int main(int argc, char **argv)
{
#ifdef UNION
  union {
    uint64_t full;
    struct {
      uint32_t low;
      uint32_t high;
    } p;
  } result;
  #define value result.full
#else
  uint64_t result;
  #define value result
#endif
  uint32_t high, low;

  if (argc < 3) return 0;

  high = atoi(argv[1]);
  low = atoi(argv[2]);

#ifdef UNION
  result.p.high = high;
  result.p.low = low;
#else
  result = ((uint64_t) high << 32) | low;
#endif

  // printf("%08x%08x\n", (uint32_t) (value >> 32), (uint32_t) (value & 0xffffffff));
  func(value);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

运行未优化输出的差异gcc -s

<   mov -4(%rbp), %eax
<   movq    %rax, %rdx
<   salq    $32, %rdx
<   mov -8(%rbp), %eax
<   orq %rdx, %rax
<   movq    %rax, -16(%rbp)
---
>   movl    -4(%rbp), %eax
>   movl    %eax, -12(%rbp)
>   movl    -8(%rbp), %eax
>   movl    %eax, -16(%rbp)
Run Code Online (Sandbox Code Playgroud)

我不懂汇编,所以我很难分析它。然而,看起来非联合(顶部)版本上正在发生一些变化。

-O2启用优化后,输出是相同的。因此生成了相同的代码,两种方式将具有相同的性能。

(Linux/AMD64 上的 gcc 版本 4.5.2)

带或不带联合的优化代码的部分输出-O2

    movq    8(%rsi), %rdi
    movl    $10, %edx
    xorl    %esi, %esi
    call    strtol

    movq    16(%rbx), %rdi
    movq    %rax, %rbp
    movl    $10, %edx
    xorl    %esi, %esi
    call    strtol

    movq    %rbp, %rdi
    mov     %eax, %eax
    salq    $32, %rdi
    orq     %rax, %rdi
    call    func
Run Code Online (Sandbox Code Playgroud)

该代码段在该行生成的跳转之后立即开始if

  • @尼尔,正确。为了讨论起见,我们假设联合更快。我的观点很简单,如果您使用期望更快结果的联合,那并不重要,因为编译器已将其“优化”为与移位相同的东西。 (4认同)