簡體   English   中英

哪個gcc的-O3優化標志啟用“硬件加速指令”

[英]Which of gcc's -O3 optimization flags enable “hardware accelerated instructions”

所以基本上,對於我的項目,有一個限制,它不能使用-O3標志(我們必須只使用-O2)。 這樣做的原因是-O3標志顯然引入了“硬件加速指令”。

gcc版本是5.4,此版本的優化標志的手冊頁是: this

我希望盡可能多地包含-O3的標志。 -O3引入的標志列表是:

-finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-loop-distribute-patterns, -ftree-slp-vectorize, -fvect-cost-model, -ftree-partial-pre and -fipa-cp-clone

所以我打算使用-O2並手動包含盡可能多的上述標志。

上面哪些標志啟用“硬件加速指令”優化? 如何通過閱讀描述來判斷標志是否啟用“硬件加速指令”優化? 是什么構成的?

使用的指令集由-march控制,而不是由-O3 確實-O3可以更多地使用SIMD指令進行矢量化,但是-O3在代碼生成期間沒有特別添加或刪除指令。

如果您只想使用最簡單的說明編譯代碼,請為您的平台選擇最簡單的march 例如, -march=core2對於x86-64來說是一個保守的選擇,因為它指的是相當陳舊的英特爾酷睿2處理器系列。

Core 2支持MMX和SSE到SSE3和SSSE3。 要禁用它們,請添加:

-mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-ssse3

我覺得約翰已經回答了這個問題,我會嘗試提供一些例子。

考慮遵循最小程序:

#include <cstring>

void copy(long *dst , const long *src)
{
    std::memcpy(dst, src, sizeof(long) * 4);
}

在G86_64上用GCC 7.2 g++ -O2編譯得到以下輸出:

copy(long*, long const*):
  movdqu (%rsi), %xmm0
  movups %xmm0, (%rdi)
  movdqu 16(%rsi), %xmm0
  movups %xmm0, 16(%rdi)
  ret

g++ -O2 -mno-sse上用GCC 7.2 g++ -O2 -mno-sse編譯得到以下輸出:

copy(long*, long const*):
  movq (%rsi), %rax
  movq %rax, (%rdi)
  movq 8(%rsi), %rax
  movq %rax, 8(%rdi)
  movq 16(%rsi), %rax
  movq %rax, 16(%rdi)
  movq 24(%rsi), %rax
  movq %rax, 24(%rdi)
  ret

如您所見,GCC即使在-O2級別也能生成SSE指令。 需要單獨的標志來禁止生成這些指令。

同時,GCC 5.4使用和不使用-mno-sse標志生成相同的代碼,但它也對-O3優化級別執行相同的操作。

所以你的目標在這里有點誤導。 在某些情況下,使用-O2標志的超集可能會抑制SSE和類似指令的生成,但這並不能保證,因為優化級別僅與生成的指令間接相關。 如果你真的想要壓制它們,你可以使用-mno-sse標志,但這可能會使你處於劣勢。 堅持使用-O2 - 這樣每個人都會平等。

我使用https://godbolt.org/來證明這一點。

我想補充幾個。

你的助教說:

使用-O3可以啟用硬加速指令,例如SSE

我認為這不是真的正確。 似乎-f選項旨在與機器無關。 編譯器解析源代碼並將其轉換為通常稱為中間表示(IR)的東西。 接下來,編譯器優化IR本身,即所謂的機器獨立。 然后,從優化的IR生成匯編代碼。 生成程序集時,將應用一組不同的優化。 IR的例子是LLVM IR,Sun IR,GCC gimple tree和/或RTL等。我相信所有現代編譯器都有IR(s)。

我認為,GCC的-f選項基本上是與機器無關的。 -m選項用於依賴於機器的優化。 -O2或-O3確定-f選項,理想情況下與機器無關。 使用花哨的指令取決於編譯器的機器相關部分。

實際上,機器相關和機器無關的世界之間的邊界線可能不是很清楚。

由-O3打開的矢量化將是灰色區域中的優化的示例。 有些機器不支持SIMD。 例如,有些但矢量大小與架構不同。 這是我的示例代碼:

// code.c
long long int inner_product(int* v0, int* v1, int sz) {
    long long int res = 0;
    for (int i = 0; i < sz; i++) {
        res += (v0[i] * v1[i]);
    }
    return res;
}

如果編譯如下:

$ gcc  -O3 -S -march=core2  code.c  -o code.s  -fdump-tree-all 

Gcc矢量化它,但矢量大小為2 long long int或4 int:

$ cat code.*.optimized | grep 'vector('
vector(2) long long int vect_res_16.21;
vector(2) long long int vect_res_16.19;
vector(2) long long int vect__8.18;
vector(4) int vect__7.17;
vector(4) int vect__6.16;
vector(4) int * vectp_v1.15;
vector(4) int vect__4.13;
vector(4) int * vectp_v0.12;

另一方面,如果使用-march = skylake-avx512編譯,其矢量大小是core2的4倍,結果將是:

$ gcc  -O3 -S -march=skylake-avx512  code.c  -o code.s  -fdump-tree-all && cat code.*.optimized | grep 'vector('
vector(8) long long int vect_res_16.21;
vector(8) long long int vect_res_16.19;
vector(8) long long int vect__8.18;
vector(16) int vect__7.17;
vector(16) int vect__6.16;
vector(16) int * vectp_v1.15;
vector(16) int vect__4.13;
vector(16) int * vectp_v0.12;

請注意,此時代碼生成尚未開始。 根據行軍價值,IR看起來不同。 我猜矢量化不是顯示這種行為的唯一例子。

盡管如此,我認為將這種優化稱為機器依賴是不公平的。 典型的機器相關優化是指令調度。 它幾乎與中間表示無關。 它更多地是關於機器指令和微架構。 對於灰色區域中與機器無關的優化,從概念上講,編譯器可以生成統一的矢量化IR(例如,使矢量大小始終為4),並讓代碼生成器處理它(每個代碼生成器可能需要合並或拆分矢量操作數)。 然而,在實現中,給予向量操作數適當的大小在IR級別比在代碼生成級別更容易。 所以,我猜人們放棄了生活在“思想”的世界。 盡管如此,我認為與機器無關的優化可以稱為與機器無關。

您可能需要詢問TA不希望看到的那種花哨的指示。 如果這只是向量指令,則應禁用所有與向量相關的標志,但可以使用-O3。 我的示例代碼可用於查看是否仍有SIMD指令:

$ gcc -O3 -S code.c
$ cat code.s | egrep xmm

如果輸出為空,那你很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM