Vamos interpretar o código-fonte do GCC 5.1 para ver o que acontece, -O100pois não está claro na página do manual.
Devemos concluir que:
- qualquer coisa acima
-O3até INT_MAXé igual -O3, mas isso pode mudar facilmente no futuro, então não confie nisso.
- O GCC 5.1 executa um comportamento indefinido se você inserir números inteiros maiores que
INT_MAX.
- o argumento pode ter apenas dígitos ou falha normalmente. Em particular, isso exclui números inteiros negativos como
-O-1
Foco em subprogramas
Primeiro lembre-se que GCC é apenas um-front-end para cpp, as, cc1, collect2. Um rápido ./XXX --helpdiz isso apenas collect2e cc1pegue -O, então vamos nos concentrar neles.
E:
gcc -v -O100 main.c |& grep 100
dá:
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.
então -Ofoi encaminhado para ambos cc1e collect2.
O em comum.opt
common.opt é um formato de descrição de opção CLI específico do GCC descrito na documentação interna e traduzido para C por opth-gen.awk e optc-gen.awk .
Ele contém as seguintes linhas interessantes:
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
que especificam todas as Oopções. Observe como -O<n>está em uma família separada da outra Os, Ofaste Og.
Quando construímos, isso gera um options.harquivo que contém:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Como um bônus, enquanto procuramos por \bO\ndentro common.opt, notamos as linhas:
-optimize
Common Alias(O)
que nos ensina que --optimize(traço duplo porque começa com um traço -optimizeno .optarquivo) é um apelido não documentado para o -Oqual pode ser usado como --optimize=3!
Onde OPT_O é usado
Agora nós grep:
git grep -E '\bOPT_O\b'
que nos aponta para dois arquivos:
Vamos primeiro rastrear opts.c
opts.c: default_options_optimization
Todos os opts.cusos acontecer dentro: default_options_optimization.
Retrocedemos para ver quem chama esta função e vemos que o único caminho de código é:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
e main.cé o ponto de entrada de cc1. Boa!
A primeira parte desta função:
- faz o
integral_argumentque chama atoia string correspondente a OPT_Opara analisar o argumento de entrada
- armazena o valor dentro de
opts->x_optimizeonde optsé a struct gcc_opts.
struct gcc_opts
Depois de fazer grep em vão, notamos que isso structtambém é gerado em options.h:
struct gcc_options {
int x_optimize;
[...]
}
de onde x_optimizevem as linhas:
Variable
int optimize
presente em common.opt, e que options.c:
struct gcc_options global_options;
então achamos que é isso que contém todo o estado global da configuração, e int x_optimize é o valor de otimização.
255 é um máximo interno
in opts.c:integral_argument, atoié aplicado ao argumento de entrada, assim INT_MAXcomo um limite superior. E se você colocar algo maior, parece que o GCC executa um comportamento C indefinido. Ai?
integral_argumenttambém envolve atoie rejeita o argumento se algum caractere não for um dígito. Portanto, os valores negativos falham normalmente.
Voltar para opts.c:default_options_optimization, vemos a linha:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
para que o nível de otimização seja truncado para 255. Durante a leitura opth-gen.awk, descobri:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
e no gerado options.h:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
o que explica por que o truncamento: as opções também devem ser encaminhadas para cl_optimization, que usa umchar para economizar espaço. Portanto, 255 é um máximo interno, na verdade.
opts.c: Maybe_default_options
Voltar para opts.c:default_options_optimization, encontramos o maybe_default_optionsque parece interessante. Nós entramos nele, e então maybe_default_optionchegamos a uma grande mudança:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
Não há >= 4verificações, o que indica que 3é o maior possível.
Em seguida, procuramos a definição de OPT_LEVELS_3_PLUSem 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. */
};
Ha! Este é um forte indicador de que existem apenas 3 níveis.
opts.c: default_options_table
opt_levelsé tão interessante que vimos OPT_LEVELS_3_PLUSe encontramos 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 },
[...]
}
portanto, é aqui que o -Onmapeamento de otimização específico mencionado na documentação é codificado. Agradável!
Certifique-se de que não haja mais usos para x_optimize
O principal uso de x_optimizeera definir outras opções de otimização específicas, como -fdefer_popdocumentado na página do manual. Existem mais?
Nós grep, e encontraremos mais alguns. O número é pequeno e, após inspeção manual, vemos que todo uso faz apenas no máximo a x_optimize >= 3, portanto, nossa conclusão se mantém.
lto-wrapper.c
Agora vamos para a segunda ocorrência de OPT_O, que foi em lto-wrapper.c.
LTO significa Link Time Optimization, que como o nome sugere vai precisar de uma -Oopção e será vinculado collec2(que é basicamente um linker).
Na verdade, a primeira linha de lto-wrapper.cdiz:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
Neste arquivo, as OPT_Oocorrências parecem apenas normalizar o valor de Opara repassá-lo, então devemos ficar bem.
man gccCygwin (12.000 linhas ímpares), você pode pesquisar-Oe encontrar tudo o que as respostas abaixo afirmam e muito mais.