Spójrzmy prawdzie w interpretacji kodu źródłowego GCC 5.1 , aby zobaczyć, co dzieje się -O100
, ponieważ nie jest jasne, na stronie man.
Wnioskujemy, że:
- wszystko powyżej
-O3
do INT_MAX
jest takie samo jak -O3
, ale może się to łatwo zmienić w przyszłości, więc nie polegaj na tym.
- GCC 5.1 uruchamia niezdefiniowane zachowanie, jeśli wprowadzisz liczby całkowite większe niż
INT_MAX
.
- argument może mieć tylko cyfry lub zawodzi. W szczególności wyklucza to ujemne liczby całkowite, takie jak
-O-1
Skoncentruj się na podprogramach
Po pierwsze należy pamiętać, że GCC jest tylko front-end dla cpp
, as
, cc1
, collect2
. Krótko ./XXX --help
mówiąc, tylko collect2
i cc1
bierz -O
, więc skupmy się na nich.
I:
gcc -v -O100 main.c |& grep 100
daje:
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.
więc -O
został przekazany do obu cc1
i collect2
.
O in common.opt
common.opt to specyficzny dla GCC format opisu opcji CLI opisany w wewnętrznej dokumentacji i przetłumaczony na C przez opth-gen.awk i optc-gen.awk .
Zawiera następujące interesujące wiersze:
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
które określają wszystkie O
opcje. Zwróć uwagę, jak -O<n>
jest w osobnej rodziny z drugiej strony Os
, Ofast
i Og
.
Kiedy budujemy, generuje options.h
plik, który zawiera:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Jako bonus, gdy grepujemy do \bO\n
środka common.opt
, zauważamy linie:
-optimize
Common Alias(O)
co nas uczy, że --optimize
(podwójny myślnik, ponieważ zaczyna się od myślnika -optimize
w .opt
pliku) jest nieudokumentowanym aliasem, -O
którego można użyć jako --optimize=3
!
Gdzie OPT_O jest używany
Teraz grep:
git grep -E '\bOPT_O\b'
co wskazuje nam na dwa pliki:
Najpierw wytropmy opts.c
opts.c: default_options_optimization
Wszystkie opts.c
zwyczaje zdarzyć wewnątrz: default_options_optimization
.
Wykonujemy grep backtrack, aby zobaczyć, kto wywołuje tę funkcję i widzimy, że jedyna ścieżka do kodu to:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
i main.c
jest punktem wejścia cc1
. Dobry!
Pierwsza część tej funkcji:
- robi,
integral_argument
która wywołuje atoi
ciąg odpowiadający do, OPT_O
aby przeanalizować argument wejściowy
- przechowuje wartość wewnątrz,
opts->x_optimize
gdzie opts
jest struct gcc_opts
.
struct gcc_opts
Po grepowaniu na próżno zauważamy, że struct
jest to również generowane pod adresem options.h
:
struct gcc_options {
int x_optimize;
[...]
}
skąd x_optimize
pochodzi z linii:
Variable
int optimize
obecny w common.opt
i że options.c
:
struct gcc_options global_options;
więc domyślamy się, że to właśnie zawiera cały stan globalny konfiguracji i int x_optimize
jest wartością optymalizacji.
255 to wewnętrzne maksimum
in opts.c:integral_argument
, atoi
jest stosowany do argumentu wejściowego, więc INT_MAX
jest to górna granica. A jeśli umieścisz coś większego, wydaje się, że GCC uruchamia niezdefiniowane zachowanie C. Auć?
integral_argument
również cienko zawija atoi
i odrzuca argument, jeśli którykolwiek znak nie jest cyfrą. Zatem wartości ujemne zawodzą wdzięcznie.
Wracając do opts.c:default_options_optimization
, widzimy wiersz:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
tak aby poziom optymalizacji został obcięty do 255
. Podczas czytania opth-gen.awk
natknąłem się na:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
i na wygenerowanych options.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
co wyjaśnia, dlaczego obcięcie: opcje muszą być również przekazane do cl_optimization
, który używa a, char
aby zaoszczędzić miejsce. Tak więc 255 jest właściwie wewnętrznym maksimum.
opts.c: może_default_options
Wracając do opts.c:default_options_optimization
, natrafiliśmy na to, maybe_default_options
co brzmi interesująco. Wchodzimy do niego, a potem maybe_default_option
docieramy do dużego przełącznika:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
Nie ma >= 4
kontroli, co oznacza, że 3
jest to możliwie największe.
Następnie szukamy definicji OPT_LEVELS_3_PLUS
w 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! To mocny wskaźnik, że istnieją tylko 3 poziomy.
opts.c: default_options_table
opt_levels
jest tak interesujący, że grepujemy OPT_LEVELS_3_PLUS
i natrafiamy na 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 },
[...]
}
więc w tym miejscu -On
jest kodowane mapowanie optymalizacyjne do określonego, o którym mowa w dokumentacji. Miły!
Upewnij się, że x_optimize nie ma już zastosowań
Głównym zastosowaniem x_optimize
było ustawienie innych specyficznych opcji optymalizacji, takich -fdefer_pop
jak udokumentowane na stronie podręcznika. Czy jest ich więcej?
My grep
i znajdujemy kilka innych. Liczba jest niewielka i po ręcznym sprawdzeniu widzimy, że każde użycie powoduje co najwyżej a x_optimize >= 3
, więc nasz wniosek jest ważny.
lto-wrapper.c
Teraz przejdźmy do drugiego wystąpienia OPT_O
, które było w lto-wrapper.c
.
LTO oznacza optymalizację czasu łącza, która, jak nazwa sugeruje, będzie potrzebować -O
opcji i będzie połączona z collec2
(co jest w zasadzie konsolidatorem).
W rzeczywistości pierwsza linijka lto-wrapper.c
mówi:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
W tym pliku OPT_O
wystąpienia wydają się tylko normalizować wartość, O
aby przekazać ją dalej, więc powinno być dobrze.
man gcc
na Cygwin (12000 nieparzystych wierszy) możesz wyszukać-O
i znaleźć wszystko, co podają poniższe odpowiedzi, a następnie niektóre.