Cerchiamo di interpretare il codice sorgente di GCC 5.1 per vedere cosa succede in -O100quanto non è chiaro nella pagina del manuale.
Concluderemo che:
- qualsiasi cosa sopra
-O3fino a INT_MAXè uguale a -O3, ma potrebbe facilmente cambiare in futuro, quindi non fare affidamento su di esso.
- GCC 5.1 esegue un comportamento indefinito se inserisci numeri interi maggiori di
INT_MAX.
- l'argomento può contenere solo cifre o non riesce correttamente. In particolare, questo esclude interi negativi come
-O-1
Concentrati sui sottoprogrammi
In primo luogo ricordare che GCC è solo un front-end per cpp, as, cc1, collect2. Un rapido ./XXX --helpdice che solo collect2e cc1prendi -O, quindi concentriamoci su di loro.
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ì è -Ostato inoltrato a entrambi cc1e collect2.
O in comune. Opt
common.opt è un formato di descrizione dell'opzione CLI specifico di GCC descritto nella documentazione interna e tradotto in C da opth-gen.awk e optc-gen.awk .
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 Oopzioni. Si noti come -O<n>è in una famiglia separata dalle altre Os, Ofaste Og.
Quando creiamo, questo genera un options.hfile che contiene:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Come bonus, mentre cerchiamo l' \bO\ninterno common.optnotiamo le linee:
-optimize
Common Alias(O)
che ci insegna che --optimize(doppio trattino perché inizia con un trattino -optimizesul .optfile) è un alias non documentato per il -Oquale può essere usato come --optimize=3!
Dove viene utilizzato OPT_O
Ora grep:
git grep -E '\bOPT_O\b'
che ci indica due file:
Prima rintracciamo opts.c
opts.c: default_options_optimization
Tutti gli opts.cusi avvengono all'interno: default_options_optimization.
Facciamo un backtrack per vedere chi chiama questa funzione e vediamo che l'unico percorso del codice è:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
ed main.cè il punto di ingresso di cc1. Buona!
La prima parte di questa funzione:
- fa ciò
integral_argumentche chiama atoila stringa corrispondente a OPT_Oper analizzare l'argomento di input
- memorizza il valore all'interno di
opts->x_optimizedove optsè un struct gcc_opts.
struct gcc_opts
Dopo aver invano invano, notiamo che questo structviene generato anche in options.h:
struct gcc_options {
int x_optimize;
[...]
}
da dove x_optimizeviene le righe:
Variable
int optimize
presente in common.opt, e che options.c:
struct gcc_options global_options;
quindi supponiamo che questo sia ciò che contiene l'intero stato globale della configurazione, ed int x_optimizeè il valore di ottimizzazione.
255 è un massimo interno
in opts.c:integral_argument, atoiviene applicato all'argomento di input, quindi INT_MAXè un limite superiore. E se metti qualcosa di più grande, sembra che GCC esegua un comportamento C indefinito. Ahia?
integral_argumentinoltre racchiude in modo sottile atoie rifiuta l'argomento se un carattere non è una cifra. Quindi i valori negativi falliscono con grazia.
Torna a 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 venga troncato a 255. Durante la lettura opth-gen.awkmi ero imbattuto:
# 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 sul generato options.h:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
il che spiega il motivo del troncamento: le opzioni devono essere inoltrate anche a cl_optimization, che utilizza a charper risparmiare spazio. Quindi 255 è un massimo interno in realtà.
opts.c: forse_default_options
Tornando a opts.c:default_options_optimization, ci imbattiamo in ciò maybe_default_optionsche sembra interessante. Lo entriamo, e poi maybe_default_optiondove raggiungiamo 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 >= 4controlli, il che indica che 3è il più grande possibile.
Quindi cerchiamo la definizione di OPT_LEVELS_3_PLUSin 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. */
};
Ah! Questo è un forte indicatore che ci sono solo 3 livelli.
opts.c: default_options_table
opt_levelsè così interessante, che grep OPT_LEVELS_3_PLUS, e ci imbattiamo 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 è qui che -Onviene codificata la mappatura per l'ottimizzazione specifica menzionata nei documenti. Bello!
Assicurati che non ci siano più usi per x_optimize
L'utilizzo principale di x_optimizeera quello di impostare altre opzioni di ottimizzazione specifiche -fdefer_popcome documentato nella pagina man. Ce ne sono altri?
Noi grep, e ne troviamo altri. Il numero è piccolo e dopo un'ispezione manuale vediamo che ogni utilizzo fa solo al massimo a x_optimize >= 3, quindi la nostra conclusione vale.
lto-wrapper.c
Ora passiamo alla seconda occorrenza di OPT_O, che era in lto-wrapper.c.
LTO significa Ottimizzazione del tempo di collegamento, che come suggerisce il nome avrà bisogno di -Oun'opzione e sarà collegata a collec2(che è fondamentalmente un linker).
In effetti, la prima riga di lto-wrapper.cdice:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
In questo file, le OPT_Ooccorrenze sembrano normalizzare solo il valore di Oper passarlo in avanti, quindi dovremmo stare bene.
man gccCygwin (12000 righe dispari) puoi cercare-Oe trovare tutto ciò che le risposte sottostanti indicano, e poi alcune.