<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Clang on icyveins7's blog</title><link>https://icyveins7.github.io/tags/clang/</link><description>Recent content in Clang on icyveins7's blog</description><generator>Hugo</generator><language>en-us</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Mon, 11 Mar 2024 20:00:00 +0800</lastBuildDate><atom:link href="https://icyveins7.github.io/tags/clang/index.xml" rel="self" type="application/rss+xml"/><item><title>Clang and Eigen's alternatives to complex multiplication SIMD</title><link>https://icyveins7.github.io/posts/2024/03/clang-and-eigens-alternatives-to-complex-multiplication-simd/</link><pubDate>Mon, 11 Mar 2024 20:00:00 +0800</pubDate><guid>https://icyveins7.github.io/posts/2024/03/clang-and-eigens-alternatives-to-complex-multiplication-simd/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;Clang isn&amp;rsquo;t much better than MSVC for complex number multiplication, while Eigen is equivalent to GCC but uses slightly different instructions.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h1 id="complex-number-multiplication-is-probably-not-common-enough"&gt;Complex Number Multiplication Is Probably Not Common Enough&lt;/h1&gt;&#10;&lt;p&gt;I think I might have bashed MSVC too much on the last post; trying to vectorise our simple 4-element complex number multiplication using clang with AVX instructions delivers &lt;a href="https://godbolt.org/z/35dGqTfKv"&gt;similarly poor results&lt;/a&gt;:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#include &amp;lt;complex&amp;gt;&#10;&#10;void cmul(&#10; const std::complex&amp;lt;float&amp;gt;* __restrict__ x,&#10; const std::complex&amp;lt;float&amp;gt;* __restrict__ y,&#10; std::complex&amp;lt;float&amp;gt;* __restrict__ z&#10;){&#10; for (int i = 0; i &amp;lt; 4; ++i)&#10; z[i] = x[i] * y[i];&#10;}&#10;&#10;void mul(&#10; const float* __restrict__ x,&#10; const float* __restrict__ y,&#10; float* __restrict__ z&#10;){&#10; for (int i = 0; i &amp;lt; 8; ++i)&#10; z[i] = x[i] * y[i];&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;cmul(std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt;*): # @cmul(std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt; const*, std::complex&amp;lt;float&amp;gt;*)&#10; vmovsd xmm0, qword ptr [rdi] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx], xmm0&#10; vmovsd xmm0, qword ptr [rdi + 8] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi + 8] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx + 8], xmm0&#10; vmovsd xmm0, qword ptr [rdi + 16] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi + 16] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx + 16], xmm0&#10; vmovsd xmm0, qword ptr [rdi + 24] # xmm0 = mem[0],zero&#10; vmovsd xmm1, qword ptr [rsi + 24] # xmm1 = mem[0],zero&#10; vbroadcastss xmm2, xmm0&#10; vmovshdup xmm0, xmm0 # xmm0 = xmm0[1,1,3,3]&#10; vshufps xmm3, xmm1, xmm1, 225 # xmm3 = xmm1[1,0,2,3]&#10; vmulps xmm0, xmm3, xmm0&#10; vfmaddsub231ps xmm0, xmm1, xmm2 # xmm0 = (xmm1 * xmm2) +/- xmm0&#10; vmovlps qword ptr [rdx + 24], xmm0&#10; ret&#10;mul(float const*, float const*, float*): # @mul(float const*, float const*, float*)&#10; vmovups ymm0, ymmword ptr [rsi]&#10; vmulps ymm0, ymm0, ymmword ptr [rdi]&#10; vmovups ymmword ptr [rdx], ymm0&#10; vzeroupper&#10; ret&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Compiled with clang 18.1.0, with &lt;code&gt;-O3 -ffast-math -march=x86-64-v3&lt;/code&gt;, this still refuses to vectorise the &lt;code&gt;cmul&lt;/code&gt; function correctly, only using the &lt;code&gt;xmm&lt;/code&gt; registers. I included the normal real-valued float multiplication to check that clang is indeed able to vectorise that. Note that you still need the &lt;code&gt;__restrict__&lt;/code&gt; keywords for the vectorisation to work. Using &lt;code&gt;-ffast-math&lt;/code&gt; doesn&amp;rsquo;t seem to do anything for us in the real float vectorisation, but it does make the complex-valued vectorisation less verbose.&lt;/p&gt;</description></item></channel></rss>