2017-02-09 25 views
0

這是一個關於此post的後續。免責聲明:我已經完成了零分析,甚至沒有應用程序,這純粹是爲了瞭解更多關於矢量化的知識。如何自動矢量化數組比較功能

我的代碼如下。我正在用帶有i3 m370的機器編譯gcc 4.9.4。第一個循環矢量化,如我所料。然而,檢查temp的每個元素的第二個循環不是矢量化的AFAICT,所有的「andb」指令。我預計它將被像_mm_test_all_ones這樣的矢量化。那個循環又如何被矢量化呢?第二個問題,我真的希望這是一個更大的循環的一部分。如果我取消註釋下面的內容,則沒有任何內容被矢量化。我怎樣才能獲得矢量化?

#define ARR_LENGTH 4096 
#define block_size 4 
typedef float afloat __attribute__ ((__aligned__(16))); 

char all_equal_2(afloat *a, afloat *b){ 
    unsigned int i, j; 
    char r = 1; 
    unsigned int temp[block_size] __attribute__((aligned(16))); 
    //for (i=0; i<ARR_LENGTH; i+=block_size){ 

     for (j = 0; j < block_size; ++j) { 
      temp[j] = (*a) == (*b); 
      a++; 
      b++; 
     } 

     for (j=0; j<block_size; j++){ 
      r &= temp[j]; 
     } 

     /*if (r == 0){ 
      break; 
     } 
    }*/ 
    return r; 
} 

並導致組件的關鍵部分:

.cfi_startproc 
    movaps (%rdi), %xmm0 
    cmpeqps (%rsi), %xmm0 
    movdqa .LC0(%rip), %xmm1 
    pand %xmm0, %xmm1 
    movaps %xmm1, -24(%rsp) 
    movl -24(%rsp), %eax 
    andl $1, %eax 
    andb -20(%rsp), %al 
    andb -16(%rsp), %al 
    andb -12(%rsp), %al 
    ret 
    .cfi_endproc 

更新: 這post類似於我的第一個問題。在那個問題中,vector是一個原始指針,所以segfaults是可能的,但這不是一個問題。因此,AFAIK重新排序比較操作在這裏是安全的,但不是在那裏。雖然結論可能是相同的。

回答

1

因此,您的循環安靜得很小並且是遞歸的:迭代N的結果在迭代N + 1中用作輸入。 如果你改變你的第二個循環,讓每ieration 2個操作:

 char r2 = r; 
    for (j=0; j<block_size/2; j+=2){ 
     r &= temp[j]; 
     r2 &=temp[j+1]; 
    } 
    r &= r2; 

,你會看到輸出進行了優化

.cfi_def_cfa_register %rbp 
vmovss (%rdi), %xmm0   ## xmm0 = mem[0],zero,zero,zero 
vmovss 4(%rdi), %xmm1   ## xmm1 = mem[0],zero,zero,zero 
vucomiss (%rsi), %xmm0 
sete %al 
vucomiss 4(%rsi), %xmm1 
sete %cl 
andb %al, %cl 
movzbl %cl, %eax 
popq %rbp 
retq 
.cfi_endproc 

對於最後一點,與優化的代碼和外環使我看到一些優化。你有沒有改變編譯選項?

+0

使用和不使用外循環,我現在用的編譯器標誌是 「-O3 -fopt-INFO-VEC優化」。當然,gcc進行了一些優化,但是特定於向量化沒有循環優化,外部循環未註釋,如fopt-info所報告。另外我的白癡的檢查向量化浮動指南是尋找一堆* ps指令,並且沒有任何一次外部循環被包括 – user2133814

1

Autovectorization真的很喜歡減少操作,所以訣竅是把它變成減少。

#define ARR_LENGTH 4096 
typedef float afloat __attribute__ ((__aligned__(16))); 
int foo(afloat *a, afloat *b){ 
    unsigned int i, j; 
    unsigned int result; 
    unsigned int blocksize = 4; 
    for (i=0; i<ARR_LENGTH; i+=blocksize){ 
     result = 0; 
     for (j=0; j<blocksize; j++){ 
      result += (*a) == (*b); 
      a++; 
      b++; 
     } 
     if (result == blocksize){ 
      blocksize *= 2; 
     } else { 
      break; 
     } 
    } 
    blocksize = ARR_LENGTH - i; 
    for (i=0; i<blocksize; i++){ 
     result += (*a) == (*b); 
     a++; 
     b++; 
    } 
    return result == i; 
} 

編譯成一個漂亮的循環:

.L3: 
     movaps (%rdi,%rax), %xmm1 
     addl $1, %ecx 
     cmpeqps (%rsi,%rax), %xmm1 
     addq $16, %rax 
     cmpl %r8d, %ecx 
     psubd %xmm1, %xmm0 
     jb  .L3