簡體   English   中英

如何將__attribute __((aligned(32)))應用於int *?

[英]How can I apply __attribute__(( aligned(32))) to an int *?

在我的程序中,我需要將__attribute__(( aligned(32)))應用於int *float *我試過這樣但我不確定它是否會起作用。

int  *rarray __attribute__(( aligned(32)));

我看到了這個,但沒有找到答案

所以你想告訴編譯器你的指針是對齊的嗎? 例如,此函數的所有調用者都將傳遞保證對齊的指針。 指向對齊靜態或本地存儲的指針,或指向C11 aligned_alloc或POSIX posix_memalign指針。 (如果那些不可用, _mm_malloc是一個選項,但在_mm_malloc結果上不保證free是安全的:你需要_mm_free )。 這允許編譯器自動向量化,而無需使用一堆膨脹代碼來處理未對齊的輸入。

使用內在函數手動矢量化時,使用_mm256_loadu_si256_mm256_load_si256通知編譯器內存是否已對齊。 傳遞對齊信息是加載/存儲內在函數的主要點,而不是簡單地解引用__m256i指針。


我不認為有一種可移植的方式來通知編譯器指針指向對齊的內存。 (C11 / C ++ 11 alignas似乎無法做到這一點,見下文)。

使用GNU C __attribute__語法 ,似乎有必要使用typedef來獲取要應用於指向類型的屬性,而不是指針本身。 如果你聲明一個aligned_int類型或類似的東西,它肯定更容易鍵入和更容易閱讀

// Only helps GCC, not clang or ICC
typedef __attribute__(( aligned(32)))  int aligned_int;
int my_func(const aligned_int *restrict a, const aligned_int *restrict b) {
    int sum = 0;
    for (int i=0 ; i<1024 ; i++) {
        sum += a[i] - b[i];
    }
    return sum;
}

自動向量化而沒有任何膨脹用於處理未對齊的輸入(GCC 5.3 -O3上godbolt)

    pxor    xmm0, xmm0
    xor     eax, eax
.L2:
    psubd   xmm0, XMMWORD PTR [rsi+rax]
    paddd   xmm0, XMMWORD PTR [rdi+rax]
    add     rax, 16
    cmp     rax, 4096
    jne     .L2          # end of vector loop

    ...   # horizontal sum with psrldq omitted, see the godbolt link if you're curious
    movd    eax, xmm0
    ret

如果沒有aligned屬性,你會得到一大塊標量intro / outro代碼,這會更糟糕的是-march=haswell使AVX2代碼具有更寬的內循環。


Clang對未對齊輸入的常規策略是使用未對齊的加載/存儲,而不是完全展開的intro / outro循環。 如果沒有AVX,這意味着無法將負載折疊到SSE ALU操作的內存操作數中。

aligned屬性沒有幫助clang(最近測試為clang7.0):它仍然使用單獨的movdqu加載。 請注意,clang的循環更大,因為它默認為展開4,而gcc不會在沒有-funroll-loops (由-fprofile-use啟用)的情況下展開。

但請注意,此aligned_int typedef 適用於GCC本身,不適用於clang或ICC gcc memory alignment pragma有另一個例子。

__builtin_assume_aligned是更嘈雜的語法,但適用於所有支持GNU C擴展的編譯器。

請參閱如何告訴GCC指針參數始終是雙字對齊的?


請注意,您不能創建一個aligned_int數組 (請參閱有關sizeof(aligned_int)討論的評論,以及它仍為4,而不是32的事實)。 GNU C拒絕將其視為帶有填充的int ,因此使用gcc 5.3:

static aligned_int arr[1024];
// error: alignment of array elements is greater than element size
int tmp = sizeof(arr);

clang-3.8編譯它,並將tmp初始化為4096.大概是因為它只是完全忽略了該上下文中的aligned屬性,沒有做任何魔法gcc所做的任何一種類型比它所需的對齊更窄的類型。 (因此,只有每四個元素實際上具有該對齊。)

gcc文檔聲稱在結構上使用aligned屬性可以讓你創建一個數組,這是主要的用例之一。 但是,正如@ user3528438在注釋中指出的那樣, 情況並非如此 :您在嘗試聲明一個aligned_int數組時會遇到相同的錯誤。 自2005年以來就是如此。


要定義對齊的局部或靜態/全局數組aligned屬性應該應用於整個數組,而不是應用於每個元素。

在便攜式C11和C ++ 11中,你可以使用像alignas(32) int myarray[1024]; 另請參閱使用alignas語法進行拼寫 :它似乎僅用於對齊事物本身,而不是聲明指針指向對齊的內存。 std::align更像是((uintptr_t)ptr) & ~63或者其他東西:強制對齊指針而不是告訴編譯器它已經對齊了。

// declaring aligned storage for arrays
#ifndef __cplusplus
#include <stdalign.h>   // for C11: defines alignas() using _Alignas()
#endif                  // C++11 defines alignas without any headers

// works for global/static or local  (aka automatic storage)
alignas(32) int foo[1000];      // portable ISO C++11 and ISO C11 syntax


// __attribute__((aligned(32))) int foo[1000];  // older GNU C
// __declspec something  // older MSVC

有關cppreference的信息,請參閱C11 alignas()文檔

如果您希望在不支持C11的舊編譯器上實現可移植性,則CPP宏可用於在GNU C __attribute__語法和MSVC __declspec語法之間進行選擇。

例如,使用此代碼聲明一個局部數組具有比堆棧指針更多的對齊,編譯器必須創建空間,然后使用AND指向堆棧指針以獲得對齊的指針:

void foo(int *p);
void bar(void) {
  __attribute__((aligned(32))) int a[1000];
  foo (a);
}

編譯為(clang-3.8 -O3 -std=gnu11 for x86-64)

    push    rbp
    mov     rbp, rsp       # stack frame with base pointer since we're doing unpredictable things to rsp
    and     rsp, -32       # 32B-align the stack
    sub     rsp, 4032      # reserve up to 32B more space than needed
    lea     rdi, [rsp]     # this is weird:  mov rdi,rsp  is a shorter insn to set up foo's arg
    call    foo
    mov     rsp, rbp
    pop     rbp
    ret

gcc(晚於4.8.2)使得大量代碼無緣無故地進行了大量的額外工作,最奇怪的是push QWORD PTR [r10-8]將一些堆棧內存復制到堆棧上的另一個位置。 (在godbolt鏈接上查看:翻轉到gcc)。

暫無
暫無

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

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