{"id":4034,"date":"2019-01-15T00:52:07","date_gmt":"2019-01-14T23:52:07","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=4034"},"modified":"2019-01-15T18:48:38","modified_gmt":"2019-01-15T17:48:38","slug":"c-guns-how-now-to-design-fortran-c-interfaces","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=4034","title":{"rendered":"C++ Guns: How NOW to design FORTRAN -> C++ Interfaces"},"content":{"rendered":"<p>This is one wrong way to design a FORTRAN to C++ interface.<br \/>\nBut let's start at the beginning. From FORTRAN callable C++ function must be declared with extern \"C\" to disable name mangling.<br \/>\nThe function <em>funcCPP<\/em> expect a 2D array. Two items a 3 values. Calculate the sum and return it.<br \/>\nRember: C counts from 0 and the right most index is the fastest index.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#ifdef __cplusplus\r\n    extern &quot;C&quot; {\r\n#endif\r\n\r\ndouble funcCPP(double arr&#x5B;2]&#x5B;3]);\r\n\r\n#ifdef __cplusplus\r\n    }\r\n#endif\r\n\r\ndouble funcCPP(double arr&#x5B;2]&#x5B;3]) {\r\n  return arr&#x5B;0]&#x5B;0] + arr&#x5B;0]&#x5B;1] + arr&#x5B;0]&#x5B;2] + arr&#x5B;1]&#x5B;0] + arr&#x5B;1]&#x5B;1] + arr&#x5B;1]&#x5B;2];\r\n}\r\n<\/pre>\n<p>The generated ASM code (GCC -O1) looks straight forward. Almost perfect (except of SIMD). Nothing more to say.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfuncCPP:\r\n        movsd   (%rdi), %xmm0\r\n        addsd   8(%rdi), %xmm0\r\n        addsd   16(%rdi), %xmm0\r\n        addsd   24(%rdi), %xmm0\r\n        addsd   32(%rdi), %xmm0\r\n        addsd   40(%rdi), %xmm0\r\n        ret\r\n<\/pre>\n<p>Now we implement an FORTRAN interface for that function. Using iso_c_binding module to make life easier. But the compiler didn't to any real check. If you add an parameter in the C function and forget to add it in the FORTRAN interface -> BOOM.<br \/>\nThe array is pass as an 1D array. <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmodule CPPinterface_m\r\n  use, intrinsic :: iso_c_binding\r\n  implicit none\r\n\r\n  interface\r\n    function funcCPP(arr)  bind(c, name=&quot;funcCPP&quot;)\r\n      use, intrinsic :: iso_c_binding\r\n      implicit none\r\n      real(c_double), dimension(*) :: arr\r\n      real(c_double) :: funcCPP\r\n    end function\r\n  end interface\r\nend module\r\n<\/pre>\n<p>The main code is a subroutine <em>func<\/em>  which get an 2D array with N items a 3 values. The variable <em>idx<\/em> contains the position of the items we are interested in. This values are passed to <em>funcCPP<\/em>. But the two items at position idx(1) and idx(2) are not consecutive stored in RAM. So the compiler has to generate code which make a copy of the six floating point values. That's not what we intend to.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmodule prog_m\r\n  use CPPinterface_m\r\n  implicit none\r\n  integer :: N\r\n\r\n  contains\r\n\r\n  subroutine func(arr, idx)\r\n    implicit none\r\n    real(8), intent(inout) :: arr(3,N)\r\n    integer, intent(in) :: idx(2)\r\n    real(8) :: res\r\n\r\n    res = funcCPP(arr(:,idx))\r\n  end subroutine\r\nend module\r\n<\/pre>\n<p>You can see it right here in the assembler code. I commented it for you. The data is passed through stack.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n__unrunoff_m_MOD_func:\r\n    subq    $56, %rsp              # allocate 56 bytes on stack\r\n    movslq    (%rsi), %rax         \r\n    leaq    (%rax,%rax,2), %rax    # calculate address of first item\r\n    leaq    (%rdi,%rax,8), %rax\r\n    movsd    -24(%rax), %xmm0      # copy arr&#x5B;0]&#x5B;0]\r\n    movsd    %xmm0, (%rsp)\r\n    movsd    -16(%rax), %xmm0      # copy arr&#x5B;0]&#x5B;1]\r\n    movsd    %xmm0, 8(%rsp)\r\n    movsd    -8(%rax), %xmm0       # copy arr&#x5B;0]&#x5B;2]\r\n    movsd    %xmm0, 16(%rsp)\r\n    movslq    4(%rsi), %rax\r\n    leaq    (%rax,%rax,2), %rax    # calculate address of second item\r\n    leaq    (%rdi,%rax,8), %rax\r\n    movsd    -24(%rax), %xmm0      # copy arr&#x5B;1]&#x5B;0]\r\n    movsd    %xmm0, 24(%rsp)\r\n    movsd    -16(%rax), %xmm0      # copy arr&#x5B;1]&#x5B;1]\r\n    movsd    %xmm0, 32(%rsp)\r\n    movsd    -8(%rax), %xmm0       # copy arr&#x5B;1]&#x5B;2]\r\n    movsd    %xmm0, 40(%rsp)\r\n    movq    %rsp, %rdi\r\n    call    funcCPP@PLT            # call the C++ function\r\n    addq    $56, %rsp              # release stack space\r\n    ret\r\n<\/pre>\n<p>We have 6 ASM instruction to process the data and 21 instructions to access the data. Nope. Fail.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is one wrong way to design a FORTRAN to C++ interface. But let's start at the beginning. From FORTRAN callable C++ function must be declared with extern \"C\" to disable name mangling. The function funcCPP expect a 2D array. Two items a 3 values. Calculate the sum and return it. Rember: C counts from [&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-4034","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\/4034","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=4034"}],"version-history":[{"count":7,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4034\/revisions"}],"predecessor-version":[{"id":4043,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4034\/revisions\/4043"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4034"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4034"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4034"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}