天天看點

優化級别linux gcc,c - 有多少GCC優化級别?

讓我們解釋一下GCC 5.1的源代碼,看看O上發生了什麼,因為在手冊頁上不清楚。

我們将得出結論:

O以上-O的任何内容與Os相同,但未來可能很容易改變,是以不要依賴它。

如果輸入大于O的整數,GCC 5.1将運作未定義的行為。

參數隻能有數字,或者優雅地失敗。 特别是,這不包括像O這樣的負整數

專注于子程式

首先要記住GCC隻是O,-O,Os,collect2的前端。快速./XXX --help表示隻有collect2和cc1需要-O,是以讓我們關注它們。

和:

gcc -v -O100 main.c |& grep 100

得到:

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.

是以O被轉發到-O和Os。

O在common.opt中

common.opt是内部文檔中描述的GCC特定的CLI選項描述格式,并由opth-gen.awk和optc-gen.awk翻譯為C.

它包含以下有趣的行:

O

Common JoinedOrMissing Optimization

-O Set optimization level to

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

其中指定了所有O選項。 注意-O是如何與其他Os,OPT_O和O分開列入獨立系列的。

當我們建構時,這會生成一個OPT_O檔案,其中包含:

OPT_O = 139,

OPT_Ofast = 140,

OPT_Og = 141,

OPT_Os = 142,

作為獎勵,雖然我們在OPT_O裡面的OPT_O,我們注意到這些線路:

-optimize

Common Alias(O)

它告訴我們OPT_O(輕按兩下,因為它以opts.c:default_options_table檔案中的短劃線O開頭)是-O的無證别名,可以用作--optimize=3!

使用OPT_O的地方

現在我們grep:

git grep -E '\bOPT_O\b'

這指向我們兩個檔案:

opts.c

LTO-wrapper.c

我們先來追蹤OPT_O

opts.c:default_options_optimization

所有OPT_O用法發生在:O。

我們回溯看看誰調用了這個函數,我們看到唯一的代碼路徑是:

OPT_O

OPT_O

OPT_O

OPT_O

和OPT_O是O的切入點。好!

這個功能的第一部分:

OPT_O在對應于opts.c:default_options_table的字元串上調用O來解析輸入參數

将值存儲在OPT_O中,其中O是opts.c:default_options_table。

struct gcc_opts

在徒勞地貪圖之後,我們注意到這個OPT_O也生成于O:

struct gcc_options {

int x_optimize;

[...]

}

其中OPT_O來自以下行:

Variable

int optimize

目前在OPT_O,和O:

struct gcc_options global_options;

是以我們猜測這是包含整個配置全局狀态的,OPT_O是優化值。

255是内部最大值

在OPT_O,O中應用于輸入參數,是以opts.c:default_options_table是上限。 如果你把任何更大的東西,似乎GCC運作C未定義的行為。 哎喲?

OPT_O也會精簡包裝O,如果任何字元不是數字,則拒絕該參數。 是以負值優雅地失敗了。

回到OPT_O,我們看到了這一行:

if ((unsigned int) opts->x_optimize > 255)

opts->x_optimize = 255;

是以優化級别被截斷為OPT_O.在閱讀O時,我遇到過:

# All of the optimization switches gathered together so they can be saved and restored.

# This will allow attribute((cold)) to turn on space optimization.

并在生成的OPT_O上:

struct GTY(()) cl_optimization

{

unsigned char x_optimize;

這解釋了為什麼截斷:選項也必須轉發到OPT_O,它使用O來節省空間。 是以255實際上是一個内部最大值。

opts.c:maybe_default_options

傳回OPT_O,我們看到O,聽起來很有趣。 我們輸入它,然後我們到達一個大開關的opts.c:default_options_table:

switch (default_opt->levels)

{

[...]

case OPT_LEVELS_1_PLUS:

enabled = (level >= 1);

break;

[...]

case OPT_LEVELS_3_PLUS:

enabled = (level >= 3);

break;

沒有OPT_O檢查,這表明O是最大可能的。

在O上搜尋OPT_O的定義:

enum opt_levels

{

OPT_LEVELS_NONE,

OPT_LEVELS_ALL,

OPT_LEVELS_0_ONLY,

OPT_LEVELS_1_PLUS,

OPT_LEVELS_1_PLUS_SPEED_ONLY,

OPT_LEVELS_1_PLUS_NOT_DEBUG,

OPT_LEVELS_2_PLUS,

OPT_LEVELS_2_PLUS_SPEED_ONLY,

OPT_LEVELS_3_PLUS,

OPT_LEVELS_3_PLUS_AND_SIZE,

OPT_LEVELS_SIZE,

OPT_LEVELS_FAST

};

哈! 這是一個強有力的名額,隻有3個級别。

opts.c:default_options_table

OPT_O非常有趣,我們grep O,并且翻譯為opts.c:default_options_table:

static const struct default_options default_options_table[] = {

{ OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },

[...]

{ OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },

[...]

}

是以這是對文檔中提到的特定優化映射進行編碼的OPT_O。太好了!

確定x_optimize沒有更多用途

OPT_O的主要用途是設定其他特定的優化選項,如手冊頁中記錄的O。 還有嗎?

我們OPT_O,并找到更多。 數量很小,經過人工檢查,我們發現每次使用最多隻能進行O,是以我們的結論是成立的。

LTO-wrapper.c

現在我們去第二次出現OPT_O,這是在O。

LTO意味着連結時間優化,顧名思義它将需要OPT_O選項,并且将連結到O(基本上是連結器)。

事實上,第一行OPT_O說:

/* Wrapper to call lto. Used by collect2 and the linker plugin.

在這個檔案中,OPT_O的出現似乎隻是将O的值标準化為向前傳遞,是以我們應該沒問題。