【发布时间】:2020-12-14 13:06:17
【问题描述】:
我有这段代码
#include <cstdlib>
#include <time.h>
int sum () {
srand (time(NULL));
unsigned long extra = rand() % 10;
int sum = 0;
// #pragma nounroll. <<<< This makes no difference
for (int i = 0; i < 16 + extra; ++i) {
sum += i;
}
return sum;
}
并使用-O3,clang 将其优化为以下内容,这让我大吃一惊。 (注意怎么没有分支)
我真的不明白如何证明这种优化的正确性。
具体来说,使用两个看似神奇的数字(顺便说一句,在编译之间不会改变)似乎很神秘。此外,我猜你称这些为“随机”,但不符合rand() 的精神,不是吗?
sum(): # @sum()
push rax
xor edi, edi
call time
mov edi, eax
call srand
call rand
cdqe
imul rcx, rax, 1717986919. # <<<< magic number
mov rdx, rcx
shr rdx, 63
sar rcx, 34
add ecx, edx
add ecx, ecx
lea ecx, [rcx + 4*rcx]
mov edx, eax
sub edx, ecx
neg ecx
add eax, ecx
add eax, 16
lea rcx, [rax - 1]
movabs rsi, 8589934590 # <<< magic number
add rsi, rax
imul rsi, rcx
shr rsi
lea eax, [rsi + rdx]
add eax, 15
pop rcx
ret
为了后代,gcc 产生了以下内容
sum():
sub rsp, 8
xor edi, edi
call time
mov rdi, rax
call srand
call rand
mov esi, 1
movsx rdx, eax
mov ecx, eax
imul rdx, rdx, 1717986919
sar ecx, 31
sar rdx, 34
sub edx, ecx
lea ecx, [rdx+rdx*4]
add ecx, ecx
sub eax, ecx
mov edx, eax
add eax, 16
movsx rcx, eax
cmp edx, -16
cmovne rsi, rcx
cmp eax, 18
jbe .L6
mov rdx, rsi
movdqa xmm1, XMMWORD PTR .LC0[rip]
pxor xmm0, xmm0
xor eax, eax
movdqa xmm3, XMMWORD PTR .LC1[rip]
shr rdx, 2
.L3:
movdqa xmm2, xmm1
add eax, 1
paddd xmm1, xmm3
paddd xmm0, xmm2
cmp eax, edx
jne .L3
movdqa xmm1, xmm0
mov rdi, rsi
psrldq xmm1, 8
and rdi, -4
paddd xmm0, xmm1
movsx rdx, edi
movdqa xmm1, xmm0
psrldq xmm1, 4
paddd xmm0, xmm1
movd eax, xmm0
cmp rsi, rdi
je .L1
.L5:
add eax, edx
add rdx, 1
cmp rcx, rdx
ja .L5
.L1:
add rsp, 8
ret
.L6:
xor edx, edx
xor eax, eax
jmp .L5
.LC0:
.long 0
.long 1
.long 2
.long 3
.LC1:
.long 4
.long 4
.long 4
.long 4
【问题讨论】:
-
有一个问题:示例代码似乎是C++
-
可能用
res = (16+extra-1) * (16+extra-2) / 2替换了循环。 -
@MarcoBonelli 抱歉,我在标签编辑方面有点过分热心。
-
@MarcoBonelli 它不会改变结果。有趣的是,用于 arm 的 gcc 正在生成类似的幻数(它们在十六进制 FWIW 中看起来没有那么神奇)
-
@CuriousLearner 有一个公式可以计算从
0到n的整数之和,即n * (n-1) / 2。 Clang 可能看到循环正是这样做的,所以它用公式替换了它。神奇的数字可能与模计算有关。如果您查看 llvm IR 输出(使用-emit-llvm),则没有神奇的数字。
标签: c++ optimization compiler-optimization llvm-clang