Уловка оптимизации GCC, действительно ли она работает?

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

Итак, написание простого фрагмента кода для примера класса Foo и компиляция фрагментов кода с помощью g ++ v4.4 и -O2 дали некоторый вывод ассемблера (используйте -S). Части ассемблера, перечисленные только с частью цикла, показаны ниже. При рассмотрении вывода кажется, что цикл почти идентичен для обоих, с разницей только в одном адресе. Этот адрес является указателем на выходной аргумент для первого примера или на локальную переменную для второго.

Кажется, нет никаких изменений в фактическом эффекте, независимо от того, используется ли локальная переменная или нет.Таким образом, вопрос разбивается на 3 части:

a) GCC не выполняет дополнительную оптимизацию, даже с учетом предложенной подсказки;

b) GCC успешно оптимизирует оба случаев, но не должно быть;

c) GCC успешно оптимизирует в обоих случаях и производит совместимые выходные данные, как определено стандартом C ++?

Вот неоптимизированная функция:

void DoSomething(const Foo& foo1, const Foo* foo2, int numFoo, Foo& barOut)
{
    for (int i=0; i

И соответствующая сборка:

.L3:
    movl    (%esi), %eax
    addl    $1, %ebx
    addl    $4, %esi
    movl    %eax, 8(%esp)
    movl    (%edi), %eax
    movl    %eax, 4(%esp)
    movl    20(%ebp), %eax       ; Note address is that of the output argument
    movl    %eax, (%esp)
    call    _ZN3Foo5mungeES_S_
    cmpl    %ebx, 16(%ebp)
    jg      .L3

Вот переписанная функция:

void DoSomethingFaster(const Foo& foo1, const Foo* foo2, int numFoo, Foo& barOut)
{
    Foo barTemp = barOut;
    for (int i=0; i

А вот вывод компилятора для функции, использующей локальную переменную:

.L3:
    movl    (%esi), %eax          ; Load foo2[i] pointer into EAX
    addl    $1, %ebx              ; increment i
    addl    $4, %esi              ; increment foo2[i] (32-bit system, 8 on 64-bit systems)
    movl    %eax, 8(%esp)         ; PUSH foo2[i] onto stack (careful! from EAX, not ESI)
    movl    (%edi), %eax          ; Load foo1 pointer into EAX
    movl    %eax, 4(%esp)         ; PUSH foo1
    leal    -28(%ebp), %eax       ; Load barTemp pointer into EAX
    movl    %eax, (%esp)          ; PUSH the this pointer for barTemp
    call    _ZN3Foo5mungeES_S_    ; munge()!
    cmpl    %ebx, 16(%ebp)        ; i < numFoo
    jg      .L3                   ; recall incrementing i by one coming into the loop
                                  ; so test if greater

8
задан Community 23 May 2017 в 11:57
поделиться