Lassen Sie uns den Quellcode von GCC 5.1 interpretieren, um zu sehen, was passiert, -O100
da dies auf der Manpage nicht klar ist.
Wir werden daraus schließen, dass:
- Alles, was darüber liegt
-O3
, INT_MAX
ist 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 --help
sagt das nur collect2
und cc1
nimm -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 -O
wurde an beide cc1
und 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 O
Optionen angeben . Beachten Sie, wie -O<n>
in einer von der anderen Familie getrennt ist Os
, Ofast
und Og
.
Beim Erstellen wird eine options.h
Datei 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\n
innen greifen common.opt
, die Zeilen:
-optimize
Common Alias(O)
Das lehrt uns, dass --optimize
(doppelter Bindestrich, da er mit einem Bindestrich -optimize
in der .opt
Datei beginnt ) ein undokumentierter Alias ist, für -O
den 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.c
Verwendungen 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.c
ist der Einstiegspunkt von cc1
. Gut!
Der erste Teil dieser Funktion:
- tut,
integral_argument
was atoi
die Zeichenfolge aufruft, die OPT_O
dem Analysieren des Eingabearguments entspricht
- speichert den Wert darin,
opts->x_optimize
wo a opts
ist struct gcc_opts
.
struct gcc_opts
Nachdem wir vergeblich gegriffen haben, stellen wir fest, dass dies struct
auch generiert wird bei options.h
:
struct gcc_options {
int x_optimize;
[...]
}
wo x_optimize
kommt aus den Zeilen:
Variable
int optimize
vorhanden in common.opt
und dass options.c
:
struct gcc_options global_options;
Wir vermuten also, dass dies den gesamten globalen Konfigurationsstatus und int x_optimize
den Optimierungswert enthält.
255 ist ein internes Maximum
in opts.c:integral_argument
, atoi
wird auf das Eingabeargument angewendet, ebenso INT_MAX
eine Obergrenze. Und wenn Sie etwas Größeres hinzufügen, scheint es, dass GCC C undefiniertes Verhalten ausführt. Autsch?
integral_argument
Außerdem wird atoi
das 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_optimization
wir 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.awk
ich 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 char
Platz 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_options
was interessant klingt. Wir betreten es und maybe_default_option
erreichen 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 3
die größtmögliche ist.
Dann suchen wir nach der Definition von 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! Dies ist ein starker Indikator dafür, dass es nur 3 Ebenen gibt.
opts.c: default_options_table
opt_levels
ist so interessant, dass wir grep OPT_LEVELS_3_PLUS
und 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 -On
die 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_optimize
bestand darin, andere spezifische Optimierungsoptionen festzulegen, wie sie -fdefer_pop
auf der Manpage dokumentiert sind. Gibt es noch mehr
Wir grep
und 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 -O
Option erforderlich ist und mit der verknüpft wird collec2
(was im Grunde genommen ein Linker ist).
In der Tat lto-wrapper.c
sagt die erste Zeile von :
/* Wrapper to call lto. Used by collect2 and the linker plugin.
In dieser Datei OPT_O
scheinen die Vorkommen nur den Wert von O
zu normalisieren , um ihn weiterzuleiten, also sollten wir in Ordnung sein.
man gcc
auf Cygwin (12000 ungerade Zeilen) können Sie-O
alles suchen und finden, was die Antworten unten angeben, und noch einige mehr.