Ich habe ein wenig mit der x86-64-Assemblierung herumgespielt, um mehr über die verschiedenen verfügbaren SIMD-Erweiterungen (MMX, SSE, AVX) zu erfahren.
Um zu sehen, wie verschiedene C- oder C++-Konstrukte von GCC in Maschinencode übersetzt werden, habe ich verwendet Compiler-Explorer das ist ein hervorragendes Werkzeug.
Während einer meiner „Spielsitzungen“ wollte ich sehen, wie GCC eine einfache Laufzeitinitialisierung eines Integer-Arrays optimieren kann. In diesem Fall habe ich versucht, die Zahlen 0 bis 2047 in ein Array von 2048 vorzeichenlosen Ganzzahlen zu schreiben.
Der Code sieht wie folgt aus:
unsigned int buffer[2048];
void setup()
{
for (unsigned int i = 0; i < 2048; ++i)
{
buffer[i] = i;
}
}
Wenn ich Optimierungen und AVX-512-Anweisungen aktiviere -O3 -mavx512f -mtune=intel
GCC 6.3 generiert wirklich cleveren 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
Als ich jedoch testete, was generiert würde, wenn derselbe Code mit dem GCC-C-Compiler kompiliert würde, indem die Flags hinzugefügt würden -x c
Ich war wirklich überrascht.
Ich habe ähnliche, wenn nicht identische Ergebnisse erwartet, aber der C-Compiler scheint zu generieren viel komplizierterer und vermutlich auch viel langsamerer Maschinencode. Die resultierende Baugruppe ist zu groß, um sie hier vollständig einzufügen, aber sie kann unter godbolt.org angezeigt werden, indem Sie folgen Dies Verknüpfung.
Ein Ausschnitt des generierten Codes, Zeilen 58 bis 83, ist unten zu sehen:
.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]
Wie Sie sehen können, hat dieser Code viele komplizierte Bewegungen und Sprünge und fühlt sich im Allgemeinen wie eine sehr komplexe Art an, eine einfache Array-Initialisierung durchzuführen.
Warum gibt es so einen großen Unterschied im generierten Code?
Ist der GCC C++-Compiler im Vergleich zum C-Compiler allgemein besser darin, Code zu optimieren, der sowohl in C als auch in C++ gültig ist?
Zusätzlicher Datenpunkt: using
static unsigned int buffer[2048];
macht den C-Code auch ähnlich. Sie müssen die tatsächlich verwendenbuffer
damit es aber nicht ganz wegfällt. Sieht so aus, als ob es sich um ein Ausrichtungsproblem handelt, der zusätzliche Code dient dazu, eine Fehlausrichtung zu behandeln.– Narr
22. Dezember 2016 um 23:19 Uhr
@Olaf vielleicht könnten Sie uns den Unterschied zwischen der Semantik in C und C++ für diesen Codeabschnitt erläutern
– MM
22. Dezember 2016 um 23:23 Uhr
@Jester Pro-Tipp für Godbolt, Putten
void g(void *); g(buffer);
verhindert, dass der Puffer herausoptimiert wird– MM
22. Dezember 2016 um 23:24 Uhr
@Olaf Warum sollte es nicht? Wenn Sie einen bestimmten Einblick haben, wie und warum gcc in diesem Fall tut, was es tut, fügen Sie eine Antwort hinzu, da es im Grunde das ist, was OP fragt.
– Nr
22. Dezember 2016 um 23:26 Uhr
Putten
unsigned int buffer[2048] = { 0 };
generiert auch den einfacheren Code. Vielleicht ist Olaf tatsächlich auf etwas in Cunsigned int buffer[2048]
ist ein vorläufige Definition, etwas, das C++ nicht hat. Dies wirkt sich nicht wirklich auf das beobachtbare Verhalten des Programms aus, hat aber offensichtlich einen gewissen Einfluss auf die GCC-Codegenerierung.– MM
22. Dezember 2016 um 23:26 Uhr