[英]Visual C++ Tail Call Optimization
According to answers to that question: Which, if any, C++ compilers do tail-recursion optimization? 根据该问题的答案: 如果有的话,哪些C ++编译器会进行尾递归优化? it seems, that compiler should do tail-recursion optimization.
看起来,编译器应该进行尾递归优化。
But I've tried proposed options and it seems that compiler can't do this optimization in case of template functions. 但我已经尝试过提出的选项,似乎编译器在模板函数的情况下不能进行这种优化。 Could it be fixed somehow?
它能以某种方式修复吗?
I don't use the MS compilers, but GCC can certainly do tail-recursion optimisation for templates. 我不使用MS编译器,但GCC肯定可以对模板进行尾递归优化。 Given this function:
鉴于此功能:
template <typename T>
T f( T t ) {
cout << t << endl;
if ( t == 0 ) {
return t;
}
return f( t - 1 );
}
The code produced is: 生成的代码是:
5 T f( T t ) {
6 cout << t << endl;
- 0x401362 <main+22>: mov %esi,0x4(%esp)
- 0x401366 <main+26>: movl $0x4740c0,(%esp)
- 0x40136d <main+33>: call 0x448620 <_ZNSolsEi>
- 0x401372 <main+38>: mov %eax,%ebx
7 if ( t == 0 ) {
- 0x4013a5 <main+89>: test %esi,%esi
- 0x4013a7 <main+91>: je 0x4013c8 <main+124>
8 return t;
9 }
10 return f( t - 1 );
- 0x4013a9 <main+93>: dec %esi
- 0x4013aa <main+94>: jmp 0x401362 <main+22>
11 }
You can see that the recursive call has been turned into a jump back to the start of the function. 您可以看到递归调用已转变为跳回函数的开头。 This optimisation is only performed by GCC if the code is compiled with optimisations enabled (-O2 in this case) - perhaps the same is true for MS C++?
如果代码是在启用了优化的情况下编译的(在这种情况下为-O2),则此优化仅由GCC执行 - 对于MS C ++,可能也是如此。
I'm guessing here, but it might be possible to do them manually. 我在这里猜测,但有可能手动完成它们。
The first fill template uses recursion to fill a buffer. 第一个填充模板使用递归来填充缓冲区。 The second uses a hand crafted tail recursion to do the same thing.
第二个使用手工制作的尾递归来做同样的事情。
This may be bad for some reason, so I am suggesting it's use with caution. 由于某些原因,这可能是不好的,所以我建议谨慎使用它。
eg. 例如。
#include <stdio.h>
template <class myType>
// fill a buffer with n v's
void fill( myType *p , int n , myType v ){
if ( n <= 0 ) return;
*p = v;
fprintf( stderr , "[%x] = %d\n" , (unsigned) p , *p );
fill( p+1 , n-1 , v );
}
template <class myType>
// fill a buffer with n v's
void fillTail( myType *p , int n , myType v ){
tail:
if ( n <= 0 ) return;
*p = v;
fprintf( stderr , "[%x] = %d\n" , (unsigned) p , *p );
// hand crafted tail call
p++;
n--;
goto tail;
}
int main(){
int buf[100];
int v = 12;
fill( buf , 10 , v );
for ( int i=0; i<10 ; i++ ){
fprintf( stderr , "[%d] = %d\n" , i , buf[i] );
}
v = 13;
fill( buf , 10 , v );
for ( int i=0; i<10 ; i++ ){
fprintf( stderr , "[%d] = %d\n" , i , buf[i] );
}
}
Edit: 编辑:
Good idea to add the assembler. 添加汇编程序的好主意。 I have changed some labels to make it clearer.
我更改了一些标签以使其更清晰。
I simply used g++ file.cpp
to compile and g++ -S file.cpp
to get the assembler. 我只是使用
g++ file.cpp
编译和g++ -S file.cpp
来获取汇编程序。
fill:
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
subl $24, %esp
LCFI2:
cmpl $0, 12(%ebp)
jle L4
movl 8(%ebp), %edx
movl 16(%ebp), %eax
movl %eax, (%edx)
movl 12(%ebp), %edx
decl %edx
movl 8(%ebp), %ecx
addl $4, %ecx
movl 16(%ebp), %eax
movl %eax, 8(%esp)
movl %edx, 4(%esp)
movl %ecx, (%esp)
call fill
L4:
leave
ret
fillTail:
pushl %ebp
LCFI3:
movl %esp, %ebp
LCFI4:
subl $8, %esp
LCFI5:
jmp L6
L10:
movl 8(%ebp), %edx
movl 16(%ebp), %eax
movl %eax, (%edx)
addl $4, 8(%ebp)
leal 12(%ebp), %eax
decl (%eax)
L6:
cmpl $0, 12(%ebp)
jg L10
L9:
leave
ret
The Llvm project is a framework to create compilers which has an extensive set of optimization mechanism (tail call optimization among them). Llvm项目是一个创建编译器的框架,它具有一组广泛的优化机制(其中包括尾部调用优化)。 It provides c and c++ compilers, although c++ is not considered complete.
它提供了c和c ++编译器,尽管c ++不被认为是完整的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.