簡體   English   中英

如何使用仿函數對循環進行矢量化?

[英]How do I vectorize loop with functors?

我使用一些使用一些容器來存儲數據的類; 有多維容器的類。 這些類重載operator ()以索引數據。 我在循環中使用了很多這樣的對象,並希望對它們進行矢量化。 海灣合作委員會無法直接對其進行矢量化; 它說“在基本塊中找不到SLP機會”並且駁回了矢量化。
我將如何進行矢量化代碼?

我還沒有與其他編譯器一起檢查,因為我希望這可以被少數使用中的着名編譯器進行矢量化。

首先,我同意評論說如果你打算成功地對你的循環進行矢量化,你必須“非常接近地管理你的記憶”。 如果不知道這一點 - 請參閱本答案末尾的腳注,以獲得關於內存對齊的簡短而膚淺的介紹。

然而,即使你的記憶很好地對齊,也有可能讓你退縮。 Georg Hager和Gerhard Wellein是受人尊敬的着作“科學家和工程師高性能計算簡介”的作者,他明確表示C ++運算符重載可能會阻止循環向量化

用他們自己的話說:

“(....)STL可以通過以下方式定義此運算符(改編自GNU ISO C ++庫源):

const T& operator[](size_t __n) const{ return *(this->_M_impl._M_start + __n); } 

雖然這看起來很簡單,可以有效地內聯,但是當前的編譯器拒絕將SIMD矢量化應用於上面的求和循環。 單層抽象,在這種情況下是一個重載索引操作符,因此可以防止創建最佳循環代碼。“

一位好朋友讓我相信,對於stl容器來說,這實際上並不正確,因為編譯器可以消除與operator[]相關的間接層。 但是,您似乎編寫了自己的容器,因此必須檢查編譯器是否可以消除與您自己的operator()關聯的間接層! 一個好的交叉檢查是為你自己提供一種方法來直接處理你的容器所擁有的底層數組(意思是:編寫一個類似於std::vector.data()的成員函數,並使用C指針作為你內部的“迭代器”循環)。

關於內存對齊的腳注:

問題:假設你想要矢量化c[i] = a[i] + b[i]

第一個事實: size(double) = 8個字節= 64位。

第二個事實:有一個匯編指令在內存中讀取2個雙精度數並將它們放在128位寄存器=>一個匯編指令,你可以讀取2個雙精度數據=>它們可以讀取a[0]a[1]然后b[0]b[1]

第三個事實:當您在寄存器上應用指令時,您可以同時將兩個64位的和double

問題是只有當a[0]b[0]的內存地址是16的倍數時,程序集才能同時讀取a[0]a[1] (如果不是,他可以測試如果a[1]b[1]是對齊等等)。 這就是為什么內存可能成為阻止矢量化的問題。 要解決這個問題,您必須編寫容器分配器,以確保容器的第一個元素將寫入16的倍數的內存地址。

更新: 此答案提供了有關如何編碼對齊內存的分配器的詳細說明。

更新2:學習如何編碼分配器的另一個有用的答案

更新3:使用posix_memalign / _aligned_malloc的替代方法

暫無
暫無

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

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