{"id":3461,"date":"2018-05-10T13:48:07","date_gmt":"2018-05-10T12:48:07","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3461"},"modified":"2018-05-10T13:48:07","modified_gmt":"2018-05-10T12:48:07","slug":"c-guns-schlecht-generiertes-assember-von-fortran-code","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3461","title":{"rendered":"C++ Guns: schlecht generiertes Assember von Fortran Code"},"content":{"rendered":"<p>Analog zum letzten Beispiel mit C++ hier die angefangene Funktion mit Fortran. Auf die Getter Funktionen und ctors habe ich erst mal verzichtet. In Fortran ist es ohnehin nicht m\u00f6glich immer vereinheitlichten Code zu schreiben, und es ist auch so schon schlimm genug. <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmodule geometrymodule\r\n  implicit none \r\n  type Point2D_t\r\n    real(8) :: xp, yp\r\n    \r\n    contains\r\n    \r\n    procedure :: Point2Dminus\r\n    generic :: operator(-) =&gt; Point2Dminus\r\n  end type\r\n  \r\n  type Line2D_t\r\n    type(Point2D_t) :: pt1, pt2\r\n  end type\r\n\r\n  contains\r\n  \r\n  pure function Point2Dminus(this, point1) result(point2)\r\n    implicit none\r\n    class(Point2D_t), intent(in) :: this\r\n    type(Point2D_t), intent(in) :: point1\r\n    type(Point2D_t) :: point2\r\n\r\n    point2%xp = this%xp - point1%xp\r\n    point2%yp = this%yp - point1%yp\r\n  end function\r\nend module\r\n\r\nfunction func(line1, line2) result(denominator) \r\n  use geometrymodule\r\n  implicit none\r\n  type(Line2D_t), intent(in) :: line1, line2\r\n  type(Point2D_t) :: a, b\r\n  real(8) :: denominator\r\n  \r\n  a = line1%pt2 - line1%pt1\r\n  b = line2%pt1 - line2%pt2\r\n  denominator = a%yp * b%xp - a%xp * b%yp\r\nend function\r\n<\/pre>\n<p>Und hier der Fortran Code. Zur Erinnerung: Wir brauchen f\u00fcnf Subtraktionen, zwei Multiplikationen und vier explizite Kopier-Befehle in C++. In Fortran z\u00e4hle ich nur vier Subtraktionen, daf\u00fcr eine Addition, zwei Multiplikationen, 15 Kopier (MOV) Befehle, ein push\/pop Paar f\u00fcr den Stack, zwei Funktionsaufrufe, mit Point2D_t sind es sogar vier, und vier leaq Aufrufe. LEA steht f\u00fcr Load Effective Address. Hell NO. Das war mit Optimierung O1.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nPoint2d_t:\r\n\tmovq\t(%rdi), %rax\r\n\tmovq\t8(%rdi), %rdx\r\n\tmovq\t%rax, (%rsi)\r\n\tmovq\t%rdx, 8(%rsi)\r\n\tret\r\n\r\npoint2dminus:\r\n\tmovq\t(%rdi), %rax\r\n\tmovsd\t8(%rax), %xmm1\r\n\tmovsd\t(%rax), %xmm0\r\n\tsubsd\t(%rsi), %xmm0\r\n\tsubsd\t8(%rsi), %xmm1\r\n\tret\r\n\r\nfunc_:\r\n\tpushq\t%rbx\r\n\tsubq\t$48, %rsp\r\n\tmovq\t%rsi, %rbx\r\n\tmovq\tPoint2d_t, 24(%rsp)\r\n\tleaq\t16(%rdi), %rax\r\n\tmovq\t%rax, 16(%rsp)\r\n\tmovq\t%rdi, %rsi\r\n\tleaq\t16(%rsp), %rdi\r\n\tcall\tpoint2dminus\r\n\tmovsd\t%xmm0, (%rsp)\r\n\tmovsd\t%xmm1, 8(%rsp)\r\n\tmovq\tPoint2d_t, 40(%rsp)\r\n\tmovq\t%rbx, 32(%rsp)\r\n\tleaq\t16(%rbx), %rsi\r\n\tleaq\t32(%rsp), %rdi\r\n\tcall\tpoint2dminus\r\n\tmulsd\t8(%rsp), %xmm0\r\n\tmulsd\t(%rsp), %xmm1\r\n\tsubsd\t%xmm1, %xmm0\r\n\taddq\t$48, %rsp\r\n\tpopq\t%rbx\r\n\tret\r\n<\/pre>\n<p>Mit Optimierung O2 wird es besser. Auf einmal sind es sieben Subtraktionen, daf\u00fcr keine Addition mehr. Es bleibt bei zwei Multiplikationen. 13 Kopier MOV Befehle. Der Stack, LEA und die Funktionsaufrufe fallen weg. Hmmm, aber die Funktionen Point2d_t und point2dminus sind immer noch da. Dead Code elimination funktioniert also nicht. Damit bleiben effektiv f\u00fcnf Subtraktionen, zwei Multiplikationen und 6 Kopier\/MOV \u00fcbrig. Naja immerhin.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nPoint2d_t:\r\n\tmovq\t(%rdi), %rax\r\n\tmovq\t8(%rdi), %rdx\r\n\tmovq\t%rax, (%rsi)\r\n\tmovq\t%rdx, 8(%rsi)\r\n\tret\r\n\r\npoint2dminus:\r\n\tmovq\t(%rdi), %rax\r\n\tmovsd\t8(%rax), %xmm1\r\n\tmovsd\t(%rax), %xmm0\r\n\tsubsd\t8(%rsi), %xmm1\r\n\tsubsd\t(%rsi), %xmm0\r\n\tret\r\n\r\nfunc_:\r\n\tmovsd\t(%rsi), %xmm0\r\n\tmovapd\t%xmm0, %xmm1\r\n\tmovsd\t24(%rdi), %xmm0\r\n\tsubsd\t16(%rsi), %xmm1\r\n\tsubsd\t8(%rdi), %xmm0\r\n\tmulsd\t%xmm1, %xmm0\r\n\tmovsd\t8(%rsi), %xmm1\r\n\tmovapd\t%xmm1, %xmm2\r\n\tmovsd\t16(%rdi), %xmm1\r\n\tsubsd\t24(%rsi), %xmm2\r\n\tsubsd\t(%rdi), %xmm1\r\n\tmulsd\t%xmm2, %xmm1\r\n\tsubsd\t%xmm1, %xmm0\r\n\tret\r\n<\/pre>\n<p>Werden hingegen Getter Funktionen f\u00fcr Point2D x und y implementiert, um ein einheitliches Interface f\u00fcr alle geometrischen Datentypen bereit zu stellen, was in C++ immer ohne Overhead m\u00f6glich ist, kommen wieder Funktionsaufrufe und LEA Instruktionen in den Code. Und die gehn auch nicht mehr weg, egal mit welcher Optimierungsstufe.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Analog zum letzten Beispiel mit C++ hier die angefangene Funktion mit Fortran. Auf die Getter Funktionen und ctors habe ich erst mal verzichtet. In Fortran ist es ohnehin nicht m\u00f6glich immer vereinheitlichten Code zu schreiben, und es ist auch so schon schlimm genug. module geometrymodule implicit none type Point2D_t real(8) :: xp, yp contains procedure [&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,30],"class_list":["post-3461","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp","tag-fortran"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3461","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=3461"}],"version-history":[{"count":6,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3461\/revisions"}],"predecessor-version":[{"id":3467,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3461\/revisions\/3467"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3461"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3461"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3461"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}