Vamos a interpretar el código fuente de GCC 5.1 para ver lo que ocurre en -O100ya que no está claro en la página del manual.
Concluiremos que:
- todo lo anterior
-O3hasta INT_MAXes lo mismo que -O3, pero eso podría cambiar fácilmente en el futuro, así que no confíe en él.
- GCC 5.1 ejecuta un comportamiento indefinido si ingresa números enteros mayores que
INT_MAX.
- el argumento solo puede tener dígitos, o falla correctamente. En particular, esto excluye enteros negativos como
-O-1
Centrarse en subprogramas
En primer lugar, recuerde que GCC es sólo un front-end para cpp, as, cc1, collect2. Un rápido ./XXX --helpdice eso solo collect2y cc1toma -O, así que centrémonos en ellos.
Y:
gcc -v -O100 main.c |& grep 100
da:
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.
por lo que -Ose reenvió a ambos cc1y collect2.
O en common.opt
common.opt es un formato de descripción de opción CLI específico de GCC descrito en la documentación interna y traducido a C por opth-gen.awk y optc-gen.awk .
Contiene las siguientes líneas interesantes:
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 especifican todas las Oopciones. Tenga -O<n>en cuenta cómo está en una familia separada de la otra Os, Ofasty Og.
Cuando construimos, esto genera un options.harchivo que contiene:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Como beneficio adicional, mientras buscamos \bO\ndentro common.opt, notamos las líneas:
-optimize
Common Alias(O)
lo que nos enseña que --optimize(doble guión porque comienza con un guión -optimizeen el .optarchivo) es un alias indocumentado para el -Ocual se puede usar como --optimize=3!
Donde se usa OPT_O
Ahora hacemos grep:
git grep -E '\bOPT_O\b'
que nos apunta a dos archivos:
Primero busquemos opts.c
opts.c: optimización_opciones_predeterminadas
Todos los opts.cusos suceden en el interior: default_options_optimization.
Hacemos grep backtrack para ver quién llama a esta función, y vemos que la única ruta de código es:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
y main.ces el punto de entrada de cc1. ¡Bueno!
La primera parte de esta función:
- hace
integral_argumentque llama atoia la cadena correspondiente a OPT_Opara analizar el argumento de entrada
- almacena el valor dentro de
opts->x_optimizedonde optsestá a struct gcc_opts.
struct gcc_opts
Después de hacer grepping en vano, notamos que esto structtambién se genera en options.h:
struct gcc_options {
int x_optimize;
[...]
}
de donde x_optimizeviene de las lineas:
Variable
int optimize
presente en common.opt, y que options.c:
struct gcc_options global_options;
por lo que suponemos que esto es lo que contiene todo el estado global de la configuración y int x_optimizees el valor de optimización.
255 es un máximo interno
in opts.c:integral_argument, atoise aplica al argumento de entrada, por lo que INT_MAXes un límite superior. Y si pones algo más grande, parece que GCC ejecuta un comportamiento indefinido de C. ¿Ay?
integral_argumenttambién envuelve atoiy rechaza el argumento si algún carácter no es un dígito. Así que los valores negativos fallan con gracia.
De vuelta a opts.c:default_options_optimization, vemos la línea:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
de modo que el nivel de optimización se trunca a 255. Mientras leía opth-gen.awkme encontré con:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
y sobre el generado options.h:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
lo que explica por qué el truncamiento: las opciones también deben reenviarse a cl_optimization, que usa a charpara ahorrar espacio. Entonces 255 es un máximo interno en realidad.
opts.c: maybe_default_options
Volviendo a opts.c:default_options_optimization, nos encontramos con lo maybe_default_optionsque suena interesante. Lo ingresamos, y luego maybe_default_optiondonde llegamos a un gran interruptor:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
No hay >= 4cheques, lo que indica que 3es el más grande posible.
Luego buscamos la definición de OPT_LEVELS_3_PLUSen 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. */
};
¡Decir ah! Este es un fuerte indicador de que solo hay 3 niveles.
opts.c: tabla_opciones_predeterminadas
opt_levelses tan interesante, que hacemos grep OPT_LEVELS_3_PLUSy 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 },
[...]
}
por lo que aquí es donde -Onse codifica el mapeo de optimización específico mencionado en los documentos. ¡Agradable!
Asegúrese de que no haya más usos para x_optimize
El uso principal de x_optimizefue establecer otras opciones de optimización específicas -fdefer_popcomo se documenta en la página de manual. ¿Hay más?
Nosotros grep, y encontramos algunos más. El número es pequeño y, tras una inspección manual, vemos que cada uso solo hace como máximo a x_optimize >= 3, por lo que nuestra conclusión es válida.
lto-wrapper.c
Ahora vamos a la segunda aparición de OPT_O, que estaba en lto-wrapper.c.
LTO significa Optimización de tiempo de enlace, que, como su nombre indica, necesitará una -Oopción y estará vinculada collec2(que es básicamente un enlazador).
De hecho, la primera línea de lto-wrapper.cdice:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
En este archivo, las OPT_Oocurrencias parecen solo normalizar el valor de Opara pasarlo hacia adelante, así que deberíamos estar bien.
man gccCygwin (12000 líneas impares) puede buscar-Oy encontrar todo lo que indican las respuestas a continuación, y más.