考虑一下简单的代码:
UINT64 result;
UINT32 high, low;
...
result = ((UINT64)high << 32) | (UINT64)low;
现代编译器是把它变成一个真正的桶移位,还是把它优化成一个简单的拷贝到正确的位置?
如果不是,那么使用联合似乎比大多数人似乎使用的换班更有效。但是,让编译器对此进行优化是理想的解决方案。
我在想,当人们确实需要额外的性能时,我应该如何建议他们。
发布于 2011-05-26 02:59:50
我写了以下(希望是有效的)测试:
#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;
}
运行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)
我不懂汇编,所以我很难去分析它。然而,在非联盟(顶部)版本上,看起来像预期的那样正在发生一些转变。
但是在启用了优化-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
代码片段紧跟在if
代码行生成的跳转之后开始。
发布于 2011-05-26 02:17:35
现代编译器比你想象的更聪明;-) (所以,是的,我认为你可以期待在任何好的编译器上都会有很大的进步)。
无论如何,我会使用语义更接近您实际想要做的事情的选项。
发布于 2011-05-26 02:20:43
如果这被认为是独立于平台的,那么唯一的选择就是在这里使用移位。
使用union { r64; struct{low;high}}
时,您无法判断低/高场将映射到哪些场。考虑字符顺序。
现代编译器可以很好地处理这样的移位。
https://stackoverflow.com/questions/6128760
复制相似问题