2012-06-18 13 views
11

私は1次元配列を16バイトメモリに合わせる必要があるコードにSSEベクトル化を実装しようとしています。しかし、私は16バイトのメモリアライメントされたデータを割り当てるいくつかの方法を試しましたが、4バイトのメモリが整列してしまいます。16バイトのメモリアライメントデータを割り当てる方法

私はIntel iccコンパイラで作業する必要があります。 は、これは私がテストしていたサンプルコードです:

#include <stdio.h> 
    #include <stdlib.h> 

    void error(char *str) 
    { 
    printf("Error:%s\n",str); 
    exit(-1); 
    } 

    int main() 
    { 
    int i; 
    //float *A=NULL; 
    float *A = (float*) memalign(16,20*sizeof(float)); 

    //align 
    // if (posix_memalign((void **)&A, 16, 20*sizeof(void*)) != 0) 
    // error("Cannot align"); 

    for(i = 0; i < 20; i++) 
     printf("&A[%d] = %p\n",i,&A[i]); 

     free(A); 

     return 0; 
    } 

これは、私が手に出力されます:

&A[0] = 0x11fe010 
&A[1] = 0x11fe014 
&A[2] = 0x11fe018 
&A[3] = 0x11fe01c 
&A[4] = 0x11fe020 
&A[5] = 0x11fe024 
&A[6] = 0x11fe028 
&A[7] = 0x11fe02c 
&A[8] = 0x11fe030 
&A[9] = 0x11fe034 
&A[10] = 0x11fe038 
&A[11] = 0x11fe03c 
&A[12] = 0x11fe040 
&A[13] = 0x11fe044 
&A[14] = 0x11fe048 
&A[15] = 0x11fe04c 
&A[16] = 0x11fe050 
&A[17] = 0x11fe054 
&A[18] = 0x11fe058 
&A[19] = 0x11fe05c 

それは4バイト整列毎回ですが、私はあるmemalign、POSIXであるmemalignの両方を使用しています。私はLinuxで作業しているので、_mm_mallocを使用することはできません。どちらも_aligned_mallocを使用することはできません。 _aligned_attributeを使用しようとするとメモリの破損エラーが発生します(これはgccだけに適しています)。

Linuxプラットフォームでicc用に16バイトのメモリアラインメントデータを正確に生成するのに助けてくれる人は誰でも助けてくれますか?

+0

printfが一度に4バイトしか出力しないので、それが4バイト整列であることをどのように知っていますか?ちょうどあなたがmemalignルーチンを使用しているので、あなたは浮動小数点型に入れています。 printfを使用して印刷する場合、プリミティブ型(float)を処理する方法を知っています。 – trumpetlicks

+1

Linuxで "_mm_malloc"を使用できないのはなぜですか? –

答えて

14

割り当てるメモリは16バイトです。
&A[0] = 0x11fe010
floatの配列では、各要素は4バイトなので、2番目の要素は4バイトに整列しています。私はWikipediaにこのコードを見つけ

struct x { 
    float y; 
} __attribute__((aligned(16))); 
struct x *A = memalign(...); 
+0

'__attribute__'はGCCの組み込みであり、ICCでは利用できません。 – Benoit

+0

@Benoit、確かにGCC特有ですが、ICCはそれをサポートしていると思います。 [参照してください](http://software.intel.com/sites/products/collat​​eral/hpc/compilers/intel_linux_compiler_compatibility_with_gnu_compilers.pdf) – ugoren

+0

@Benoit:16に構造体を配置する必要がある場合は、12バイトのパディングを追加してください終わり... –

0

Example: get a 12bit aligned 4KBytes buffer with malloc() 

// unaligned pointer to large area 
void *up=malloc((1<<13)-1); 
// well aligned pointer to 4KBytes 
void *ap=aligntonext(up,12); 

where aligntonext() is meant as: 
move p to the right until next well aligned address if 
not correct already. A possible implementation is 

// PSEUDOCODE assumes uint32_t p,bits; for readability 
// --- not typesafe, not side-effect safe 
#define alignto(p,bits) (p>>bits<<bits) 
#define aligntonext(p,bits) alignto((p+(1<<bits)-1),bits) 
7

memalignによって返されたアドレス

あなたはaligned属性で、それぞれが単一のfloatを含む、構造体の配列を使用することができます関数は0x11fe010であり、これは0x10の倍数です。機能は正しいことをしています。これは、配列が16バイトの境界に正しく整列していることを意味します。後でやっていることは、配列内のすべての次の要素のアドレスfloatを印刷することです。あなたのケースではfloatのサイズはちょうど4バイトなので、次のアドレスはすべて前のアドレス+4と同じになります。たとえば、0x11fe010 + 0x4 = 0x11FE014です。もちろん、アドレス0x11FE0140x10の倍数ではありません。すべての浮動小数点数を16バイト境界に揃える場合は、要素あたり16/4 - 1バイトを無駄にする必要があります。使用している組み込み関数の要件を再確認してください。

1

AFAIK、memalignposix_memalignの両方が仕事をしています。

&A[0] = 0x11fe010 

これは16バイトに揃えられています。

あなたが floatポインタに一つの位置を追加するcompillerを言っているん &A[1]
&A[1] = 0x11fe014 

。あなたは16バイトにアラインあなたのベクトル内のすべてのの要素を持っているしたい場合、あなたは16バイト幅のある構造体の配列を宣言する検討すべきである

&A[0] + sizeof(float) = 0x11fe010 + 4 = 0x11fe014 

:それは不可避的につながります。

struct float_16byte 
{ 
    float data; 
    float padding[ 3 ]; 
} 
    A[ ELEMENT_COUNT ]; 

次にあなたがELEMENT_COUNT(20、あなたの例では)変数のためのメモリを割り当てる必要があります。

struct float_16byte *A = (struct float_16byte *)memalign(16, ELEMENT_COUNT * sizeof(struct float_16byte)); 
0

私は個人的にあなたのコードが正しいとIntel SSEコードに適していると考えています。 XMMレジスタにデータをロードするとき、プロセッサはメインメモリから連続した4つの浮動小数点データをロードすることができます。最初の浮動小数点データは16バイトで整列します。

要するに、あなたがしたことはまさにあなたが望むものだと思います。