GCC не использует inc

Компилятор GCC

$ gcc --version
gcc (GCC) 4.8.2
...

не генерирует inc ассемблерную инструкцию, где она может быть полезна, как в этой программе на C:

int main(int argc, char **argv)
{
    int sum = 0;
    int i;
    for(i = 0; i < 1000000000L; i++)                     <---- that "i++"
        sum += i;
    return sum;
}

Вместо этого он генерирует инструкцию add:

0000000000000000 <main>:
   0:   31 d2                   xor    %edx,%edx
   2:   31 c0                   xor    %eax,%eax
   4:   0f 1f 40 00             nopl   0x0(%rax)
   8:   01 d0                   add    %edx,%eax
   a:   83 c2 01                add    $0x1,%edx         <---- HERE
   d:   81 fa 00 ca 9a 3b       cmp    $0x3b9aca00,%edx
  13:   75 f3                   jne    8 <main+0x8>
  15:   f3 c3                   repz retq 

Почему это происходит?

EDIT: я использовал gcc -O2 для компиляции. gcc -Os действительно генерирует инструкцию inc. Разве использование inc не является скорее оптимизацией скорости, чем оптимизацией пространства?


person heinrich5991    schedule 10.11.2013    source источник
comment
Вы пробовали gcc -Os ? Проблема в том, что варианты add, вероятно, быстрее в сообщении +386, а inc все равно будет внутренне переведено на add.   -  person Aki Suihkonen    schedule 10.11.2013
comment
См. этот ответ: stackoverflow.com/questions/5993326/   -  person thebjorn    schedule 10.11.2013
comment
Современные процессоры не выполняют машинный код. У них есть риск-подобный механизм выполнения, который одновременно выполняет несколько микроопераций. Инструкция чтения-изменения-записи, такая как INC, ускоряет суперскалярное выполнение. Старая архитектура, такая как Pentium 4, выполняет ADD за 0,25 такта, INC за 0,5 такта. Более новые делают и то, и другое с частотой 0,33 цикла, так что это не имеет значения. Ознакомьтесь с руководствами по Agner Fog.   -  person Hans Passant    schedule 10.11.2013
comment
Да, но вариант процессора не использовался (march/mtune/mcpu), поэтому, насколько известно GCC, это может иметь значение.   -  person Robin Green    schedule 10.11.2013


Ответы (2)


Попробуйте с -march=<your machine>. Результат может быть другим.

Однако обратите внимание, что add $1, %reg не обязательно плохой выбор. Хотя inc и dec имеют меньшие кодировки, что привлекательно, они страдают тем, что лишь частично обновляют флаги, что приводит к ложным проблемам с зависимостями. Руководство по оптимизации Intel содержит этот комментарий (выделено мной):

Инструкции INC и DEC изменяют только подмножество битов в регистре флагов. Это создает зависимость от всех предыдущих записей регистра флагов. Это особенно проблематично, когда эти инструкции находятся на критическом пути, потому что они используются для изменения адреса нагрузки, от которой зависят многие другие инструкции. Правило 33 кодирования ассемблера/компилятора. (Влияние M, общность H) Инструкции INC и DEC следует заменить инструкциями ADD или SUB, поскольку ADD и SUB перезаписывают все флаги, а INC и DEC — нет, поэтому создание ложных зависимостей от более ранних инструкций, которые устанавливают флаги.

person gsg    schedule 10.11.2013

Это может зависеть от конкретных настроек оптимизации, которые вы используете (или не используете). GCC можно либо оптимизировать по времени, либо по пространству (хотя оптимизация по пространству иногда может быть эффективным способом оптимизации времени выполнения!)

Тот факт, что инструкция доступна для специальной задачи, не означает, что она обязательно является наиболее эффективной для использования.

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

Кроме того, если вы не сообщите GCC, на какой модели процессора x86 вы собираетесь запускать код, ему придется угадывать что-то общее.

person Robin Green    schedule 10.11.2013