C++Guns – RoboBlog

12.09.2017

C++ Guns - Missed optimizations

Filed under: Allgemein — Tags: , — Thomas @ 02:09

Compiler sind nicht perfekt. Gerade das Optimieren von Code ist so komplex, dass es keinen Algorithmus dafür gibt. Ehr werden Heuristiken dafür benutzt. So kommt es schon mal vor, dass bei banal aussehenden Code die Compiler Optimierung versagt hat und es möglich ist, von Hand schnelleren Assembler Code zu schreiben.

In [1] wurde viele solcher fehlerhaften Optimierungen gezeigt. Mit "Fehlerbeschreibung", Assembercode und teils sogar Patches für den Compiler. Leider nur für die ARM Architektur.

Ich möchte nun einige Beispiele aufgreifen und versuchen sie auf X86 64bit Plattformen nachzuahmen. Getestet wird mit g++ 64bit 4.9.2, 7.1.0, 32bit 6.3.0. Compileraufruf:
g++ -save-temps -O3 -g -fverbose-asm -march=native -c 1.cpp -Wa,-adhln=test.s

Compiler passedfailed
gcc 8.0.0 ARM 0 2
g++ 7.1.0 x86-642 0
g++ 6.0.0 x86-321 1
g++ 4.9.2 x86-642 0

Useless initialization of struct passed by value

struct S0 {
  int f0;
  int f1;
  int f2;
  int f3;
};

int f1(struct S0 p) {
    return p.f0;
}

ARM:

The struct is passed in registers, and the function's result is already in r0, which is also the return register. The function could return immediately, but GCC first stores all the struct fields to the stack and reloads the first field.

X86:

11:1.cpp         ****     return p.f0;
71   	         movl	%edi, %eax	# p,
72               ret

Ja, nur eine Assembler Instruktion.

float to char type conversion goes through memory

char fn1(float p1) {
  return (char) p1;
}

ARM:

the result of the conversion in s15 is stored to the stack and then reloaded into r0 instead of just copying it between the registers

X86-64:

 2:2.cpp         ****   return (char) p1;
78         vcvttss2si      %xmm0, %eax     # p1

VCVTTSS2SI: Convert one single-precision floating-point value from xmm1/m32 to one signed doubleword integer in r32 using truncation.

Ja, mit AVX zwischen den Register kopiert.

X86-32:

78               subl    $4, %esp        #,
 2:2.cpp         ****   return (char) p1;
81               flds    8(%esp) # p1
82               fisttps 2(%esp) #
83               movzwl  2(%esp), %eax   #

FISTTP: Store Integer with Truncation

Nein, die Variable wird vom Stack in ein floating point Register geladen und dort convertiert. Danach zurück auf den Stack gespeichert und zum Schluss in das Rückgaberegister geladen.

[1] https://github.com/gergo-/missed-optimizations/blob/master/README.md

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress