Почему gcc использует jmp для вызова функции в оптимизированной версии - PullRequest
5 голосов
/ 02 ноября 2011

Когда я дизассемблировал свою программу, я увидел, что gcc использует jmp для второго вызова pthread_wait_barrier при компиляции с -O3. Почему это так?

Какое преимущество он получает, используя jmp вместо call . Какие трюки здесь играет компилятор? Я предполагаю, что здесь выполняется оптимизация хвостового вызова.

Кстати, здесь я использую статическое связывание.

__attribute__ ((noinline)) void my_pthread_barrier_wait( 
    volatile int tid, pthread_barrier_t *pbar ) 
{
    pthread_barrier_wait( pbar );
    if ( tid == 0 )
    {
        if ( !rollbacked )
        {
            take_checkpoint_or_rollback( ++iter == 4 );
        }
    }
    //getcontext( &context[tid] );
    SETJMP( tid );
    asm("addr2jmp:"); 
    pthread_barrier_wait( pbar );
    // My suspicion was right, gcc was performing tail call optimization, 
    // which was messing up with my SETJMP/LONGJMP implementation, so here I
    // put a dummy function to avoid that.
    dummy_var = dummy_func();
}

Ответы [ 5 ]

12 голосов
/ 02 ноября 2011

Поскольку вы не показываете пример, я могу только догадываться: вызываемая функция имеет тот же тип возврата, что и вызывающая, и это работает как

return func2(...)

или вообще не имеет типа возврата (void).

В этом случае «мы» оставляем «наш» адрес возврата в стеке, оставляя его «им», чтобы использовать его для возврата «нашему» абоненту.

6 голосов
/ 02 ноября 2011

Возможно, это был хвост-рекурсивный вызов. У GCC есть некоторый проход, выполняющий хвостовую рекурсивную оптимизацию.

Но зачем тебе это беспокоить? Если вызываемая функция является extern функцией, то она общедоступна, и GCC должна вызывать ее в соответствии с соглашениями ABI (что означает, что она следует соглашению о вызовах).

Вам не важно, вызвана ли функция jmp.

И это также может быть вызов динамической библиотечной функции (т. Е. С PLT для динамического связывания )

2 голосов
/ 02 ноября 2011

Я предполагаю, что это хвостовой вызов, означающий, что либо текущая функция возвращает результат вызванной функции без изменений, либо (для функции, возвращающей void), возвращается сразу после вызова функции.В любом случае нет необходимости использовать call.

. Инструкция call выполняет две функции.Во-первых, он помещает адрес инструкции после вызова в стек как адрес возврата.Затем он переходит к месту назначения вызова.ret извлекает адрес возврата из стека и переходит в это место.

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

2 голосов
/ 02 ноября 2011

jmp имеет меньше накладных расходов, чем call.jmp просто прыгает, call кладет что-то в стек и прыгает

0 голосов
/ 02 ноября 2011

Вы никогда не узнаете, но одной из вероятных причин является «кэш» (среди других причин, таких как уже упоминавшаяся оптимизация хвостового вызова).

Встраивание может сделать код быстрее и замедлить его,потому что чем больше кода, тем меньше его будет в кеше L1 за один раз.

JMP позволяет компилятору повторно использовать один и тот же кусок кода практически без затрат или вообще без затрат.Современные процессоры глубоко конвейерны, и конвейеры проходят через JMP без проблем (здесь нет возможности неправильного предсказания!).В среднем, это будет стоить всего 1-2 цикла, в лучшем случае ноль циклов, потому что ЦПУ все равно придется ждать предыдущей инструкции для выхода на пенсию.Это, очевидно, полностью зависит от соответствующего индивидуального кода.
Компилятор в принципе может сделать это даже с несколькими функциями, имеющими общие части.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...