J'ai joué un peu avec le x86-64 assemblée essayer d'en apprendre plus sur les différents SIMD extensions qui sont disponibles (MMX, SSE, AVX).
Afin de voir comment les différents C ou C++ constructions sont traduit en code machine par GCC j'ai été en utilisant le Compilateur Explorer qui est un superbe outil.
Lors d'une de mes séances de jeu " je voulais voir comment CCG pourrait optimiser un simple moment de l'exécution de l'initialisation d'un tableau d'entiers. Dans ce cas, j'ai essayé d'écrire les nombres de 0 à 2047 à un tableau de 2048 des entiers non signés.
Le code se présente comme suit:
unsigned int buffer[2048];
void setup()
{
for (unsigned int i = 0; i < 2048; ++i)
{
buffer[i] = i;
}
}
Si je activer les optimisations et AVX-512 instructions -O3 -mavx512f -mtune=intel
GCC 6.3 génère de très intelligent de code :)
setup():
mov eax, OFFSET FLAT:buffer
mov edx, OFFSET FLAT:buffer+8192
vmovdqa64 zmm0, ZMMWORD PTR .LC0[rip]
vmovdqa64 zmm1, ZMMWORD PTR .LC1[rip]
.L2:
vmovdqa64 ZMMWORD PTR [rax], zmm0
add rax, 64
cmp rdx, rax
vpaddd zmm0, zmm0, zmm1
jne .L2
ret
buffer:
.zero 8192
.LC0:
.long 0
.long 1
.long 2
.long 3
.long 4
.long 5
.long 6
.long 7
.long 8
.long 9
.long 10
.long 11
.long 12
.long 13
.long 14
.long 15
.LC1:
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
Cependant, lorsque j'ai testé ce que pourrait être générée si le même code a été compilé à l'aide de la GCC compilateur C en ajoutant les drapeaux -x c
j'ai été vraiment surpris.
Je m'attendais similaire, sinon identique, les résultats, mais le compilateur C semble générer beaucoup plus compliqué et sans doute aussi beaucoup plus lent en code machine. L'assemblage qui en résulte est trop grand pour coller ici dans son intégralité, mais il peut être consulté à godbolt.org en suivant ce lien.
Un extrait du code généré, lignes 58 à 83, peut être vu ci-dessous:
.L2:
vpbroadcastd zmm0, r8d
lea rsi, buffer[0+rcx*4]
vmovdqa64 zmm1, ZMMWORD PTR .LC1[rip]
vpaddd zmm0, zmm0, ZMMWORD PTR .LC0[rip]
xor ecx, ecx
.L4:
add ecx, 1
add rsi, 64
vmovdqa64 ZMMWORD PTR [rsi-64], zmm0
cmp ecx, edi
vpaddd zmm0, zmm0, zmm1
jb .L4
sub edx, r10d
cmp r9d, r10d
lea eax, [r8+r10]
je .L1
mov ecx, eax
cmp edx, 1
mov DWORD PTR buffer[0+rcx*4], eax
lea ecx, [rax+1]
je .L1
mov esi, ecx
cmp edx, 2
mov DWORD PTR buffer[0+rsi*4], ecx
lea ecx, [rax+2]
Comme vous pouvez le voir, ce code a beaucoup de mouvements compliqués, de sauts et en général se sent comme très complexe de la façon de procéder à une simple initialisation de tableau.
Pourquoi est-il une si grande différence dans le code généré?
Est la GCC C++compilateur mieux en général à l'optimisation de code qui est valable en C et C++, comparativement à la compilateur C?