2016-07-13 23 views
3

Hallo Ich habe ein seltsames Problem mit AVX2 intrinsics. Ich erstelle einen Zeiger auf einen _m256i Vektor mit einer int64_t * Besetzung. Ich weise dann einen Wert zu, indem ich den Zeiger dereferenziere. Das Seltsame ist, dass der Wert in der Vektorvariablen nicht beobachtet wird, es sei denn, ich führe ein paar Cout-Anweisungen danach aus. Der Zeiger und der Vektor haben die gleiche Speicheradresse, und bei der Dereferenzierung erzeugt der Zeiger den richtigen Wert, der Vektor jedoch nicht. Was vermisse ich?int64_t Zeiger auf AVX2 intrinsisch _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

Welcher Compiler ist das? Ich glaube, dass dies einer der Eckfälle in GCC ist, wo eine strenge Aliasing-Verletzung tatsächlich Probleme verursachen wird, obwohl sie dies nicht tun sollten. (SIMD-Typen werden als '__may_alias__' deklariert.) Haben Sie versucht, das strikte Aliasing zu deaktivieren? Verursacht '-Wstrict-Aliasing' eine Beschwerde? – Mysticial

+1

@Mysticial: Vielleicht gibt der Compiler auf, die Variablen kohärent zu halten, weil das Programm undefiniertes Verhalten hat? 'ptr [m]' für m = 4..9 greift außerhalb von '__m256i R_A0to3' zu. In jedem Fall ist dies eine alberne Art, Vektoren zu verwenden. Tu das nicht. Wenn Sie wirklich in einem Puffer speichern und einen Vektor ändern möchten, schreiben Sie Code, der das tut, und lädt den Vektor anschließend neu. Oder möglicherweise eine Union verwenden. Typ-Punning mit Pointer-Casts ist kein gutes Idiom. –

+0

@PeterCordes Aha, du hast Recht! Ich habe nicht gesehen, dass es außerhalb der Grenzen ging. – Mysticial

Antwort

2

Ich schlage vor, die _mm256_extract_epi64 und _mm256_insert_epi64 intrinsics verwenden, wenn Sie gelegentlich Zugriff auf einzelne Elemente benötigen. Wenn Sie auf alle Elemente aus dem Vektor zugreifen müssen, sollten Sie die Dateien _mm256_store_si256 und _mm256_lddqu_si256 zum Speichern und Laden verwenden. Diese intrinsischen Eigenschaften sind weniger auf ein undefiniertes Verhalten angewiesen und sie sind transparent hinsichtlich der erzeugten Maschinenanweisungen (und somit bezüglich der Leistung).

+0

Wenn Sie alle Elemente als separate Skalare benötigen, ist das Speichern in einem lokalen Array keine schlechte Option. Sie erhalten wahrscheinlich besseren Code als mit Extrakten. Oder verwenden Sie eine Union für Typ-Punning anstelle von Pointer-Casting, da IIRC, GNU C garantiert, dass Union-basierte Typ-Punning funktioniert. (Ich denke, es ist sicher auf anderen x86-Compiler, die nicht auch die Erweiterungen GNU C unterstützen.) –

+0

"Oder verwenden Sie eine Union für Typ-Punning anstelle von Pointer-Casting, da IIRC, GNU C garantiert, dass Union-basierte Typ- punning funktioniert. (Ich denke, es ist sicher auf anderen x86-Compilern, die nicht auch die GNU C-Erweiterungen unterstützen.) "In diesem Fall denke ich, Sie haben wenig Ahnung, wie der Compiler es implementieren wird ... wahrscheinlich mit Stores und Loads obwohl ich falsch liegen könnte. Das kann oder darf nicht sein, was Sie wollen. –

+0

[gcc speichert/lädt neu, clang verwendet Anweisungen zum Extrahieren] (https://godbolt.org/g/oqFjDE). Das ist nur eine verpasste Optimierung von gcc; aber IDK, wie bald wird es behoben werden. Offensichtlich ist eine der beiden Möglichkeiten eine ziemlich niedrige Performance (vor allem store/modify/reload store-forwarding failure), sollte also hauptsächlich für Dinge wie Debug-Prints verwendet werden. Ich hatte nicht realisiert, dass '_mm256_extract_epi64' auf oberen Elementen existierte/arbeitete, weil [' vpextrq'] (http://www.felixcloutier.com/x86/PEXTRB:PEXTRD:PEXTRQ.html) nicht funktioniert, also ist das praktisch. Außerdem ist '_mm256_lddqu_si256' sinnlos; benutze einfach 'loadu'. (oder "load" wenn ausgerichtet, denke ich). –