Оптимизация хвостового вызова c++ vs2010

Рассмотрим следующий код:

int fac_aux( int x, int res ) {
    if( x == 1 ) return res;
    else return fac_aux( x - 1, res * x );
}

int fac( int x ) {
    return fac_aux( x, 1 );
}

int main() {
    int x = fac( 50 );

    std::cout << x;
    return 0;
}

Судя по сгенерированному ассемблерному файлу, все в порядке, хвостовой вызов оптимизирован.

Попробуйте заменить

int x = fac( 50 );

с участием

int x = fac_aux( 50, 1 );

Как ни странно, но оптимизация хвостового вызова исчезла. Насколько я помню, такого странного поведения компилятора в VS2008 не было. Любые идеи, почему это происходит и как убедиться, что оптимизация хвостового вызова выполнена?

; Флаги компиляции функции: /Ogtp

Пробовал флаги оптимизации /O2 и /Ox. Существуют ли какие-либо другие параметры компилятора, которые имеют значение?

Изменить: VS2012 удалось выполнить оптимизацию.


person Voivoid    schedule 08.03.2011    source источник
comment
при изменении кода вы удалили функцию fac?   -  person SirDarius    schedule 08.03.2011
comment
так что функция, которая не оптимизируется, на самом деле никогда не вызывается? или вы говорите о хвостовом вызове в функции кулака?   -  person Euqil    schedule 29.07.2011
comment
@Voivoid: действительно ли функция вызывается в сборке? (Возможно, но решил спросить)   -  person Mooing Duck    schedule 28.09.2011
comment
Просто к вашему сведению, нет причин использовать /Ox переключить оптимизацию на /O2. Полная оптимизация имени для /Ox несколько обманчива (по крайней мере, в современных версиях); на самом деле вы получаете по крайней мере тот же уровень оптимизации, если не больше, с /O2.   -  person Cody Gray    schedule 31.07.2012


Ответы (5)


когда оригинал скомпилирован, сборка на сайте вызова имеет частичное встраивание fac_aux, в частности часть x - 1, которая требуется для хвостовой рекурсии, но использование fac_aux предотвращает частичное встраивание и, следовательно, оптимизацию хвостовой рекурсии:

TestThin.fac_aux 013B1000   CMP ECX,1
013B1003                    JE SHORT TestThin.013B100E
013B1005                    IMUL EAX,ECX
013B1008                    DEC ECX
013B1009                    CMP ECX,1
013B100C                    JNZ SHORT TestThin.013B1005
013B100E                    RETN
013B100F                    INT3
TestThin.main 013B1010      MOV EAX,32
013B1015                    LEA ECX,DWORD PTR DS:[EAX-1] ;notice the partial inlining of x - 1
013B1018                    CALL TestThin.fac_aux
person Necrolis    schedule 31.07.2012

Я пробовал следующий код

#include "stdafx.h"

int f( size_t i, int x )
{
    return ( ( i < 2 ) ? x : f( i - 1, i * x ) );
}

int f( size_t i )
{
    return ( f( i, 1 ) );
}

int _tmain(int argc, _TCHAR* argv[])
{
    {
        f( 0 );
    }

    return 0;
}

и использовал полную оптимизацию /Ox, но я не получил хвостовой рекурсии. Таким образом, кажется, что MS VC++ 2010 не поддерживает хвостовую рекурсию.

person Vlad from Moscow    schedule 31.07.2012

Попробуйте сделать функции явно inline — кроме того, какой уровень оптимизации вы используете?

person Konrad Rudolph    schedule 08.03.2011
comment
к сожалению встроенный не помогает. Пробовал оба флага /O2 и /Ox - person Voivoid; 08.03.2011

Я не знаю, сработает ли это, но попробуйте заменить if...else одним оператором возврата:

return (x == 1) ? res : fac_aux( x - 1, res * x );
person tomac    schedule 08.03.2011

Выглядит странно, вы делаете какую-то инкрементную компиляцию. Кроме того, это может быть тот факт, что компилятор запутался в нескольких параметрах, в рабочей версии фактически только один параметр, так что оптимизация больше не подходит.

Вы можете попробовать сделать параметр res глобальным, я знаю, что это грязная плохая практика, но это может сработать.

Звучит как ошибка/функция компилятора.

/Тони

person SpagnumMoss    schedule 27.09.2011