Сколько существует уровней оптимизации GCC ?
Я пробовал gcc -O1, gcc -O2, gcc -O3 и gcc -O4
Если я использую очень большое число, это не сработает.
Однако я пробовал
gcc -O100
и он скомпилирован.
Сколько существует уровней оптимизации?
Сколько существует уровней оптимизации GCC ?
Я пробовал gcc -O1, gcc -O2, gcc -O3 и gcc -O4
Если я использую очень большое число, это не сработает.
Однако я пробовал
gcc -O100
и он скомпилирован.
Сколько существует уровней оптимизации?
3
то же самое 3
(при условии, что оно не int
переполняется). Смотрите мой ответ .
-fomit-stack-pointer
изменит сгенерированный код.
Ответы:
Чтобы быть педантичным, есть 8 различных допустимых опций -O, которые вы можете передать gcc, хотя есть некоторые, которые означают то же самое.
В исходной версии этого ответа говорилось, что существует 7 вариантов. GCC с тех пор добавил, -Og
чтобы довести общее количество до 8
-O
(То же, что -O1
)-O0
(без оптимизации, по умолчанию, если не указан уровень оптимизации)-O1
(оптимизировать минимально)-O2
(оптимизировать больше)-O3
(оптимизировать еще больше)-Ofast
(очень агрессивно оптимизируйте, чтобы нарушить соответствие стандартам)-Og
(Оптимизация процесса отладки. -Og обеспечивает оптимизацию, которая не мешает отладке. Это должен быть выбранный уровень оптимизации для стандартного цикла редактирования-компиляции-отладки, предлагающий разумный уровень оптимизации при сохранении быстрой компиляции и хорошего опыта отладки. )-Os
(. Оптимизировать для размера -Os
позволяет использовать все -O2
оптимизации , которые обычно не увеличивают размер кода Он также выполняет дополнительные оптимизации , предназначенные для уменьшения размера кода..
-Os
Отключает следующие параметры оптимизации: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version
)Также могут быть оптимизации для конкретной платформы, как отмечает @pauldoo, OS X имеет -Oz
-Oz
параметр, который «оптимизирует размер более агрессивно, чем -Os
»: developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
-Og
есть все параметры оптимизации, которые не мешают отладке
Давайте интерпретируем исходный код GCC 5.1
Постараемся разобраться, что происходит дальше -O100
, поскольку на странице руководства это неясно.
Сделаем вывод, что:
-O3
, INT_MAX
то же самое -O3
, но это может легко измениться в будущем, поэтому не полагайтесь на это.INT_MAX
.-O-1
Сосредоточьтесь на подпрограммах
Во- первых помните , что НКУ просто передний конец для cpp
, as
, cc1
, collect2
. Быстрый ./XXX --help
говорит, что только collect2
и cc1
бери -O
, поэтому давайте сосредоточимся на них.
И:
gcc -v -O100 main.c |& grep 100
дает:
COLLECT_GCC_OPTIONS='-O100' '-v' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/cc1 [[noise]] hello_world.c -O100 -o /tmp/ccetECB5.
поэтому -O
был перенаправлен на оба cc1
и collect2
.
O в общем. Опт
common.opt - это формат описания опций интерфейса командной строки для GCC, описанный во внутренней документации и переведенный на C с помощью opth-gen.awk и optc-gen.awk .
Он содержит следующие интересные строки:
O
Common JoinedOrMissing Optimization
-O<number> Set optimization level to <number>
Os
Common Optimization
Optimize for space rather than speed
Ofast
Common Optimization
Optimize for speed disregarding exact standards compliance
Og
Common Optimization
Optimize for debugging experience rather than speed or size
в которых указаны все O
параметры. Обратите внимание, как -O<n>
находится в отдельной от другой семье Os
, Ofast
и Og
.
При сборке создается options.h
файл, содержащий:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
В качестве бонуса, пока мы ищем \bO\n
внутри, common.opt
мы замечаем строки:
-optimize
Common Alias(O)
который учит нас тому, что --optimize
(двойное тире, потому что оно начинается с тире -optimize
в .opt
файле) является недокументированным псевдонимом, для -O
которого можно использовать --optimize=3
!
Где используется OPT_O
Теперь мы grep:
git grep -E '\bOPT_O\b'
что указывает нам на два файла:
Давайте сначала отследим opts.c
opts.c: default_options_optimization
Все opts.c
обычаи случаются внутри: default_options_optimization
.
Мы используем команду grep backtrack, чтобы увидеть, кто вызывает эту функцию, и видим, что единственный путь кода:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
и main.c
является точкой входа cc1
. Хорошо!
Первая часть этой функции:
integral_argument
который звонитatoi
строку, соответствующую OPT_O
для анализа входного аргументаopts->x_optimize
где opts
- struct gcc_opts
.struct gcc_opts
После тщетного поиска мы замечаем, что это struct
также генерируется по адресу options.h
:
struct gcc_options {
int x_optimize;
[...]
}
откуда x_optimize
взято строки:
Variable
int optimize
присутствует в common.opt
, и это options.c
:
struct gcc_options global_options;
поэтому мы предполагаем, что это то, что содержит все глобальное состояние конфигурации и int x_optimize
является значением оптимизации.
255 - это внутренний максимум
in opts.c:integral_argument
, atoi
применяется к входному аргументу, так INT_MAX
же как и верхняя граница. И если вы поставите что-то большее, кажется, что GCC выполняет неопределенное поведение C. Ой?
integral_argument
также тонко обертывает atoi
и отклоняет аргумент, если какой-либо символ не является цифрой. Так что отрицательные значения изящно терпят неудачу.
Вернувшись opts.c:default_options_optimization
, мы видим строку:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
так что уровень оптимизации усечен до 255
. Читая, opth-gen.awk
я наткнулся на:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
и на сгенерированных options.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
что объясняет, почему усечение: параметры также должны быть перенаправлены на cl_optimization
, который использует char
для экономии места. Так что 255 на самом деле является внутренним максимумом.
opts.c: возможно_default_options
Вернемся к тому opts.c:default_options_optimization
, maybe_default_options
что звучит интересно. Входим в него, а потом maybe_default_option
доходим до большого переключателя:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
Проверок нет >= 4
, что говорит о том, что3
это максимально возможное количество.
Затем ищем определение OPT_LEVELS_3_PLUS
in common-target.h
:
enum opt_levels
{
OPT_LEVELS_NONE, /* No levels (mark end of array). */
OPT_LEVELS_ALL, /* All levels (used by targets to disable options
enabled in target-independent code). */
OPT_LEVELS_0_ONLY, /* -O0 only. */
OPT_LEVELS_1_PLUS, /* -O1 and above, including -Os and -Og. */
OPT_LEVELS_1_PLUS_SPEED_ONLY, /* -O1 and above, but not -Os or -Og. */
OPT_LEVELS_1_PLUS_NOT_DEBUG, /* -O1 and above, but not -Og. */
OPT_LEVELS_2_PLUS, /* -O2 and above, including -Os. */
OPT_LEVELS_2_PLUS_SPEED_ONLY, /* -O2 and above, but not -Os or -Og. */
OPT_LEVELS_3_PLUS, /* -O3 and above. */
OPT_LEVELS_3_PLUS_AND_SIZE, /* -O3 and above and -Os. */
OPT_LEVELS_SIZE, /* -Os only. */
OPT_LEVELS_FAST /* -Ofast only. */
};
Ха! Это сильный показатель того, что уровней всего 3.
opts.c: default_options_table
opt_levels
настолько интересно, что мы grep OPT_LEVELS_3_PLUS
и встречаем opts.c:default_options_table
:
static const struct default_options default_options_table[] = {
/* -O1 optimizations. */
{ OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },
[...]
/* -O3 optimizations. */
{ OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
[...]
}
так -On
что здесь кодируется конкретное отображение оптимизации, упомянутое в документации. Ницца!
Убедитесь, что x_optimize больше не используется
Основное использование x_optimize
заключалось в установке других конкретных параметров оптимизации, таких как-fdefer_pop
как описано на странице руководства. Есть еще?
Мы grep
, и найдем еще несколько. Число невелико, и при проверке вручную мы видим, что при каждом использовании происходит не более a x_optimize >= 3
, поэтому наш вывод остается верным.
lto-wrapper.c
Теперь перейдем ко второму вхождению OPT_O
, которое было вlto-wrapper.c
.
LTO означает оптимизацию времени связи, для которой, как следует из названия, потребуется -O
опция, и она будет связана сcollec2
(который в основном является компоновщиком).
Фактически, первая строка lto-wrapper.c
говорит:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
В этом файле OPT_O
вхождения, кажется, только нормализуют значение, O
чтобы передать его вперед, так что все должно быть в порядке.
Семь различных уровней:
-O0
(по умолчанию): без оптимизации.
-O
или -O1
(то же самое): оптимизируйте, но не тратьте слишком много времени.
-O2
: Более агрессивная оптимизация
-O3
: Оптимизировать наиболее агрессивно
-Ofast
: Эквивалентно -O3 -ffast-math
. -ffast-math
запускает оптимизацию с плавающей запятой, не соответствующую стандартам. Это позволяет компилятору делать вид, что числа с плавающей запятой бесконечно точны, и что их алгебра следует стандартным правилам алгебры действительных чисел. Он также сообщает компилятору, чтобы оборудование сбрасывало денормальные значения до нуля и обрабатывало денормальные значения как ноль, по крайней мере, на некоторых процессорах, включая x86 и x86-64. Денормальные значения запускают медленный путь для многих FPU, поэтому рассмотрение их как нуля (которое не запускает медленный путь) может быть большим выигрышем в производительности.
-Os
: Оптимизировать под размер кода. В некоторых случаях это действительно может улучшить скорость из-за лучшего поведения I-кеша.
-Og
: Оптимизировать, но не мешать отладке. Это обеспечивает отличную производительность отладочных сборок и предназначено для замены -O0
отладочных сборок.
Есть также другие параметры, которые не активируются ни одним из них, и их нужно включать отдельно. Также можно использовать параметр оптимизации, но отключить определенные флаги, включенные этой оптимизацией.
Для получения дополнительной информации см. Веб-сайт GCC.
-O100
тогда компилируется?
Четыре (0-3): см. Руководство GCC 4.4.2 . Все, что выше, просто -O3, но в какой-то момент вы превысите ограничение на размер переменной.
atoi
неопределенное поведение, за которым следует 255
внутреннее ограничение.
man gcc
Cygwin (12000 нечетных строк) вы можете искать-O
и находить все, что указано в ответах ниже, а также некоторые.