Let's interpretare il codice sorgente di GCC 5.1 per vedere cosa succede su -O100
poiché non è chiaro sulla pagina man.
Dobbiamo concludere che:
- qualsiasi cosa sopra
-O3
fino al INT_MAX
è lo stesso di -O3
, ma che potrebbe facilmente cambiare in futuro, in modo da non fare affidamento su di esso.
- GCC 5.1 esegue un comportamento non definito se si immettono numeri interi maggiori di
INT_MAX
.
- l'argomento può contenere solo cifre o non funziona correttamente. In particolare, questo esclude interi negativi come
-O-1
Focus on sottoprogrammi
Prima ricordare che GCC è solo un front-end per cpp
, as
, cc1
, collect2
. Un rapido ./XXX --help
dice che solo collect2
e cc1
prendono -O
, quindi concentriamoci su di essi.
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.
così -O
è stata trasmessa sia cc1
e collect2
.
O in common.opt
common.opt è un'opzione specifica CLI descrizione formato GCC descritto nella internals documentation e tradotto a C opth-gen.awk e optc-gen.awk.
Esso contiene le seguenti righe interessanti:
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
che specificano tutte le opzioni O
. Si noti come -O<n>
si trovi in una famiglia separata dall'altra Os
, Ofast
e Og
.
Quando costruiamo, questo genera un file options.h
che contiene:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Come bonus, mentre stiamo grep per \bO\n
all'interno common.opt
notiamo le linee:
-optimize
Common Alias(O)
che ci insegna che --optimize
(doppio trattino perché inizia con un trattino -optimize
sul file .opt
) è un alias non documentato per -O
che può essere utilizzato come --optimize=3
!
Dove OPT_O viene utilizzato
Ora ci Grep:
git grep -E '\bOPT_O\b'
che ci indica due file:
prima traccia
Let giù opts.c
opts.c: default_options_optimization
Tutti opts.c
usi avvengono all'interno: default_options_optimization
.
Abbiamo grep passo indietro per vedere chi chiama questa funzione, e vediamo che l'unico percorso di codice è:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
e main.c
è il punto di ingresso di cc1
. Buona!
La prima parte di questa funzione:
- fa
integral_argument
che invita atoi
sulla stringa corrispondente al OPT_O
per analizzare l'argomento di input
- memorizza il valore all'interno
opts->x_optimize
dove opts
è un struct gcc_opts
.
struct gcc_opts
Dopo grep invano, notiamo che questo struct
viene generata anche in options.h
:
struct gcc_options {
int x_optimize;
[...]
}
dove x_optimize
viene dalle linee:
Variable
int optimize
prese nt in common.opt
, e che options.c
:
struct gcc_options global_options;
così abbiamo indovinare che questo è ciò che contiene tutto lo stato globale di configurazione, e int x_optimize
è il valore di ottimizzazione.
255 è un interno massimo
in opts.c:integral_argument
, atoi
viene applicata l'argomento di input, in modo INT_MAX
è un limite superiore. E se metti qualcosa di più grande, sembra che GCC esegua un comportamento non definito. Ahia?
integral_argument
avvolge anche atoi
e rifiuta l'argomento se qualsiasi carattere non è una cifra. Quindi i valori negativi falliscono con grazia.
Torna opts.c:default_options_optimization
, vediamo la linea:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
in modo che il livello di ottimizzazione è troncato a 255
.Durante la lettura opth-gen.awk
mi ero imbattuto in:
# 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 sulla generato options.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
il che spiega il motivo per cui il troncamento: le opzioni devono essere inoltrate al cl_optimization
, che utilizza un char
per risparmiare spazio . Quindi 255 è effettivamente un massimo interno.
opts.c: maybe_default_options
Torna opts.c:default_options_optimization
, ci imbattiamo in maybe_default_options
che sembra interessante. Entriamo, e poi maybe_default_option
dove si arriva ad un grande interruttore:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
non ci sono >= 4
controlli, che indica che 3
è il più grande possibile.
Poi cerchiamo la definizione di OPT_LEVELS_3_PLUS
in 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! Questo è un forte indicatore che ci sono solo 3 livelli.
opts.c: default_options_table
opt_levels
è così interessante, che noi Grep OPT_LEVELS_3_PLUS
, e si imbatte 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 },
[...]
}
quindi questo è dove il -On
alla mappatura ottimizzazione specifico menzionato nella i documenti sono codificati. Bello!
assicuro che non ci sono più usi per x_optimize
L'utilizzo principale del x_optimize
era per impostare altre opzioni di ottimizzazione specifici come -fdefer_pop
come documentato nella pagina man. Ce ne sono altri?
grep
, e trovarne alcuni altri. Il numero è piccolo, e dopo l'ispezione manuale vediamo che ogni utilizzo fa al massimo uno x_optimize >= 3
, quindi la nostra conclusione vale.
lto-wrapper.c
Adesso andiamo per la seconda occorrenza di OPT_O
, che era in lto-wrapper.c
.
LTO significa Link Time Optimization, che come suggerisce il nome avrà bisogno di un'opzione -O
e sarà collegato a collec2
(che è fondamentalmente un linker).
In effetti, la prima linea di lto-wrapper.c
dice:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
In questo file, i OPT_O
occorrenze sembra normalizzarsi solo il valore del O
a passare in avanti, in modo che dovrebbe andare bene.
@Jens: TFM è lungo 15.000 righe e non ha molto da dire su '-O' :) – Ryan
@minitech Quale FM stai guardando? Anche con 'man gcc' su Cygwin (12000 righe dispari) puoi cercare' -O' e trovare tutte le risposte che seguono e poi alcune. – Jens
@minmaxavg dopo aver letto la fonte, non sono d'accordo con te: qualsiasi cosa più grande di '3' è la stessa di' 3' (a patto che non abbia un overflow 'int'). Vedi [la mia risposta] (http://stackoverflow.com/a/30308151/895245). –