Nous utilisons l'assemblage en ligne pour rendre les instructions SHA disponibles si __SHA__
n'est pas défini. Sous GCC nous utilisons:Travailler autour de l'absence de contrainte de machine Yz sous Clang?
GCC_INLINE __m128i GCC_INLINE_ATTRIB
MM_SHA256RNDS2_EPU32(__m128i a, const __m128i b, const __m128i c)
{
asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "Yz" (c));
return a;
}
Clang ne consomme pas de GCC Yz
constraint (voir Clang 3.2 Issue 13199 et Clang 3.9 Issue 32727), qui est requis par l'instruction sha256rnds2
:
Yz First SSE register (%xmm0).
Nous avons ajouté un mov
pour Clang :
asm ("mov %2, %%xmm0; sha256rnds2 %%xmm0, %1, %0" : "+x"(a) : "xm"(b), "x" (c) : "xmm0");
La performance est désactivée d'environ 3 cycles par octet. Sur ma machine de test Celeron J3455 2,2 GHz (Goldmont avec extensions SHA), cela représente environ 230 Mio/s. C'est non trivial.
En regardant le démontage, Clang n'optimise autour SHA de k
lorsque deux tours sont effectués:
Breakpoint 2, SHA256_SSE_SHA_HashBlocks (state=0xaaa3a0,
data=0xaaa340, length=0x40) at sha.cpp:1101
1101 STATE1 = _mm_loadu_si128((__m128i*) &state[4]);
(gdb) disass
Dump of assembler code for function SHA256_SSE_SHA_HashBlocks(unsigned int*, unsigned int const*, unsigned long):
0x000000000068cdd0 <+0>: sub $0x308,%rsp
0x000000000068cdd7 <+7>: movdqu (%rdi),%xmm0
0x000000000068cddb <+11>: movdqu 0x10(%rdi),%xmm1
...
0x000000000068ce49 <+121>: movq %xmm2,%xmm0
0x000000000068ce4d <+125>: sha256rnds2 %xmm0,0x2f0(%rsp),%xmm1
0x000000000068ce56 <+134>: pshufd $0xe,%xmm2,%xmm3
0x000000000068ce5b <+139>: movdqa %xmm13,%xmm2
0x000000000068ce60 <+144>: movaps %xmm1,0x2e0(%rsp)
0x000000000068ce68 <+152>: movq %xmm3,%xmm0
0x000000000068ce6c <+156>: sha256rnds2 %xmm0,0x2e0(%rsp),%xmm2
0x000000000068ce75 <+165>: movdqu 0x10(%rsi),%xmm3
0x000000000068ce7a <+170>: pshufb %xmm8,%xmm3
0x000000000068ce80 <+176>: movaps %xmm2,0x2d0(%rsp)
0x000000000068ce88 <+184>: movdqa %xmm3,%xmm4
0x000000000068ce8c <+188>: paddd 0x6729c(%rip),%xmm4 # 0x6f4130
0x000000000068ce94 <+196>: movq %xmm4,%xmm0
0x000000000068ce98 <+200>: sha256rnds2 %xmm0,0x2d0(%rsp),%xmm1
...
Par exemple, 0068ce8c
si 0068ce98
aurait dû être:
paddd 0x6729c(%rip),%xmm0 # 0x6f4130
sha256rnds2 %xmm0,0x2d0(%rsp),%xmm1
Je devine notre choix d'instructions asm en ligne est un peu éteint.
Comment pouvons-nous contourner l'absence de contrainte machine Yz
sous Clang? Quel modèle évite le déplacement intermédiaire en code optimisé?
Toute tentative d'utilisation Explicit Register Variable:
const __m128i k asm("xmm0") = c;
asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "x" (k));
return a;
Résultats dans:
In file included from sha.cpp:24:
./cpu.h:831:22: warning: ignored asm label 'xmm0' on automatic variable
const __m128i k asm("xmm0") = c;
^
./cpu.h:833:7: error: invalid operand for instruction
asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "x" (k));
^
<inline asm>:1:21: note: instantiated into assembly here
sha256rnds2 %xmm1, 752(%rsp), %xmm0
^~~~~~~~~~
In file included from sha.cpp:24:
./cpu.h:833:7: error: invalid operand for instruction
asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "x" (k));
^
<inline asm>:1:21: note: instantiated into assembly here
sha256rnds2 %xmm3, 736(%rsp), %xmm1
^~~~~~~~~~
...
Merci Michael. GCC appelle cela [Variables de registre explicites] (https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables). Clang ne le compilera pas. J'ai essayé un certain nombre de façons différentes en utilisant C++ et C jette. Je pense que cela a quelque chose à voir avec le type '__m128i'. – jww
En regardant votre mise à jour vous manquez le qualificateur de type 'register' sur votre variable temporaire qui est nécessaire pour utiliser un registre explicite. Essayez 'register const __m128i k asm (" xmm0 ") = c;' –
Merci Michael. Le mot-clé 'register' disparaît en C++, nous ne pouvons donc pas l'utiliser. (Nous sommes une bibliothèque C++, et ce code est dans un fichier d'en-tête Peut-être que j'ai besoin de trouver une solution de contournement spécifique au compilateur, comme '__register' ou' GCC_REGISTER'). – jww