Vamos interpretar o código-fonte do GCC 5.1 para ver o que acontece, -O100
pois não está claro na página do manual.
Devemos concluir que:
- qualquer coisa acima
-O3
até 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 --help
diz isso apenas collect2
e cc1
pegue -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 -O
foi encaminhado para ambos cc1
e 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 O
opções. Observe como -O<n>
está em uma família separada da outra Os
, Ofast
e Og
.
Quando construímos, isso gera um options.h
arquivo 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\n
dentro common.opt
, notamos as linhas:
-optimize
Common Alias(O)
que nos ensina que --optimize
(traço duplo porque começa com um traço -optimize
no .opt
arquivo) é um apelido não documentado para o -O
qual 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.c
usos 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_argument
que chama atoi
a string correspondente a OPT_O
para analisar o argumento de entrada
- armazena o valor dentro de
opts->x_optimize
onde opts
é a struct gcc_opts
.
struct gcc_opts
Depois de fazer grep em vão, notamos que isso struct
também é gerado em options.h
:
struct gcc_options {
int x_optimize;
[...]
}
de onde x_optimize
vem 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_MAX
como um limite superior. E se você colocar algo maior, parece que o GCC executa um comportamento C indefinido. Ai?
integral_argument
também envolve atoi
e 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_options
que parece interessante. Nós entramos nele, e então maybe_default_option
chegamos 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á >= 4
verificações, o que indica que 3
é o maior possível.
Em seguida, procuramos a definição de OPT_LEVELS_3_PLUS
em 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_PLUS
e 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 -On
mapeamento 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_optimize
era definir outras opções de otimização específicas, como -fdefer_pop
documentado 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 -O
opção e será vinculado collec2
(que é basicamente um linker).
Na verdade, a primeira linha de lto-wrapper.c
diz:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
Neste arquivo, as OPT_O
ocorrências parecem apenas normalizar o valor de O
para repassá-lo, então devemos ficar bem.
man gcc
Cygwin (12.000 linhas ímpares), você pode pesquisar-O
e encontrar tudo o que as respostas abaixo afirmam e muito mais.