2016-01-08 5 views
0

Почему Visual Studio C++ компилятор не оптимизирует по умолчанию следующий фрагмент кода?C++ встроенные оптимизации сборки

#include "ctime" 
#include "iostream" 

#define BIG_NUM 10000000000 

int main() { 

    std::clock_t begin = clock(); 

    for (unsigned long long i = 0; i < BIG_NUM; ++i) { 
     __asm 
     { 
      nop 
     } 
    } 

    std::clock_t end = clock(); 
    std::cout << "time: " << double(end - begin)/CLOCKS_PER_SEC; 

    std::cin.get(); 
} 

Без _asm блока, времени работы всегда равен 0, так как цикл «пропускается» полностью из-за оптимизации компилятора. С блоком _asm требуется несколько секунд.

Есть ли какой-либо флаг компилятора для оптимизации встроенной сборки или для некоторых неясных причин это невозможно?

+0

Это не скрытые, блоки asm обрабатываются как в основном черные ящики. – harold

+0

c компиляторам не пытаются понять, что находится внутри блоков asm, они просто помещают их в правильное положение внутри своего собственного кода сборки, а затем перенаправляют все на ассемблер –

+0

Когда вы добавляете блок '__asm', он предполагает, что вы знаете что вы делаете (что может быть не так) и не знает, что вы можете сделать внутри него, что мешает ему делать оптимизации. В противном случае вы получите очень непредсказуемый код. Для компилируемого кода нет ничего необычного в том, что он имеет очень неочевидную структуру/код, чтобы использовать преимущества конвейеров и других оптимизаций процессора. Ваша встроенная сборка бросает в нее ключ. –

ответ

5

Компилятор действительно не понимает встроенную сборку и, следовательно, предполагает, что он может что-либо сделать.

Обычно встроенная сборка используется, когда вы специально хотите оптимизировать код на низком уровне. И если вы это делаете, почему вы ожидаете, что компилятор сможет его оптимизировать?

0

Добавление больше информации к принятому ответу

1) Есть некоторые компиляторы, которые могут оптимизировать по инлайн ASM - Xbox 360 компилятор может, но они, вероятно, скорее исключение, чем правило.

2) Есть некоторые инструменты, которые выполняют оптимизацию на скомпилированном двоичном файле e.g. here - они, вероятно, смогут оптимизировать встроенный asm.

3) Наконец, и, возможно, наиболее подходящим образом, одной из самых распространенных причин добавления встроенного asm является ручная математика с тяжелыми векторизованными программами SIMD, которые слишком сложны для компилятора, чтобы сделать это самостоятельно. Если вы хотите этого, то лучше всего использовать intrinsics. Intrinsics дают вам лучшее из обоих миров - вы можете вручную перевернуть свои сложные процедуры, а THEN позволить компилятору обрабатывать распределение регистров, разворот, чередование, обрезку мертвого кода и т. Д. Для вас.

Для хорошего примера см. Примеры ниже - если определено значение «INLINE_ASM», оно принимает ~ 300 мс, иначе оно оптимизировано ни к чему и принимает 0 мс, даже если они делают аналогичную вещь.

#include <windows.h> 
#include <iostream> 

int main() 
{ 
    auto tc = ::GetTickCount(); 

    for(int i=0; i<1024 * 1024 * 1024; ++i) 
    { 
#if INLINE_ASM 
     _asm 
     { 
      paddw xmm0, xmm0; 
     } 
#else 
     _mm_add_epi16(__m128i(), __m128i()); 
#endif 
    } 

    std::cout << "Took " << ::GetTickCount()-tc << " milli-seconds!" << std::endl; 
} 
Смежные вопросы