Подтвердить что ты не робот

Условный оператор?

В руководстве GCC (версия 4.8.2) указано следующее:

-ftree-loop-if-convert-stores:
       Попытка также выполнить if-convert условные прыжки, содержащие память        пишет. Это преобразование может быть небезопасным для многопоточных        программ, поскольку он преобразует условную память в        записывается безусловная память. Например,

   for (i = 0; i < N; i++)
      if (cond)
        A[i] = expr;

преобразуется в

   for (i = 0; i < N; i++)
       A[i] = cond ? expr : A[i];

потенциально создавая расы данных.

Интересно, однако, если есть усиление производительности, используя оператор operator? по сравнению с if.

  • В первом фрагменте кода A[i] устанавливается expr только, если условие выполнено. Если это не выполняется, то код внутри оператора пропускается.
  • Во втором, A[i], кажется, записано независимо от условия; условие влияет только на значение, на которое оно установлено.

Используя operator?, мы также делаем чек; однако мы добавляем некоторые накладные расходы в случае, если условие не выполняется. Я что-то пропустил?

4b9b3361

Ответ 1

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

С инструкциями перехода вы не знаете, в каких продвинутых инструкциях для загрузки, поэтому используется предсказание, и ветка загружается в конвейер. Если предсказание было правильным, все хорошо, следующие инструкции уже выполняются на конвейере. Однако после того, как скачок был оценен, если предсказание было неправильным, все последующие инструкции, уже находящиеся в конвейере, бесполезны, поэтому конвейер должен быть освобожден и загружены правильные инструкции. Современные процессоры содержат 16-30 этапов трубы, а неверные предсказания отрасли сильно ухудшают производительность. Условные перемещения обходят это, потому что они не вставляют ветки в поток программы.

Но пишет ли cmove всегда?

Из справки по набору инструкций Intel x86:

Инструкции CMOVcc проверяют состояние одного или нескольких флажков состояния в регистре EFLAGS [..] и выполняют операцию перемещения, если флаги находятся в определенном состоянии (или состоянии). [..] Если условие не выполнено, движение не выполняется, и выполнение продолжается с инструкцией, следующей за инструкцией CMOVcc.

Edit

После дальнейшего изучения руководства gcc я запутался, поскольку, насколько я знаю, компилятор не оптимизирует преобразование кода C в другой код C, но использует внутренние структуры данных, такие как Control Flow Graphs, поэтому я действительно не знаю, что они имеют в виду их пример. Я предполагаю, что они означают эквивалент C нового генерируемого потока. Я уже не уверен, если эта оптимизация связана с генерацией cmoves.

Изменить 2

Так как cmove работает с регистрами, а не с памятью, это

if (cond)
  A[i] = expr

не может генерировать cmove.

Однако это

 A[i] = cond ? expr : A[i];

может.

Предположим, что в bx значение expr.

load A[i] into ax
cmp // cond
cmove ax, bx
store ax into &A[i]

Итак, чтобы использовать cmove, вы должны прочитать значение A [i] и записать его, если cond if false, что не эквивалентно оператору if, но с тернарным оператором.