Nous allons interpréter le code source de GCC 5.1 pour voir ce qui se passe sur-O100
, car il est pas clair sur la page de manuel.
Nous conclurons que:
- quoi que ce soit au- dessus
-O3
jusqu'à INT_MAX
est le même que -O3
, mais que , dans l'avenir pourrait facilement changer, alors ne comptez pas sur elle.
- GCC 5.1 exécute un comportement non défini si vous entrez des entiers supérieurs à
INT_MAX
.
- l'argument ne peut avoir que des chiffres, ou il échoue normalement. En particulier, cela exclut les entiers négatifs comme
-O-1
Focus sur les sous-programmes
Tout d' abord se rappeler que le GCC est juste un front-end pour cpp
, as
, cc1
, collect2
. Un rapide ./XXX --help
dit cela seulement collect2
et cc1
prenons -O
, alors concentrons-nous sur eux.
Et:
gcc -v -O100 main.c |& grep 100
donne:
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.
donc a -O
été transmis à la fois cc1
et collect2
.
O en commun.opt
common.opt est un format de description d'option CLI spécifique à GCC décrit dans la documentation interne et traduit en C par opth-gen.awk et optc-gen.awk .
Il contient les lignes intéressantes suivantes:
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
qui spécifient toutes les O
options. Notez comment se -O<n>
trouve dans une famille distincte de l'autre Os
, Ofast
et Og
.
Lorsque nous construisons, cela génère un options.h
fichier qui contient:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
En prime, pendant que nous cherchons à l' \bO\n
intérieur, common.opt
nous remarquons les lignes:
-optimize
Common Alias(O)
ce qui nous apprend que --optimize
(double tiret car il commence par un tiret -optimize
sur le .opt
fichier) est un alias non documenté pour -O
lequel peut être utilisé comme --optimize=3
!
Où OPT_O est utilisé
Maintenant, nous grep:
git grep -E '\bOPT_O\b'
ce qui nous renvoie à deux fichiers:
Commençons par traquer opts.c
opts.c: default_options_optimization
Tout opts.c
les usages se produisent à l' intérieur: default_options_optimization
.
Nous faisons un retour en arrière pour voir qui appelle cette fonction, et nous voyons que le seul chemin du code est:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
et main.c
est le point d'entrée de cc1
. Bien!
La première partie de cette fonction:
- fait
integral_argument
qui appelleatoi
la chaîne correspondant à OPT_O
pour analyser l'argument d'entrée
- stocke la valeur à l'intérieur
opts->x_optimize
où opts
est a struct gcc_opts
.
struct gcc_opts
Après avoir vainement greffé, nous remarquons que ceci struct
est également généré à options.h
:
struct gcc_options {
int x_optimize;
[...]
}
d'où x_optimize
vient les lignes:
Variable
int optimize
présent dans common.opt
, et que options.c
:
struct gcc_options global_options;
on suppose donc que c'est ce qui contient tout l'état global de la configuration, et int x_optimize
la valeur d'optimisation.
255 est un maximum interne
in opts.c:integral_argument
, atoi
est appliqué à l'argument d'entrée, de même INT_MAX
qu'une limite supérieure. Et si vous mettez quelque chose de plus gros, il semble que GCC exécute un comportement C indéfini. Aie?
integral_argument
encapsule également finement atoi
et rejette l'argument si un caractère n'est pas un chiffre. Les valeurs négatives échouent donc gracieusement.
De retour opts.c:default_options_optimization
, nous voyons la ligne:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
afin que le niveau d'optimisation soit tronqué à 255
. En lisant, opth-gen.awk
j'étais tombé sur:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
et sur le généré options.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
ce qui explique pourquoi la troncature: les options doivent également être transmises vers cl_optimization
, qui utilise unchar
pour économiser de l'espace. Donc, 255 est en fait un maximum interne.
opts.c: peut-être_default_options
De retour à opts.c:default_options_optimization
, nous trouvons maybe_default_options
ce qui semble intéressant. Nous y entrons, puis maybe_default_option
nous atteignons un gros interrupteur:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
Il n'y a pas de >= 4
contrôle, ce qui indique que 3
c'est le plus grand possible.
Ensuite, nous recherchons la définition de 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! C'est un indicateur fort qu'il n'y a que 3 niveaux.
opts.c: default_options_table
opt_levels
est si intéressant, que nous grep OPT_LEVELS_3_PLUS
, et tombons sur 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 },
[...]
}
c'est donc là que le -On
mappage d'optimisation spécifique mentionné dans la documentation est codé. Agréable!
Assurez-vous qu'il n'y a plus d'utilisations pour x_optimize
L'utilisation principale de x_optimize
était de définir d'autres options d'optimisation spécifiques telles -fdefer_pop
que décrites dans la page de manuel. Y en a-t-il plus?
Nous grep
, et en trouver quelques autres. Le nombre est petit, et après une inspection manuelle, nous voyons que chaque utilisation ne fait qu'au plus un x_optimize >= 3
, donc notre conclusion est valable.
lto-wrapper.c
Nous passons maintenant à la deuxième occurrence de OPT_O
, qui était enlto-wrapper.c
.
LTO signifie Link Time Optimization, qui, comme son nom l'indique, aura besoin d'une -O
option et sera lié àcollec2
(qui est essentiellement un éditeur de liens).
En fait, la première ligne de lto-wrapper.c
dit:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
Dans ce fichier, les OPT_O
occurrences semblent ne normaliser que la valeur de O
pour la transmettre, donc ça devrait aller.
man gcc
sur Cygwin (12000 lignes impaires), vous pouvez rechercher-O
et trouver tout ce que les réponses ci-dessous indiquent, et plus encore.