ead*_*ead 6 c++ optimization gcc tail-call-optimization
尝试尾调用优化(tco),我偶然发现了以下奇怪的例子:
unsigned long long int fac1(unsigned long long int n){
if (n==0)
return 1;
return n*fac1(n-1);
}
Run Code Online (Sandbox Code Playgroud)
实际上,我印象深刻,gcc能够在这里执行tco(带-O2标志),因为它不是那么直接:
fac1(unsigned long long):
testq %rdi, %rdi
movl $1, %eax
je .L4
.L3:
imulq %rdi, %rax
subq $1, %rdi
jne .L3
rep ret
.L4:
rep ret
Run Code Online (Sandbox Code Playgroud)
但是,从返回类型更改unsigned long long int为unsigned intgcc后无法执行tlo:
unsigned int fac2(unsigned long long int n){
if (n==0)
return 1;
return n*fac2(n-1);
}
Run Code Online (Sandbox Code Playgroud)
我们可以清楚地看到生成的程序集中的递归调用:
fac2(unsigned long long):
testq %rdi, %rdi
jne .L16
movl $1, %eax
ret
.L16:
pushq %rbx
movq %rdi, %rbx
leaq -1(%rdi), %rdi
call fac2(unsigned long long)
imull %ebx, %eax
popq %rbx
ret
Run Code Online (Sandbox Code Playgroud)
起初,我认为这是一个错过的优化,但现在我不确定,因为clang也无法执行此优化.所以也许我不知道哪种语言可以阻止这种优化.
为什么gcc不对该函数执行尾调用优化,fac2但仅用于fac1?
我很清楚,在第二个版本中,必须降低结果.显然这是唯一的区别.但为什么这是一个问题并阻止tlo?
例如,如果我帮助编译器并将我的函数重写为经典的尾递归(它应该产生与版本相同的结果fac2):
unsigned int tlo_fac(unsigned long long int n, unsigned long long int cur){
if (n==0)
return cur;
return tlo_fac(n-1, n*cur);
}
unsigned int fac(unsigned long long int n){
return tlo_fac(n,1);
}
Run Code Online (Sandbox Code Playgroud)
我得到了一个与之相同fac1的tlo优化版本 (高32位允许包含垃圾,因此imulq可以在内联后使用):
fac(unsigned long long):
testq %rdi, %rdi
movl $1, %eax
je .L10
.L11:
imulq %rdi, %rax
subq $1, %rdi
jne .L11
.L10:
rep ret
Run Code Online (Sandbox Code Playgroud)
在 中fact2(),递归完成后,需要从unsigned long long int到进行强制转换unsigned int
unsigned int fac2(unsigned int n)产生以下组件,
fac2(unsigned int):
testl %edi, %edi
movl $1, %eax
je .L10
.L9:
imull %edi, %eax
subl $1, %edi
jne .L9
rep ret
.L10:
rep ret
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
163 次 |
| 最近记录: |