2016-07-13 71 views
3

您好,我有一個AVX2內部函數的奇怪問題。我用int64_t * cast創建一個指向_m256i向量的指針。然後我通過取消引用指針來分配一個值。奇怪的是,在向量變量中沒有觀察到該值,除非我在它後面運行一些cout語句。指針和向量具有相同的內存地址,並且取消引用指針會生成正確的值,但向量不會。我錯過了什麼?int64_t指針轉換爲AVX2內部_m256i

// Vector Variable 
__m256i R_A0to3 = _mm256_set1_epi32(0xFFFFFFFF); 

int64_t *ptr = NULL; 
for(int m=0; m<4; m++){ 
    // Cast pointer to vector type 
    ptr = (int64_t*)&R_A0to3; 

    cout<<"ptr_ADDRESS:  "<<ptr<<endl; 
    cout<<"&R_A0to3_ADDRESS: "<<&R_A0to3<<endl; 

    // access 
    ptr[m] = (int64_t) m_array[m]; 

    // generic function that prints out register 
    print_mm256_reg<int64_t>(R_A0to3, "R_A0to3"); 
    cout<<"m_array: "<< m_array[m]<<std::ends; 

    // Additional print statements 
    cout<<"ptr[m]: "<< ptr[m]<<std::endl; 
    cout<<"ptr[0]: "<< ptr[0]<<std::endl; 
    cout<<"ptr[1]: "<< ptr[1]<<std::endl; 
    cout<<"ptr[2]: "<< ptr[2]<<std::endl; 
    cout<<"ptr[3]: "<< ptr[3]<<std::endl; 
    print_mm256_reg<int64_t>(R_A0to3, "R_A0to3"); 
} 

Output: 
ptr_ADDRESS  0x7ffd9313e880 
&R_A0to3_ADDRESS 0x7ffd9313e880 
m_array: 8 
printing reg - R_C0to3 -1| -1| -1| -1| 
printing reg - R_D0to3 -1| -1| -1| -1| 

Output with Additional print statements: 
ptr_ADDRESS  0x7ffd36359e20 
&R_A0to3_ADDRESS 0x7ffd36359e20 
printing reg - R_A0to3  -1| -1| -1| -1| 
m_array: 8 

ptr[0]: 8 
ptr[1]: -1 
ptr[2]: -1 
ptr[3]: -1 
printing reg - R_A0to3  8| -1| -1| -1| 
+2

這是什麼編譯器?我認爲這是海灣合作委員會中的一個角落案件,即使他們不應該這樣做,嚴格別名違規實際上也會造成問題。 (SIMD類型聲明爲'__may_alias__'。)您是否嘗試禁用嚴格別名? 「-Wstrict-aliasing」是否會讓它投訴? – Mysticial

+1

@Mysticial:或許編譯器放棄保持變量的一致性,因爲程序有未定義的行爲?對於m = 4..9訪問'__m256i R_A0to3'外的'ptr [m]'。無論如何,這是使用向量的一種愚蠢的方式。不要這樣做。如果你真的想存儲到一個緩衝區並修改一個向量,那麼編寫這樣的代碼然後重新加載向量。或者可能使用聯盟。使用指針進行類型竄改並不是一個好習慣。 –

+0

@PeterCordes啊哈,你是對的!我沒有看到它出界。 – Mysticial

回答

2

我建議使用_mm256_extract_epi64_mm256_insert_epi64內部函數,當您需要單個元素偶爾訪問。如果您需要訪問矢量中的所有元素,請考慮使用_mm256_store_si256_mm256_lddqu_si256來存儲和加載它。這些內在函數不太可能依賴未定義的行爲,並且它們對於正在生成的機器指令(以及性能)是透明的。

+0

如果您需要將所有元素作爲單獨的標量,則存儲到本地數組並不是一個錯誤的選項。你可能會得到比提取更好的代碼。或者使用聯合來代替指針轉換,因爲IIRC,GNU C保證基於聯合的類型雙向工作。 (我認爲在其他不支持GNU C擴展的x86編譯器上也是安全的。) –

+0

「或者使用聯合來代替指針轉換進行類型轉換,因爲IIRC,GNU C保證基於聯合的類型轉換(我認爲在其他不支持GNU C擴展的x86編譯器上也是安全的)。「在這種情況下,我認爲你幾乎不知道編譯器會如何實現它......可能會有存儲和加載儘管我可能是錯的。這可能是也可能不是你想要的。 –

+0

[gcc商店/重新加載,clang使用提取指令](https://godbolt.org/g/oqFjDE)。這只是gcc的遺漏優化;但IDK多久會得到修復。顯然,無論哪種方式性能都很差(尤其是存儲/修改/重裝存儲轉發失敗),所以主要應用於諸如調試打印之類的東西。我沒有意識到'_mm256_extract_epi64'存在/工作於上層元素,因爲['vpextrq'](http://www.felixcloutier.com/x86/PEXTRB:PEXTRD:PEXTRQ.html)沒有,所以這很方便。另外,'_mm256_lddqu_si256'是毫無意義的;只需使用'loadu'。 (或者如果對齊,我猜)。 「 –