Если я использую действительно большое количество, это не сработает.
и он скомпилирован.
Ответ 3
Пусть интерпретирует исходный код GCC 5.1, чтобы узнать, что происходит на -O100
, так как на man-странице не ясно.
Сделаем вывод, что:
- что-либо выше
-O3
до INT_MAX
совпадает с -O3
, но это может легко измениться в будущем, поэтому не полагайтесь на него.
- GCC 5.1 запускает поведение undefined, если вы вводите целые числа больше
INT_MAX
.
- аргумент может содержать только цифры, или он изящно терпит неудачу. В частности, это исключает отрицательные целые числа, такие как
-O-1
Фокус на подпрограммах
Прежде всего помните, что GCC является только интерфейсом для 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
common.opt - это формат описания интерфейса CLCC, определенный в внутренняя документация и переведена на 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 */
В качестве бонуса, в то время как мы получаем grepping для \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, чтобы узнать, кто вызывает эту функцию, и мы видим, что единственный путь к коду:
-
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
После grepping напрасно, мы замечаем, что этот 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 - внутренний максимум
в opts.c:integral_argument
, atoi
применяется к входному аргументу, поэтому INT_MAX
является верхней границей. И если вы ставите что-то большее, похоже, что GCC запускает поведение C undefined. Уч?
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: maybe_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
в 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
, чтобы передать его вперед, поэтому мы должны быть в порядке.