{"id":3488,"date":"2018-05-16T10:36:17","date_gmt":"2018-05-16T09:36:17","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3488"},"modified":"2018-05-16T10:36:17","modified_gmt":"2018-05-16T09:36:17","slug":"c-guns-simd-pointnd","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3488","title":{"rendered":"C++ Guns: SIMD PointND"},"content":{"rendered":"<p>Kommen wir wieder zur\u00fcck zu meinem Lieblingsdatentype: PointND. Diesmal mit SSE. In den letzten Posts hab ich den Type SIMDarray vorgestellt zum gleichzeitigen prozessieren von mehreren Werten. Danach folge SIMDvalarray Type welcher arithmetische Operation +, -, *, \/, definierte. Was braucht es noch mehr zum SIMD PointND? Eigentlich nichts. Ein PointND ist ein fixed size array der L\u00e4nge N. Man kann noch ein paar Funktionen bereit stellen um explizit auf X und Y zuzugreifen. Aber das ist eigentlich nur Syntax Zucker und bringt keine neue Funktionalit\u00e4t. Also versuchen wir es:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate&lt;typename Array&gt;\r\nstruct PointND : Array {\r\n  static_assert(Array().size() &gt;= 2);\r\n  using value_type = typename Array::value_type;\r\n\r\n  const value_type&amp; x() const {\r\n    return (*this)&#x5B;0];\r\n  }\r\n\r\n  const value_type&amp; y() const {\r\n    return (*this)&#x5B;1];\r\n  }\r\n};\r\n\r\ntemplate&lt;typename Array&gt;\r\ninline auto operator+(const PointND&lt;Array&gt;&amp; lhs, const PointND&lt;Array&gt;&amp; rhs) {\r\n    return PointND&lt;Array&gt;{static_cast&lt;Array&gt;(lhs) + static_cast&lt;Array&gt;(rhs)};\r\n}\r\n\r\ntemplate&lt;typename Array&gt;\r\nauto func(const PointND&lt;Array&gt;&amp; p1, const PointND&lt;Array&gt;&amp; p2) {\r\n    return (p1+p2).y();\r\n}\r\n\r\nauto func2(const PointND&lt;SIMDvalarray&lt;double, 2&gt;&gt;&amp; p1, const PointND&lt;SIMDvalarray&lt;double, 2&gt;&gt;&amp; p2) {\r\n    return func(p1, p2);\r\n}\r\n<\/pre>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nacpl::func2(acpl::PointND&lt;acpl::SIMDvalarray&lt;double, 2ul&gt; &gt; const&amp;, acpl::PointND&lt;acpl::SIMDvalarray&lt;double, 2ul&gt; &gt; const&amp;):\r\n  movapd (%rsi), %xmm0\r\n  addpd (%rdi), %xmm0\r\n  unpckhpd %xmm0, %xmm0\r\n<\/pre>\n<p>Also ein paar Sachen sind ja schon nervig. Zum einem die Templates. F\u00fcr Funktionsargumente ist das zu verbose. Es z\u00e4hlt im Grunde nur, dass der Type ein PointND ist. Die Anzahl der Dimensionen, das zugrunde liegende Array oder value_type (int, double), spielt eigentlich keine Rolle. Der Compiler kennt den genauen Aufbau des Types und kann alles N\u00f6tige daraus Ableiten. Das selbe gilt auch f\u00fcr Point2D f\u00fcr nur 2D Funktionen. Hier m\u00fcssten eigentlich Concepts weiter helfen....<\/p>\n<p>Die zweite st\u00f6rende Sache sind die sich st\u00e4ndig wiederholenden operation+-*\/ Funktionen. Weglassen kann man sie f\u00fcr PointND nicht. Es wird dann z.B. operator+ f\u00fcr SIMDvalarray aufgerufen, und das Ergebnis ist wieder ein SIMDvalarray, kein PointND. So ist dann der Zugriff auf Y wie im Code gezeigt nicht mehr m\u00f6glich. Der Compiler ist so schlau zu erkennen, dass hier nur der Type ge\u00e4ndert wird. Dies hat keinen Einfluss auf die Laufzeit, wie im Assembler Code zu sehen ist.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Kommen wir wieder zur\u00fcck zu meinem Lieblingsdatentype: PointND. Diesmal mit SSE. In den letzten Posts hab ich den Type SIMDarray vorgestellt zum gleichzeitigen prozessieren von mehreren Werten. Danach folge SIMDvalarray Type welcher arithmetische Operation +, -, *, \/, definierte. Was braucht es noch mehr zum SIMD PointND? Eigentlich nichts. Ein PointND ist ein fixed size [&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-3488","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\/3488","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=3488"}],"version-history":[{"count":2,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3488\/revisions"}],"predecessor-version":[{"id":3490,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3488\/revisions\/3490"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3488"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3488"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3488"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}