<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Hi everybody!<br><br>I have a question for the vectorization experts and would like to ask for some insight please.<br><br>I am working on an LLVM-independent library that offers various memory layouts for arrays of plain structs in C++. One of these layouts is an AoSoA (Array of Struct of Arrays). E.g.:<div><div style="color:rgb(0,0,0);background-color:rgb(255,255,254);font-family:"Consolas, ""><div><span style="color:rgb(0,0,255)">constexpr</span> <span style="color:rgb(0,0,255)">auto</span> lanes = <span style="color:rgb(9,134,88)">8</span>;</div><div><span style="color:rgb(0,0,255)">struct</span> Block {</div><div>    <span style="color:rgb(0,0,255)">float</span> a[lanes];</div><div>    <span style="color:rgb(0,0,255)">float</span> b[lanes];</div><div>    <span style="color:rgb(0,0,255)">float</span> c[lanes];</div><div>};</div><div><br></div></div></div><div>Single loops that iterate over arrays of this layout fail to vectorize with clang/LLVM (also with recent g++, icc and MSVC). </div><div>E.g. adding the vectors of floats a and b into c, where a, b and c are stored in one memory block as AoSoA:</div><div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)"><span style="color:rgb(0,0,255)">constexpr</span> <span style="color:rgb(0,0,255)">auto</span> alignment = lanes * <span style="color:rgb(0,0,255)">sizeof</span>(<span style="color:rgb(0,0,255)">float</span>);</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)"><span style="color:rgb(0,0,255)">void</span> aosoa1(Block* ubuf, size_t n) {</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">    <span style="color:rgb(0,0,255)">auto</span>* buf = std::assume_aligned<alignment>(ubuf);</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">    <span style="color:rgb(0,0,255)">for</span> (size_t i = <span style="color:rgb(9,134,88)">0</span>; i < (n/lanes)*lanes; i++) {</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">        <span style="color:rgb(0,0,255)">const</span> <span style="color:rgb(0,0,255)">auto</span> block = i / lanes;</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">        <span style="color:rgb(0,0,255)">const</span> <span style="color:rgb(0,0,255)">auto</span> lane = i % lanes;</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">        buf[block].c[lane] = buf[block].a[lane] + buf[block].b[lane];</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">    }</div><div><font color="#000000" face="Consolas,"><span style="background-color:rgb(255,255,254)">}</span></font></div>Flags for clang: -std=c++20 -O3 -mavx2 -Rpass-analysis=loop-vectorize -Rpass-missed=loop-vectorize<br>clang gives me this remark: loop not vectorized: cannot identify array bounds [-Rpass-analysis=loop-vectorize]. I tried browsing through the LLVM source to figure out if I could get it working, but that obviously grew over my head :)<br><br>With two nested loops, the inner one vectorizes fine:<div><div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)"><span style="color:rgb(0,0,255)">void</span> aosoa2(Block* ubuf, size_t n) {</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">    <span style="color:rgb(0,0,255)">auto</span>* buf = std::assume_aligned<alignment>(ubuf);</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">    <span style="color:rgb(0,0,255)">for</span> (size_t block = <span style="color:rgb(9,134,88)">0</span>; block < n/lanes; block++) {</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">        <span style="color:rgb(0,0,255)">for</span> (size_t lane = <span style="color:rgb(9,134,88)">0</span>; lane < lanes; lane++) {</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">            buf[block].c[lane] = buf[block].a[lane] + buf[block].b[lane];</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">        }</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">    }</div><div style="color:rgb(0,0,0);font-family:"Consolas, ";background-color:rgb(255,255,254)">}</div><br>Full example: <a href="https://godbolt.org/z/qdG9aY">https://godbolt.org/z/qdG9aY</a></div></div></div><div><br></div><div>Why does clang/LLVM fail to vectorize the loop in aosoa1() which splits the loop index into block and lane index? I think I do not sufficiently understand the "cannot identify array bounds" remark.</div><div>Is vectorization theoretically possible for aosoa1()? That is, there is no reason that forbids vectorization.</div><div>Is there a workaround for clang, like a #pragma, that can be used to allow clang to vectorize aosoa1()?</div><div>Would this use case be important enough that clang/LLVM could at some point recognize such a pattern and successfully vectorize it?</div><div><br></div><div>I really appreciate your input here! Thank you very much!</div><div><br></div><div>Bernhard</div></div></div></div></div></div></div></div></div>