<div dir="ltr"><div>Being technical on the "lack of optimisation" here, it is not that LLVM doesn't identify the common loop variable, but the fact that it (probably misguidedly) removes the loop variable and uses multiple pointers instead.<br><br></div><div>You WOULD want:<br><br></div><div>    for(i = 0; i < size; i++)<br>    {<br></div><div>       s[i] = t[i];<br>    }<br><br></div><div>to be converted to:<br><br></div><div>    stmp = s;<br></div><div>    ttemp = t;<br></div><div>    send = s+size;<br></div><div>    while(stmp < send)<br>    {<br></div><div>       s++ = t++;<br>    }<br><br></div><div>right? So the compiler should recognise these cases, and do the conversion, but only when it's actually "better".<br></div><div><br>--<br></div>Mats<br></div><div class="gmail_extra"><br><div class="gmail_quote">On 9 June 2016 at 10:02, Wenzel Jakob via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">Apologies, there was a typo in my last message.<div><br></div><div>"The following output was generated by LLVM” in the third paragraph should have read "The following output was generated by GCC 5.3.0”.</div><div><br></div><div>-Wenzel</div><div><br><div><blockquote type="cite"><span class=""><div>On 09 Jun 2016, at 09:15, Wenzel Jakob <<a href="mailto:wenzel.jakob@epfl.ch" target="_blank">wenzel.jakob@epfl.ch</a>> wrote:</div><br></span><div>
<div style="word-wrap:break-word"><span class=""><div>Hi,</div><div><br></div><div>I’m having trouble getting LLVM/Clang to generate high quality code for a tight loop involving AVX intrinsics.</div><div>Consider the following simple function, which computes a sum of a bunch of buffers.</div><div><br></div><div><font face="Courier">#include <immintrin.h></font></div><div><font face="Courier"><br></font></div><div><font face="Courier">void sum(size_t n, </font></div><div><font face="Courier">        __m256* __restrict__ a, __m256* __restrict__ b,</font></div><div><font face="Courier">        __m256* __restrict__ c, __m256* __restrict__ d,</font></div><div><font face="Courier">        __m256* __restrict__ e, __m256* __restrict__ f,</font></div><div><font face="Courier">        __m256* __restrict__ g) {</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">    for (size_t i = 0; i < n; ++i)</font></div><div><font face="Courier">        a[i] = _mm256_add_ps(</font></div><div><font face="Courier">            _mm256_add_ps(_mm256_add_ps(b[i], c[i]),</font></div><div><font face="Courier">                _mm256_add_ps(d[i], e[i])),</font></div><div><font face="Courier">                _mm256_add_ps(f[i], g[i]));</font></div><div><font face="Courier">}</font></div><div><br></div></span><div>This is the main loop body resulting from the above expression (compiled with -mavx2 -O3 -fomit-frame-pointer -fno-unroll-loops). Note the large number of “addq” instructions!</div><div><div class="h5"><div>The compiler also seems to assume that the __m256 entries are unaligned, but that is another issue.</div><div><br></div><div><font face="Courier">LBB0_2:</font></div><div><div><font face="Courier"><span style="white-space:pre-wrap">    </span>vmovups<span style="white-space:pre-wrap"> </span>(%rdx), %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">  </span>vaddps<span style="white-space:pre-wrap">  </span>(%rcx), %ymm0, %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">   </span>vmovups<span style="white-space:pre-wrap"> </span>(%r8), %ymm1</font></div><div><font face="Courier"><span style="white-space:pre-wrap">   </span>vaddps<span style="white-space:pre-wrap">  </span>(%r9), %ymm1, %ymm1</font></div><div><font face="Courier"><span style="white-space:pre-wrap">    </span>vaddps<span style="white-space:pre-wrap">  </span>%ymm1, %ymm0, %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">    </span>vmovups<span style="white-space:pre-wrap"> </span>(%rax), %ymm1</font></div><div><font face="Courier"><span style="white-space:pre-wrap">  </span>vaddps<span style="white-space:pre-wrap">  </span>(%r10), %ymm1, %ymm1</font></div><div><font face="Courier"><span style="white-space:pre-wrap">   </span>vaddps<span style="white-space:pre-wrap">  </span>%ymm1, %ymm0, %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">    </span>vmovups<span style="white-space:pre-wrap"> </span>%ymm0, (%rsi)</font></div><div><font face="Courier"><span style="white-space:pre-wrap">  </span>addq<span style="white-space:pre-wrap">    </span>$32, %rdx</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>addq<span style="white-space:pre-wrap">    </span>$32, %rcx</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>addq<span style="white-space:pre-wrap">    </span>$32, %r8</font></div><div><font face="Courier"><span style="white-space:pre-wrap">       </span>addq<span style="white-space:pre-wrap">    </span>$32, %r9</font></div><div><font face="Courier"><span style="white-space:pre-wrap">       </span>addq<span style="white-space:pre-wrap">    </span>$32, %rax</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>addq<span style="white-space:pre-wrap">    </span>$32, %r10</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>addq<span style="white-space:pre-wrap">    </span>$32, %rsi</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>decq<span style="white-space:pre-wrap">    </span>%rdi</font></div><div><font face="Courier"><span style="white-space:pre-wrap">   </span>jne<span style="white-space:pre-wrap">     </span>LBB0_2</font></div></div><div><br></div><div><br></div><div>The following output was generated by LLVM. It identifies the common counter variable and just stores the buffer offsets in registers.</div><div><br></div><div><div><font face="Courier">L5:</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>vmovaps<span style="white-space:pre-wrap"> </span>(%r9,%rax), %ymm1</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>vmovaps<span style="white-space:pre-wrap"> </span>(%rcx,%rax), %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">     </span>vaddps<span style="white-space:pre-wrap">  </span>(%r8,%rax), %ymm1, %ymm2</font></div><div><font face="Courier"><span style="white-space:pre-wrap">       </span>vaddps<span style="white-space:pre-wrap">  </span>(%rdx,%rax), %ymm0, %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>vaddps<span style="white-space:pre-wrap">  </span>%ymm0, %ymm2, %ymm1</font></div><div><font face="Courier"><span style="white-space:pre-wrap">    </span>vmovaps<span style="white-space:pre-wrap"> </span>(%r11,%rax), %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">     </span>vaddps<span style="white-space:pre-wrap">  </span>(%rbx,%rax), %ymm0, %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>vaddps<span style="white-space:pre-wrap">  </span>%ymm0, %ymm1, %ymm0</font></div><div><font face="Courier"><span style="white-space:pre-wrap">    </span>vmovaps<span style="white-space:pre-wrap"> </span>%ymm0, (%rsi,%rax)</font></div><div><font face="Courier"><span style="white-space:pre-wrap">     </span>addq<span style="white-space:pre-wrap">    </span>$32, %rax</font></div><div><font face="Courier"><span style="white-space:pre-wrap">      </span>cmpq<span style="white-space:pre-wrap">    </span>%rax, %r10</font></div><div><font face="Courier"><span style="white-space:pre-wrap">     </span>jne<span style="white-space:pre-wrap">     </span>L5</font></div></div><div><br></div><div>Is there something that could be done to LLVM to generate better code in such cases?</div><div><br></div><div><div>For reference, this is the associated LLVM IR:</div><div><font face="Courier"><br></font></div></div><div><div><font face="Courier">; Function Attrs: nounwind ssp uwtable</font></div><div><font face="Courier">define void @_Z3summPDv8_fS0_S0_S0_S0_S0_S0_(i64 %n, <8 x float>* noalias nocapture %a, <8 x float>* noalias nocapture readonly %b, <8 x float>* noalias nocapture readonly %c, <8 x float>* noalias nocapture readonly %d, <8 x float>* noalias nocapture readonly %e, <8 x float>* noalias nocapture readonly %f, <8 x float>* noalias nocapture readonly %g) #0 {</font></div><div><font face="Courier">  %1 = icmp eq i64 %n, 0</font></div><div><font face="Courier">  br i1 %1, label %._crit_edge, label %.<a href="http://lr.ph" target="_blank">lr.ph</a></font></div><div><font face="Courier"><br></font></div><div><font face="Courier">._crit_edge:                                      ; preds = %.<a href="http://lr.ph" target="_blank">lr.ph</a>, %0</font></div><div><font face="Courier">  ret void</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">.<a href="http://lr.ph" target="_blank">lr.ph</a>:                                           ; preds = %0, %.<a href="http://lr.ph" target="_blank">lr.ph</a></font></div><div><font face="Courier">  %i.01 = phi i64 [ %20, %.<a href="http://lr.ph" target="_blank">lr.ph</a> ], [ 0, %0 ]</font></div><div><font face="Courier">  %2 = getelementptr inbounds <8 x float>, <8 x float>* %b, i64 %i.01</font></div><div><font face="Courier">  %3 = load <8 x float>, <8 x float>* %2, align 16, !tbaa !2</font></div><div><font face="Courier">  %4 = getelementptr inbounds <8 x float>, <8 x float>* %c, i64 %i.01</font></div><div><font face="Courier">  %5 = load <8 x float>, <8 x float>* %4, align 16, !tbaa !2</font></div><div><font face="Courier">  %6 = fadd <8 x float> %3, %5</font></div><div><font face="Courier">  %7 = getelementptr inbounds <8 x float>, <8 x float>* %d, i64 %i.01</font></div><div><font face="Courier">  %8 = load <8 x float>, <8 x float>* %7, align 16, !tbaa !2</font></div><div><font face="Courier">  %9 = getelementptr inbounds <8 x float>, <8 x float>* %e, i64 %i.01</font></div><div><font face="Courier">  %10 = load <8 x float>, <8 x float>* %9, align 16, !tbaa !2</font></div><div><font face="Courier">  %11 = fadd <8 x float> %8, %10</font></div><div><font face="Courier">  %12 = fadd <8 x float> %6, %11</font></div><div><font face="Courier">  %13 = getelementptr inbounds <8 x float>, <8 x float>* %f, i64 %i.01</font></div><div><font face="Courier">  %14 = load <8 x float>, <8 x float>* %13, align 16, !tbaa !2</font></div><div><font face="Courier">  %15 = getelementptr inbounds <8 x float>, <8 x float>* %g, i64 %i.01</font></div><div><font face="Courier">  %16 = load <8 x float>, <8 x float>* %15, align 16, !tbaa !2</font></div><div><font face="Courier">  %17 = fadd <8 x float> %14, %16</font></div><div><font face="Courier">  %18 = fadd <8 x float> %12, %17</font></div><div><font face="Courier">  %19 = getelementptr inbounds <8 x float>, <8 x float>* %a, i64 %i.01</font></div><div><font face="Courier">  store <8 x float> %18, <8 x float>* %19, align 16, !tbaa !2</font></div><div><font face="Courier">  %20 = add nuw i64 %i.01, 1</font></div><div><font face="Courier">  %exitcond = icmp eq i64 %20, %n</font></div><div><font face="Courier">  br i1 %exitcond, label %._crit_edge, label %.<a href="http://lr.ph" target="_blank">lr.ph</a></font></div><div><font face="Courier">}</font></div></div><div><br></div><div>Thank you and best regards,</div><div>Wenzel</div></div></div></div></div></blockquote></div><br></div></div><br>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
<br></blockquote></div><br></div>