Насколько хорошо оптимизирует компилятор Visual C ++ 2008/2010? - PullRequest
3 голосов
/ 15 июля 2010

Мне просто интересно, насколько хорошо компилятор MSVC ++ может оптимизировать код (с примерами кода) или что он не может оптимизировать и почему.

Например, я использовал SSE-intrinsics с чем-то вроде этого (var isзначение __m128) (это было для теста с отбраковкой):

if( var.m128_f32[0] > 0.0f && var.m128_f32[1] > 0.0f && var.m128_f32[2] > 0.0f && var.m128_f32[3] > 0.0f ) {
    ...
}

Когда я взглянул на вывод asm, то увидел, что он компилируется в уродливую, очень нервную версию (и я знаю,что процессор просто ненавидит крутые прыжки), и я также знаю, что могу оптимизировать его с помощью инструкции PTEST SSE4.1, но почему компилятор не сделал этого (даже если авторы компилятора определили внутреннюю часть PTEST, чтобы они знали инструкцию)?

Какая оптимизация не может сделать это (до сих пор).

Означает ли это, что я с современной технологией вынужден использовать встроенные функции и встроенные функции ASM и связанные функции ASM и будет когда-либо компилятором?найти такие вещи (я так не думаю)?

Где я могу прочитать больше о том, насколько хорошо оптимизирует компилятор MSVC ++?

(Edit 1): Я использовалSSE2 sведьма и FP: быстрое переключение

Ответы [ 5 ]

4 голосов
/ 15 июля 2010

По умолчанию для компилятора установлено, что он должен генерировать код, который будет запускаться на ЦП с «наименьшим общим знаменателем», т. Е. Код без инструкций SSE 4.1.options.

Тем не менее, компилятор MS традиционно «не самый лучший», когда дело доходит до оптимизации SSE .Я даже не уверен, поддерживает ли он SSE 4 вообще.Эта ссылка дает хорошую оценку GCC для оптимизации SSE:

В качестве дополнительного замечания о почти совершенстве GCC в генерации кода - я был очень удивлен, увидев, что он превосходит даже собственный компилятор Intel

Возможно, вам нужно изменить компилятор!

2 голосов
/ 15 июля 2010

Возможно, вы захотите попробовать компилятор Intel ICC - по моему опыту, он генерирует намного лучший код, чем Visual C ++, особенно для кода SSE.Вы можете получить бесплатную 30-дневную пробную лицензию на сайте intel.com.

1 голос
/ 15 июля 2010

Вы можете активировать asm-представление скомпилированного кода и посмотреть, что сгенерировано.

0 голосов
/ 14 апреля 2011

Ïf-операторы генерируют условные переходы, если вы не можете использовать условные переходы, но, скорее всего, это будет сделано в рукописной сборке.Существуют правила, которые управляют предположениями условного перехода ЦП (прогнозирование ветвления), так что штраф за условный переход, который ведет себя по правилам, является приемлемым.Тогда есть неупорядоченное выполнение, чтобы дополнительно усложнить вещи :).Суть в том, что если ваш код прост, скачки, которые в конечном итоге происходят, не повлияют на производительность.Вы можете проверить страницы оптимизации Agner Fog .

Неотладочная компиляция вашего C-кода, в частности, должна генерировать четыре условных перехода.Использование логических ands (&&) и круглых скобок приведет к тестированию слева направо, поэтому одной из оптимизаций C может быть проверка f32, который, скорее всего, сначала будет> 0.0f (если такая вероятность может быть определена).У вас есть пять возможных вариантов выполнения: test1 истинная ветвь взята (t1tbt), test1 ложная без ветвления (t1fnb) test2 истинная ветвь взята (t2tbt) и т. Д., Предоставляя следующие возможные последовательности

t1tbt                      ; var.m128_f32[0] <= 0.0f
t1fnb t2tbt                ; var.m128_f32[0] >  0.0f, var.m128_f32[1] <= 0.0f
t1fnb t2fnb t3tbt          ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f,
                           ; var.m128_f32[2] <= 0.0f
t1fnb t2fnb t3fnb t4tbt    ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f,
                           ; var.m128_f32[2] >  0.0f, var.m128_f32[3] <= 0.0f
t1fnb t2fnb t3fnb t4fnb    ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f
                           ; var.m128_f32[2] >  0.0f, var.m128_f32[3] >  0.0f

Только взятая ветвь будетприведет к сбою конвейерной обработки, а предсказание ветвлений сведет к минимуму разрушение в максимально возможной степени.

Предполагая, что поплавки дороги в тестировании (если они есть), если var - объединение, и вы хорошо разбираетесь в элементах с плавающей точкойи выходы вы могли бы рассмотреть возможность целочисленного тестирования на перекрывающихся типах.Например, сохраненное значение 1.0f занимает четыре байта, сохраненные как 0x00, 0x00, 0x80, 0x3f (x86 / little-endian).Чтение этого значения как длинного целого даст 0x3f800000 или +1065353216.0.0f - это 0x00, 0x00, 0x00, 0x00 или 0x00000000 (long).Отрицательные значения с плавающей запятой имеют тот же формат, что и положительные, за исключением того, что установлен старший бит (0x80000000).

0 голосов
/ 15 июля 2010

Проверьте презентацию на http://lambda -the-ultimate.org / node / 3674

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

...