Как изменить уровень оптимизации одной функции?
Это связано с Определить причину segfault при использовании -O3? В этом вопросе я поймаю segfault в определенной функции при компиляции с помощью -O3
используя определенную версию GCC. В -O3
используются инструкции векторизации (в -O2
они не используются).
Я хочу обернуть одну функцию на более низком уровне оптимизации. Согласно Отключение оптимизации для конкретной функции в GCC 4.2.2, я могу это сделать. Однако, следуя различным ссылкам в вопросе и ответах, я не нахожу ответа на вопрос "как именно это сделать".
Как отметить одну функцию для использования другого уровня оптимизации?
Связанный, я не хочу переместить эту функцию в отдельный файл, а затем предоставить другой рецепт файла makefile для него. Это открывает еще одну возможность червей, например, применять ее к GCC 4.9 только на некоторых платформах.
Ответы
Ответ 1
Это описано в https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
Вы можете изменить уровень, объявив функцию следующим образом:
void some_func() __attribute__ ((optimize(1))) {
....
}
Чтобы настроить для него уровень оптимизации.
Ответ 2
Я знаю, что этот вопрос помечен как GCC, но я просто хотел сделать это мобильно и подумал, что результаты могут кому-то пригодиться, поэтому:
- GCC имеет атрибут функции
optimize(X)
- Clang имеет
optnone
функций optnone
и minsize
(используйте __has_attribute
для проверки поддержки). Так как я верю, что 3.5 также имеет #pragma clang optimize on|off
. - Компилятор Intel C/C++ имеет
#pragma intel optimization_level 0
Optimization_level #pragma intel optimization_level 0
который применяется к следующей функции после прагмы - В MSVC есть
#pragma optimize
, которая применяется к первой функции после прагмы - В IBM XL есть
#pragma option_override(funcname, "opt(level,X)")
. Обратите внимание, что 13.1.6 (по крайней мере) возвращает true для __has_attribute(optnone)
но фактически не поддерживает его. - В ARM есть
#pragma Onum
, который может быть связан с #pragma push/pop
- ODS имеет
#pragma opt X (funcname)
- У Cray есть
#pragma _CRI [no]opt
- У TI есть
#pragma FUNCTION_OPTIONS(func,"…")
(C) и #pragma FUNCTION_OPTIONS("…")
(C++) - В IAR есть
#pragma optimize=...
- Pelles C имеет
#pragma optimize time/size/none
Таким образом, для GCC/ICC/MSVC/clang/IAR/Pelles и TI C++ вы можете определить макрос, который вы только что поместили перед функцией. Если вы хотите поддерживать XL, ODS и TI C, вы можете добавить имя функции в качестве аргумента. ARM потребует другой макрос после функции, чтобы вытолкнуть настройку. Для Cray AFAIK вы не можете восстановить предыдущее значение, только отключить оптимизацию и включить.
Я думаю, что основная причина этого заключается в том, чтобы отключить оптимизацию для глючного компилятора (или компилятора, который выявляет ошибки в вашем коде), поэтому единый переносимый опыт, вероятно, не критичен, но, надеюсь, этот список поможет кому-то найти правильное решение для их компилятор.
Редактировать: Стоит также отметить, что довольно часто отключают оптимизации, потому что код, который работал раньше, больше не работает. Хотя возможно, что в компиляторе есть ошибка, гораздо более вероятно, что ваш код полагается на неопределенное поведение, а более новые, более умные компиляторы могут и будут исключать неопределенный случай. Правильный ответ в подобных ситуациях - не отключать оптимизацию, а исправить код. UBsan на Clang и GCC может помочь здесь; скомпилируйте с -fsanitize=undefined
и много неопределенного поведения начнут выдавать предупреждения во время выполнения. Кроме того, попробуйте скомпилировать все возможные варианты предупреждений; для GCC это означает -Wall -Wextra
, для броска лязга в -Weverything
.
Ответ 3
Вот как это сделать с помощью прагм:
#pragma GCC push_options
#pragma GCC optimize ("-O2")
void xorbuf(byte *buf, const byte *mask, size_t count)
{
...
}
#pragma GCC pop_options
Сделать это переносным, что-то вроде следующего.
#define GCC_OPTIMIZE_AWARE (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) || defined(__clang__)
#if GCC_OPTIMIZE_AWARE
# pragma GCC push_options
# pragma GCC optimize ("-O2")
#endif
Его нужно обернуть, потому что с -Wall
более старая версия GCC не понимает -Wno-unknown-pragma
, и они вызовут шумную компиляцию. Старая версия будет встречена в поле, например, GCC 4.2.1 на OpenBSD.
Но в соответствии с Маркусом Триппельсдорфом на Когда в списке рассылки GCC появилась опция "pragma optimize" ,
Это плохая идея в целом, потому что "оптимизация прагмы GCC" означает только отладочная помощь компилятора. Он не должен использоваться в производстве код.