2016-12-23 4 views
-2

Большинство компиляторов не оптимизируют встроенный код сборки (VS2015, gcc), это позволяет нам писать новые инструкции, которые он не поддерживает.Когда компиляторы оптимизируют код сборки в источнике C/C++?

Но когда компилятор C/C++ реализует встроенную сборку?

+0

Это может быть сделано при запросе глобальной оптимизации. Оба g ++ и MSVC поддерживают глобальную оптимизацию. –

+4

Надеюсь, что никогда! Если вы заботитесь о том, чтобы сделать встроенную сборку, вы, вероятно, не хотите, чтобы она была запутана. Как компилятор знает, что кажущаяся бесполезная запись в 0xbeefface не важна для какого-либо встроенного устройства? – John3136

+3

Когда вы используете встроенную сборку, вы в основном говорите компилятору, что знаете, что делаете, и это будет лучше, чем то, что он может сделать. Зачем компилятор пытается его оптимизировать? Если вы хотите, чтобы компилятор оптимизировал ваш код, вы должны писать на реальном языке, для которого предназначен компилятор, IMO. –

ответ

6

В целом, компиляторы не будут оптимизировать содержимое вашей встроенной сборки. То есть они не будут удалять или изменять инструкции в вашем блоке сборки. В частности, gcc просто проходит через корпус вашей встроенной сборки без изменений к базовому ассемблеру (gas в этом случае).

Однако хорошие компиляторы могут оптимизировать вокруг вашей встроенной сборки, а в некоторых случаях могут даже полностью опустить исполняемый код сборки! Например, Gcc может это сделать, если он определяет, что объявленные выходы сборки мертвы. Он также может вытащить блок сборки из цикла или объединить несколько вызовов в один. Поэтому он никогда не сталкивается с инструкциями внутри блока, но вполне разумно изменить количество раз, когда блок будет выполнен. Конечно, это поведение также можно отключить, если у блока есть другой важный побочный эффект.

В документах gcc на расширенном синтаксисе asm есть некоторые good examples всего этого.

6

Никогда. Это нарушит цель встроенной сборки, которая должна получить именно то, о чем вы просите.

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

например. вместо inline asm для popcnt, используйте int count = __builtin_popcount(x); (в GNU C, составленном с -mpopcnt). Inline-asm также специфичен для компилятора, поэтому, если что-либо внутреннее устройство более переносимо, особенно если вы используете встроенные функции Intel x86, которые поддерживаются всеми основными компиляторами, которые могут ориентироваться на x86. Используйте #include <x86intrin.h>, и вы можете использовать int _popcnt32 (int a), чтобы надежно получить инструкцию popcnt x86. См. , а также другие ссылки в теге .


int count(){ 
    int total = 0; 
    for(int i=0 ; i<4 ; ++i) 
    total += popc(i); 
    return total; 
} 

Собран с #define popc _popcnt32 по gcc6.3:

mov  eax, 4 
    ret 

clang 3.9 with an inline-asm definition of popc, on the Godbolt compiler explorer:

xor  eax, eax 
    popcnt eax, eax 
    mov  ecx, 1 
    popcnt ecx, ecx 
    add  ecx, eax 
    mov  edx, 2 
    popcnt edx, edx 
    add  edx, ecx 
    mov  eax, 3 
    popcnt eax, eax 
    add  eax, edx 
    ret 

Это классический пример встроенного ассемблере побеждая постоянная распространение, и почему вы не должны Не используйте его для повышения производительности, если его можно избежать: https://gcc.gnu.org/wiki/DontUseInlineAsm.


Это определение рядный ASM я использовал для этого теста:

int popc_asm(int x) { 
    // force use of the same register because popcnt has a false dependency on its output, on Intel hardware 
    // this is just a toy example, though, and also demonstrates how non-optimal constraints can lead to worse code 
    asm("popcnt %0,%0" : "+r"(x)); 
    return x; 
} 

Если вы не знаете, что popcnt has a false dependency on its output register on Intel hardware, это еще одна причина, вы должны оставить его в компилятор, когда это возможно.


Используя специальные инструкции, которые компилятор не знает о том, один вариант использования для встроенного ассемблере, но если компилятор не знает об этом, конечно же, не может оптимизировать его. Прежде чем компиляторы были хороши в оптимизации встроенных функций (например, для SIMD-инструкций), inline asm для такого рода вещей был более распространенным. Но мы уже много лет отстаем от этого, и компиляторы в целом хороши с внутренними особенностями даже для архитектур без архитектуры x86, таких как ARM.

+0

Я действительно слышал о такой вещи, как «оптимизирующий ассемблер», хотя я ничего не знаю о x86 (Google появился [this] (https://github.com/hundt98847/mao), но он появляется быть мертвым). Большинство из них либо для встроенных систем, либо для архитектур типа RISC, где программирование в сборке чрезвычайно утомительно из-за всех регистров и нюансов планирования команд. Таким образом, теоретически, интеграция такой вещи в встроенную сборку компилятора C была бы возможна. Я не согласен с тем, что это победит цель, если inline asm, предположив, что это действительно сработало хорошо! –

+0

Например, запись в сборке для Itanium - это огромная боль сзади, потому что вы должны обратить внимание на [комплекты команд и слоты] (https://blogs.msdn.microsoft.com/oldnewthing/20150728-00/?p = 90811) и множество странных правил. ISA была в значительной степени разработана для компилятора C/C++ и настолько сложна, что оптимизатору практически необходимо иметь любую надежду на получение полупорядочного объектного кода. Оптимизирующий ассемблер был бы довольно прохладным. Хотя я предполагаю, что синтаксис asm затруднит реализацию. Как он узнает, какие инструкции могут быть переупорядочены? –

+0

Зачем вам использовать * inline * -asm в первую очередь (вместо intrinsics), если вы хотите, чтобы компилятор перескакивал и выдавал разные инструкции? Единственная причина, по которой я могу думать, это то, что C не может переносить перенос, например. арифметический сдвиг вправо и другие недостатки. Intrinsics - это решение проблемы, которая, как мне кажется, у этого OP действительно есть, и они застревают в проблеме X-Y для оптимизированного компилятором inline-asm. –