Vamos a interpretar el código fuente de GCC 5.1 para ver qué pasa en -O100
ya que no está claro en la página de manual.
Vamos a la conclusión de que:
- nada por encima de
-O3
hasta INT_MAX
es la misma que -O3
, pero que fácilmente podría cambiar 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 con elegancia. En particular, esto excluye enteros negativos como
-O-1
Centrarse en subprogramas
En primer lugar recuerda que GCC es sólo un front-end para cpp
, as
, cc1
, collect2
. Un rápido ./XXX --help
dice que solo collect2
y cc1
toman -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 -O
fue remitida a los dos cc1
y collect2
.
O en common.opt
common.opt es una opción CLI formato de descripción específica GCC se describe en la internals documentation 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 opciones O
. Observe cómo -O<n>
se encuentra en una familia separada de la otra Os
, Ofast
y Og
.
Cuando construimos, esto genera un archivo options.h
que contiene:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Como beneficio adicional, mientras que estamos grepping para \bO\n
dentro common.opt
nos damos cuenta de las líneas:
-optimize
Common Alias(O)
que nos enseña que --optimize
(doble guión porque comienza con un guión -optimize
en el archivo .opt
) es un alias no documentado para -O
que se puede utilizar como --optimize=3
!
Cuando se utiliza OPT_O
Ahora GREP:
git grep -E '\bOPT_O\b'
que nos señala dos archivos:
primera pista
Vamos hacia abajo opts.c
opts.c: default_options_optimization
Todos opts.c
usos suceden en el interior: default_options_optimization
.
Nos GrEP a retroceder 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.c
es el punto de entrada de cc1
. ¡Bueno!
La primera parte de esta función:
- hace
integral_argument
que exige atoi
en la cuerda correspondiente a OPT_O
para analizar el argumento de entrada
- almacena el valor en el interior
opts->x_optimize
donde opts
es una struct gcc_opts
.
estructura gcc_opts
Después grepping en vano, nos damos cuenta de que este struct
también se genera en options.h
:
struct gcc_options {
int x_optimize;
[...]
}
donde x_optimize
proviene de las líneas:
Variable
int optimize
prese nt de common.opt
, y que options.c
:
struct gcc_options global_options;
así que supongo que esto es lo que contiene todo el estado de configuración global, y int x_optimize
es el valor de optimización.
255 es una interna máxima
en opts.c:integral_argument
, atoi
se aplica al argumento de entrada, por lo INT_MAX
es un límite superior. Y si pone algo más grande, parece que GCC ejecuta C comportamiento indefinido. ¿Ay?
integral_argument
también envuelve delgadas atoi
y rechaza el argumento si cualquier carácter no es un dígito. Entonces los valores negativos fallan con gracia.
Volver a opts.c:default_options_optimization
, vemos la línea:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
de manera que el nivel de optimización se trunca a 255
.Durante la lectura de opth-gen.awk
me había encontrado:
# 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 la generada options.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
que explica por qué el truncamiento: las opciones también deben enviarse a cl_optimization
, que utiliza un char
para ahorrar espacio . Entonces 255 es un máximo interno en realidad.
opts.c: maybe_default_options
Volver a opts.c:default_options_optimization
, nos encontramos con maybe_default_options
que suena interesante. Entramos en él, y luego maybe_default_option
donde se llega a un gran cambio:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
No hay >= 4
cheques, lo que indica que 3
es la más grande posible.
Luego buscamos la definición de OPT_LEVELS_3_PLUS
en 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. */
};
Ja! Este es un fuerte indicador de que solo hay 3 niveles.
opts.c: default_options_table
opt_levels
es tan interesante, que GrEP OPT_LEVELS_3_PLUS
, y 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 este es el lugar donde el -On
a la cartografía de optimización específica mencionada en el docs está codificado. ¡Bonito!
asegurar que no hay más usos para x_optimize
El uso principal de x_optimize
era establecer otras opciones de optimización específicas como -fdefer_pop
tal como se documenta en la página del manual. ¿Hay más?
We grep
, y encuentre algunos más. El número es pequeño, y después de la inspección manual vemos que cada uso solo hace como máximo un x_optimize >= 3
, por lo que nuestra conclusión es válida.
LTO-wrapper.c
Ahora vamos a por la segunda aparición de OPT_O
, que estaba en lto-wrapper.c
.
LTO significa Link Time Optimization, que como su nombre indica va a necesitar una opción -O
, y se vinculará a collec2
(que básicamente es un enlazador).
De hecho, la primera línea de lto-wrapper.c
dice:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
En este archivo, las ocurrencias OPT_O
sólo parece normalizar el valor de O
a pasarla hacia adelante, por lo que debe estar bien.
@Jens: TFM tiene 15,000 líneas y no tiene mucho que decir sobre '-O' :) – Ryan
@minitech ¿Qué FM estás mirando? Incluso con 'man gcc' en Cygwin (12000 líneas impares) puede buscar' -O' y encontrar todo lo que las respuestas a continuación dicen, y algo más. – Jens
@minmaxavg después de leer la fuente, no estoy de acuerdo con usted: cualquier cosa más grande que '3' es lo mismo que' 3' (siempre que no se sobrepase 'int'). Ver [mi respuesta] (http://stackoverflow.com/a/30308151/895245). –