Hãy giải thích mã nguồn của GCC 5.1 để xem điều gì xảy ra -O100
vì nó không rõ ràng trên trang người dùng.
Chúng tôi sẽ kết luận rằng:
- bất cứ thứ gì ở trên
-O3
cho đến INT_MAX
đều giống như -O3
, nhưng điều đó có thể dễ dàng thay đổi trong tương lai, vì vậy đừng dựa vào nó.
- GCC 5.1 chạy hành vi không xác định nếu bạn nhập các số nguyên lớn hơn
INT_MAX
.
- đối số chỉ có thể có các chữ số hoặc nó không thành công. Đặc biệt, điều này loại trừ các số nguyên âm như
-O-1
Tập trung vào các chương trình con
Đầu tiên hãy nhớ rằng GCC chỉ là một front-end cho cpp
, as
, cc1
, collect2
. Nhanh ./XXX --help
nói rằng chỉ collect2
và cc1
lấy -O
, vì vậy hãy tập trung vào chúng.
Và:
gcc -v -O100 main.c |& grep 100
cho:
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.
vì vậy -O
đã được chuyển tiếp cho cả hai cc1
và collect2
.
O chung .opt
common.opt là một định dạng mô tả tùy chọn CLI GCC cụ thể được mô tả trong tài liệu hướng dẫn internals và dịch sang C bằng opth-gen.awk và optc-gen.awk .
Nó chứa những dòng thú vị sau:
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
trong đó chỉ định tất cả các O
tùy chọn. Lưu ý như thế nào -O<n>
là trong một họ riêng biệt với họ khác Os
, Ofast
và Og
.
Khi chúng tôi xây dựng, điều này sẽ tạo ra một options.h
tệp chứa:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Như một phần thưởng, trong khi chúng tôi đang tìm kiếm \bO\n
bên trong, common.opt
chúng tôi nhận thấy các dòng:
-optimize
Common Alias(O)
điều này dạy chúng ta rằng --optimize
(dấu gạch ngang kép vì nó bắt đầu bằng dấu gạch ngang -optimize
trên .opt
tệp) là một bí danh không có giấy tờ -O
có thể được sử dụng làm --optimize=3
!
OPT_O được sử dụng ở đâu
Bây giờ chúng tôi grep:
git grep -E '\bOPT_O\b'
dẫn chúng ta đến hai tệp:
Đầu tiên chúng ta hãy theo dõi opts.c
opts.c: default_options_optimization
Tất cả các opts.c
tập quán xảy ra bên trong: default_options_optimization
.
Chúng tôi grep backtrack để xem ai gọi hàm này và chúng tôi thấy rằng đường dẫn mã duy nhất là:
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
và main.c
là điểm vào của cc1
. Tốt!
Phần đầu tiên của chức năng này:
- Liệu
integral_argument
trong đó kêu gọi atoi
trên chuỗi tương ứng với OPT_O
phân tích lập luận đầu vào
- lưu trữ giá trị bên trong
opts->x_optimize
ở đâu opts
a struct gcc_opts
.
struct gcc_opts
Sau khi nạp vô ích, chúng tôi nhận thấy rằng điều này struct
cũng được tạo ra tại options.h
:
struct gcc_options {
int x_optimize;
[...]
}
từ đâu x_optimize
đến từ các dòng:
Variable
int optimize
hiện tại common.opt
, và rằng options.c
:
struct gcc_options global_options;
vì vậy chúng tôi đoán rằng đây là thứ chứa toàn bộ trạng thái chung của cấu hình và int x_optimize
là giá trị tối ưu hóa.
255 là mức tối đa nội bộ
in opts.c:integral_argument
, atoi
được áp dụng cho đối số đầu vào, INT_MAX
giới hạn trên cũng vậy. Và nếu bạn đặt bất cứ thứ gì lớn hơn, có vẻ như GCC chạy C hành vi không xác định. Ầm ĩ?
integral_argument
cũng kết thúc mỏng atoi
và bác bỏ đối số nếu bất kỳ ký tự nào không phải là chữ số. Vì vậy, các giá trị âm không thành công một cách duyên dáng.
Quay lại opts.c:default_options_optimization
, chúng ta thấy dòng:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
để mức độ tối ưu hóa được cắt bớt 255
. Trong khi đọc, opth-gen.awk
tôi đã bắt gặp:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
và trên được tạo options.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
điều này giải thích lý do tại sao cắt bớt: các tùy chọn cũng phải được chuyển tiếp tới cl_optimization
, sử dụng a char
để tiết kiệm dung lượng. Vì vậy, 255 là một tối đa nội bộ thực sự.
opts.c: could_default_options
Quay lại opts.c:default_options_optimization
, chúng ta bắt gặp maybe_default_options
cái nào nghe có vẻ thú vị. Chúng tôi nhập nó, và sau đó maybe_default_option
chúng tôi đạt được một công tắc lớn:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
Không có >= 4
séc nào , cho thấy đó 3
là số lớn nhất có thể.
Sau đó, chúng tôi tìm kiếm định nghĩa của OPT_LEVELS_3_PLUS
trong 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! Đây là một chỉ báo mạnh rằng chỉ có 3 cấp độ.
opts.c: default_options_table
opt_levels
rất thú vị, đến mức chúng tôi thu thập OPT_LEVELS_3_PLUS
và bắt gặp 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 },
[...]
}
vì vậy đây là nơi mà -On
ánh xạ tối ưu hóa cụ thể được đề cập trong tài liệu được mã hóa. Đẹp!
Đảm bảo rằng không còn cách sử dụng x_optimize nữa
Cách sử dụng chính của x_optimize
là để đặt các tùy chọn tối ưu hóa cụ thể khác -fdefer_pop
như được ghi lại trên trang chủ. Còn nữa không?
Chúng tôi grep
, và tìm thấy một số khác. Số lượng nhỏ, và khi kiểm tra thủ công, chúng tôi thấy rằng mọi cách sử dụng chỉ thực hiện nhiều nhất là a x_optimize >= 3
, vì vậy kết luận của chúng tôi là đúng.
lto-wrapper.c
Bây giờ chúng ta đi đến sự xuất hiện thứ hai của OPT_O
, đã ở lto-wrapper.c
.
LTO có nghĩa là Tối ưu hóa thời gian liên kết, như tên cho thấy sẽ cần một -O
tùy chọn và sẽ được liên kết với collec2
(về cơ bản là một trình liên kết).
Trên thực tế, dòng đầu tiên lto-wrapper.c
nói:
/* Wrapper to call lto. Used by collect2 and the linker plugin.
Trong tệp này, các OPT_O
lần xuất hiện dường như chỉ chuẩn hóa giá trị của O
để chuyển nó về phía trước, vì vậy chúng ta sẽ ổn.
man gcc
Cygwin (12000 dòng lẻ), bạn có thể tìm kiếm-O
và tìm thấy mọi thứ câu trả lời ở trạng thái bên dưới, và sau đó là một số.