{"id":3426,"date":"2018-04-23T18:19:00","date_gmt":"2018-04-23T17:19:00","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3426"},"modified":"2018-04-23T18:19:00","modified_gmt":"2018-04-23T17:19:00","slug":"c-guns-branch-free-min-with-conditional-move-cmovcc","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3426","title":{"rendered":"C++ Guns: branch free min() with Conditional Move CMOVcc"},"content":{"rendered":"<p>In der Regel wird die min() Funktion mittels Verzweigung implementiert. Ohne zus\u00e4tzliche Optimierung f\u00fchrt dies zu einem Sprung im Code und damit zu Branchs Mispredicts. Dies ist gerade beim HPC Code ziemlich schlecht, da im Fall einer falscher Sprungvorhersage die CPU Pipeline wieder zur\u00fcckgesetzt werden muss. <\/p>\n<p>Es gibt aber Alternativen: Conditional Move CPU Instruktionen. Je nach Bedingung wird ein Wert in ein anderes Register kopiert, oder eben nicht. Da steckt kein Sprung im Code dahinter, das wird alles auf CPU Ebene realisiert. So wird dieser C++ Code zu folgendem Assember ersetzt:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nint func(int x, int y) {\r\n    int a = y;\r\n    if(x &lt; y) {\r\n        a = x;\r\n    }\r\n    return a;\r\n}\r\n<\/pre>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfunc(int, int):\r\n  cmp esi, edi        x &lt; y ?\r\n  mov eax, edi        a = y\r\n  cmovle eax, esi     Wenn x&lt;y dann a = x\r\n  ret                 return a\r\n<\/pre>\n<p>Es ist aber garnicht n\u00f6tig so komplizierten C++ Code, oder gar inline Assember zu schreiben, der Compiler erkennt das Muster automatisch. So f\u00fchrt die Benutzung von  std::min(x,y) zu exakt dem selben Assember Code.<\/p>\n<p>Das ganze Funktioniert bei meinen Tests mit Optimierung O1 und O2, aber nicht mehr mit O3. Da bei dieser Optimierung wohl zuviel Schleifen Optimierungs Magie zum Einsatz kommt. Die verantwortlichen Flags m\u00fcssten -fif-conversion -fif-conversion2 sein, welche bei jeder Optimierungsstufe aktiv sein.<\/p>\n<blockquote><p>-fif-conversion<\/p>\n<p>    Attempt to transform conditional jumps into branch-less equivalents. This includes use of conditional moves, min, max, set flags and abs instructions, and some tricks doable by standard arithmetics. The use of conditional execution on chips where it is available is controlled by -fif-conversion2.<\/p>\n<p>    Enabled at levels -O, -O2, -O3, -Os.<br \/>\n-fif-conversion2<\/p>\n<p>    Use conditional execution (where available) to transform conditional jumps into branch-less equivalents.<\/p>\n<p>    Enabled at levels -O, -O2, -O3, -Os.\n<\/p><\/blockquote>\n<p>Selbstverst\u00e4ndlich funktioniert das auch f\u00fcr Floatingpoint Typen, da reich auch eine einzelne Assembler Anweisung: std::min(x,y)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In der Regel wird die min() Funktion mittels Verzweigung implementiert. Ohne zus\u00e4tzliche Optimierung f\u00fchrt dies zu einem Sprung im Code und damit zu Branchs Mispredicts. Dies ist gerade beim HPC Code ziemlich schlecht, da im Fall einer falscher Sprungvorhersage die CPU Pipeline wieder zur\u00fcckgesetzt werden muss. Es gibt aber Alternativen: Conditional Move CPU Instruktionen. Je [&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":[17],"class_list":["post-3426","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3426","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=3426"}],"version-history":[{"count":4,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3426\/revisions"}],"predecessor-version":[{"id":3430,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3426\/revisions\/3430"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3426"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3426"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3426"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}