Lassen Sie uns den Quellcode von GCC 5.1 interpretieren, um zu sehen, was passiert, -O100da dies auf der Manpage nicht klar ist.
Wir werden daraus schließen, dass:
- Alles, was darüber liegt
-O3, INT_MAXist dasselbe wie -O3, aber das könnte sich in Zukunft leicht ändern. Verlassen Sie sich also nicht darauf.
- GCC 5.1 führt ein undefiniertes Verhalten aus, wenn Sie Ganzzahlen eingeben, die größer als sind
INT_MAX.
- Das Argument kann nur Ziffern haben oder schlägt ordnungsgemäß fehl. Dies schließt insbesondere negative ganze Zahlen wie aus
-O-1
Konzentrieren Sie sich auf Unterprogramme
Zunächst erinnert , dass GCC ist nur ein Front-End für cpp, as, cc1, collect2. Ein kurzer ./XXX --helpsagt das nur collect2und cc1nimm -O, also konzentrieren wir uns auf sie.
Und:
gcc -v -O100 main.c |& grep 100
gibt:
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.
so -Owurde an beide cc1und weitergeleitet collect2.
O gemeinsam.opt
common.opt ist ein GCC-spezifisches CLI-Optionsbeschreibungsformat, das in der internen Dokumentation beschrieben und von opth-gen.awk und optc-gen.awk in C übersetzt wird .
Es enthält die folgenden interessanten Zeilen:
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
die alle OOptionen angeben . Beachten Sie, wie -O<n>in einer von der anderen Familie getrennt ist Os, Ofastund Og.
Beim Erstellen wird eine options.hDatei generiert, die Folgendes enthält:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Als Bonus bemerken wir , während wir nach \bO\ninnen greifen common.opt, die Zeilen:
-optimize
Common Alias(O)
Das lehrt uns, dass --optimize(doppelter Bindestrich, da er mit einem Bindestrich -optimizein der .optDatei beginnt ) ein undokumentierter Alias ist, für -Oden verwendet werden kann als --optimize=3!
Wo OPT_O verwendet wird
Jetzt grep wir:
git grep -E '\bOPT_O\b'
was uns auf zwei Dateien verweist:
Lassen Sie uns zuerst aufspüren opts.c
opts.c: default_options_optimization
Alle opts.cVerwendungen erfolgen innerhalb : default_options_optimization.
Wir greifen nach dem Backtrack, um zu sehen, wer diese Funktion aufruft, und wir sehen, dass der einzige Codepfad ist:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
und main.cist der Einstiegspunkt von cc1. Gut!
Der erste Teil dieser Funktion:
- tut,
integral_argumentwas atoidie Zeichenfolge aufruft, die OPT_Odem Analysieren des Eingabearguments entspricht
- speichert den Wert darin,
opts->x_optimizewo a optsist struct gcc_opts.
struct gcc_opts
Nachdem wir vergeblich gegriffen haben, stellen wir fest, dass dies structauch generiert wird bei options.h:
struct gcc_options {
int x_optimize;
[...]
}
wo x_optimizekommt aus den Zeilen:
Variable
int optimize
vorhanden in common.optund dass options.c:
struct gcc_options global_options;
Wir vermuten also, dass dies den gesamten globalen Konfigurationsstatus und int x_optimizeden Optimierungswert enthält.
255 ist ein internes Maximum
in opts.c:integral_argument, atoiwird auf das Eingabeargument angewendet, ebenso INT_MAXeine Obergrenze. Und wenn Sie etwas Größeres hinzufügen, scheint es, dass GCC C undefiniertes Verhalten ausführt. Autsch?
integral_argumentAußerdem wird atoidas Argument dünn umbrochen und zurückgewiesen, wenn ein Zeichen keine Ziffer ist. Negative Werte scheitern also anmutig.
Zurück zu sehen opts.c:default_options_optimizationwir die Linie:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
so dass die Optimierungsstufe auf abgeschnitten wird 255. Beim Lesen war opth-gen.awkich auf Folgendes gestoßen:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
und auf dem generierten options.h:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
Das erklärt, warum die Kürzung: Die Optionen müssen auch weitergeleitet werden cl_optimization, wodurch ein charPlatz spart. 255 ist also tatsächlich ein internes Maximum.
opts.c: vielleicht_default_options
Zurück zu opts.c:default_options_optimization, wir stoßen auf das, maybe_default_optionswas interessant klingt. Wir betreten es und maybe_default_optionerreichen dann einen großen Schalter:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
Es gibt keine >= 4Überprüfungen, was darauf hinweist, dass dies 3die größtmögliche ist.
Dann suchen wir nach der Definition von 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. */
};
Ha! Dies ist ein starker Indikator dafür, dass es nur 3 Ebenen gibt.
opts.c: default_options_table
opt_levelsist so interessant, dass wir grep OPT_LEVELS_3_PLUSund stoßen auf 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 },
[...]
}
Hier wird also -Ondie in den Dokumenten erwähnte Zuordnung zur spezifischen Optimierung codiert. Nett!
Stellen Sie sicher, dass x_optimize nicht mehr verwendet wird
Die Hauptverwendung von x_optimizebestand darin, andere spezifische Optimierungsoptionen festzulegen, wie sie -fdefer_popauf der Manpage dokumentiert sind. Gibt es noch mehr
Wir grepund finden ein paar mehr. Die Anzahl ist gering, und bei manueller Prüfung stellen wir fest, dass jede Verwendung höchstens a bewirkt x_optimize >= 3, so dass unsere Schlussfolgerung gilt.
lto-wrapper.c
Jetzt gehen wir zum zweiten Vorkommen von OPT_O, das in war lto-wrapper.c.
LTO bedeutet Link Time Optimization, für die, wie der Name schon sagt, eine -OOption erforderlich ist und mit der verknüpft wird collec2(was im Grunde genommen ein Linker ist).
In der Tat lto-wrapper.csagt die erste Zeile von :
/* Wrapper to call lto. Used by collect2 and the linker plugin.
In dieser Datei OPT_Oscheinen die Vorkommen nur den Wert von Ozu normalisieren , um ihn weiterzuleiten, also sollten wir in Ordnung sein.
man gccauf Cygwin (12000 ungerade Zeilen) können Sie-Oalles suchen und finden, was die Antworten unten angeben, und noch einige mehr.