{"id":3211,"date":"2017-09-12T02:58:48","date_gmt":"2017-09-12T01:58:48","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3211"},"modified":"2017-09-12T02:59:33","modified_gmt":"2017-09-12T01:59:33","slug":"c-guns-missed-optimizations","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3211","title":{"rendered":"C++ Guns - Missed optimizations"},"content":{"rendered":"<p>Compiler sind nicht perfekt. Gerade das Optimieren von Code ist so komplex, dass es keinen Algorithmus daf\u00fcr gibt. Ehr werden Heuristiken daf\u00fcr benutzt. So kommt es schon mal vor, dass bei banal aussehenden Code die Compiler Optimierung versagt hat und es m\u00f6glich ist, von Hand schnelleren Assembler Code zu schreiben.<\/p>\n<p>In [1] wurde viele solcher fehlerhaften Optimierungen gezeigt. Mit \"Fehlerbeschreibung\", Assembercode und teils sogar Patches f\u00fcr den Compiler. Leider nur f\u00fcr die ARM Architektur.<\/p>\n<p>Ich m\u00f6chte 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:<br \/>\ng++ -save-temps -O3 -g -fverbose-asm  -march=native  -c 1.cpp -Wa,-adhln=test.s<\/p>\n<pre>\r\n<table border=1>\r\n<tr><td>Compiler<\/td>        <td>passed<\/td><td>failed<\/td><\/tr>\r\n<tr><td>gcc 8.0.0 ARM<\/td>   <td>0<\/td>     <td>2<\/td>\r\n<tr><td>g++ 7.1.0 x86-64<\/td><td>2<\/td>     <td>0<\/td>\r\n<tr><td>g++ 6.0.0 x86-32<\/td><td>1<\/td>     <td>1<\/td>\r\n<tr><td>g++ 4.9.2 x86-64<\/td><td>2<\/td>     <td>0<\/td>\r\n<\/table>\r\n<\/pre>\n<p><strong>Useless initialization of struct passed by value<\/strong><\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct S0 {\r\n  int f0;\r\n  int f1;\r\n  int f2;\r\n  int f3;\r\n};\r\n\r\nint f1(struct S0 p) {\r\n    return p.f0;\r\n}\r\n<\/pre>\n<p>ARM:<\/p>\n<blockquote><p>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.<\/p><\/blockquote>\n<p>X86:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n11:1.cpp         ****     return p.f0;\r\n71   \t         movl\t%edi, %eax\t# p,\r\n72               ret\r\n<\/pre>\n<p>Ja, nur eine Assembler Instruktion.<\/p>\n<p><strong>float to char type conversion goes through memory<\/strong><\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nchar fn1(float p1) {\r\n  return (char) p1;\r\n}\r\n<\/pre>\n<p>ARM:<\/p>\n<blockquote><p> 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<\/p><\/blockquote>\n<p>X86-64:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n 2:2.cpp         ****   return (char) p1;\r\n78         vcvttss2si      %xmm0, %eax     # p1\r\n<\/pre>\n<blockquote><p>VCVTTSS2SI: Convert one single-precision floating-point value from xmm1\/m32 to one signed doubleword integer in r32 using truncation.<\/p><\/blockquote>\n<p>Ja, mit AVX zwischen den Register kopiert.<\/p>\n<p>X86-32:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n78               subl    $4, %esp        #,\r\n 2:2.cpp         ****   return (char) p1;\r\n81               flds    8(%esp) # p1\r\n82               fisttps 2(%esp) #\r\n83               movzwl  2(%esp), %eax   #\r\n<\/pre>\n<blockquote><p>FISTTP: Store Integer with Truncation<\/p><\/blockquote>\n<p>Nein, die Variable wird vom Stack in ein floating point Register geladen und dort convertiert. Danach zur\u00fcck auf den Stack gespeichert und zum Schluss in das R\u00fcckgaberegister geladen.<\/p>\n<p>[1] https:\/\/github.com\/gergo-\/missed-optimizations\/blob\/master\/README.md<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Compiler sind nicht perfekt. Gerade das Optimieren von Code ist so komplex, dass es keinen Algorithmus daf\u00fcr gibt. Ehr werden Heuristiken daf\u00fcr benutzt. So kommt es schon mal vor, dass bei banal aussehenden Code die Compiler Optimierung versagt hat und es m\u00f6glich ist, von Hand schnelleren Assembler Code zu schreiben. In [1] wurde viele solcher [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[24,17],"class_list":["post-3211","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-asm","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3211","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3211"}],"version-history":[{"count":18,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3211\/revisions"}],"predecessor-version":[{"id":3229,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3211\/revisions\/3229"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3211"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}