2017-04-26 43 views
7

我是simd初學者,我讀過this關於該主題的文章(因爲我使用的是兼容AVX2的機器)。如何使用這個宏來測試內存是否對齊?

現在,我已閱讀this問題,以檢查指針是否對齊。

我與這個玩具例子main.cpp測試它:

#include <iostream> 
#include <immintrin.h> 

#define is_aligned(POINTER, BYTE_COUNT) \ 
    (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) 


int main() 
{ 
    float a[8]; 
    for(int i=0; i<8; i++){ 
    a[i]=i; 
    } 
    __m256 evens = _mm256_set_ps(2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0); 
    std::cout<<is_aligned(a, 16)<<" "<<is_aligned(&evens, 16)<<std::endl; 
    std::cout<<is_aligned(a, 32)<<" "<<is_aligned(&evens, 32)<<std::endl; 

} 

而且隨着icpc -std=c++11 -o main main.cpp編譯。

所得印刷是:

1 1 
1 1 

但是,如果我的4個打印之前添加thhese 3行:

for(int i=0; i<8; i++) 
    std::cout<<a[i]<<" "; 
std::cout<<std::endl; 

這是結果:

0 1 2 3 4 5 6 7 
1 1 
0 1 

特別,我不明白最後0。爲什麼它與上次打印有所不同?我錯過了什麼?

回答

6

您的is_aligned(它是一個宏而不是函數)決定對象是否已經對齊到特定的邊界。它不確定對象類型的對齊要求。

編譯器將保證浮點數組至少對齊浮點的對齊要求 - 通常爲4. 32不是4的因子,因此不能保證數組是對齊的到32字節邊界。但是,有很多內存地址可以被4和32整除,所以有可能4字節邊界上的內存地址碰巧也是32字節邊界。這是你第一次測試中發生的事情,但正如所解釋的,不能保證它會發生。在你的後一個測試中,你添加了一些局部變量,並且數組結束了另一個內存位置。恰巧另一個內存位置不在32字節邊界。

要申請可以通過SIMD指令所要求的更嚴格的對齊方式,您可以使用alignas符:

alignas(32) float a[8]; 
+0

謝謝您的回答。所以,爲了確保我能夠正確理解:讓我們想象一下,我們可以將內存表示爲連續的塊,每個塊都是4個字節(由'float'變量佔用的空間)。編譯器保證數組與這4個字節塊對齊,所以數組從4個字節塊的開始處開始。但不能保證數組從這個32字節塊(這4個字節塊中的8個)的塊的開始處開始,但它可能偶然發生。那是對的嗎? – cplusplusuberalles

+0

另外一個問題:讓我們假設我有一個具有'float *'作爲輸入參數的函數。我們不知道它是否對齊。我如何使它對齊? PS:讓我知道是否更合適,我打開一個新的問題.. – cplusplusuberalles

+0

@cplusplusuberalles 1.正確2.你當然可以使指針指向另一個對齊的內存地址,但你會怎麼做這樣的指針?考慮一個類似的問題:「我有一個函數有一個int輸入參數,我們不知道它是否可以被2整除。」我怎樣才能使它整除2?「。如果奇數,你可以加1,但就像在指針的情況下一樣:這有用嗎? – user2079303