<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span style="font-size:12.8px">I'll propose a different heuristic. SROA should ignore stores of arguments into allocas in the entry block when deciding what slices to form. Such stores happen exactly once, and are usually coercions that we have to do for ABI reasons. SROA should generate code like this before promoting allocas to SSA form:</span><br></div><div class="gmail_quote"><span style="font-size:12.8px"><br></span></div><div class="gmail_quote"><span style="font-size:12.8px">d</span><span style="font-size:12.8px">efine i32 @func(i64 %r.coerce.0, i64 %r.coerce.1) {</span></div><div class="gmail_quote"><span style="font-size:12.8px">  %r.slice.0 = alloca i64</span></div><div class="gmail_quote"><span style="font-size:12.8px">  %r.slice.1 = alloca i32</span><span style="font-size:12.8px"><br></span></div><div class="gmail_quote"><span style="font-size:12.8px">  %r.slice.2 = alloca i32</span><span style="font-size:12.8px"><br></span></div><div class="gmail_quote"><span style="font-size:12.8px">  store i64 %r.coerce.0, i64* %r.slice.0</span></div><div class="gmail_quote"><span style="font-size:12.8px">  %r.1.shr = lshr i64 %r.coerce.1, 32</span></div><div class="gmail_quote"><span style="font-size:12.8px">  %r.1 = trunc i64 %r.1.shr</span></div><div class="gmail_quote"><span style="font-size:12.8px">  %r.2 = trunc i64 %r.coerce.1</span></div><div class="gmail_quote"><span style="font-size:12.8px">  store i32 %r.1, i32* %r.slice.1</span></div><div class="gmail_quote"><span style="font-size:12.8px">  store i32 %r.2, i32* %r.slice.2</span><span style="font-size:12.8px"><br></span></div><div class="gmail_quote"><span style="font-size:12.8px">  ...</span></div><div class="gmail_quote"><span style="font-size:12.8px">}</span></div><div class="gmail_quote"><span style="font-size:12.8px"><br></span></div><div class="gmail_quote"><span style="font-size:12.8px">This is basically "reasoning about the CFG" without actually looking at loop info. Stores of arguments in the entry block can't be in a loop. Even if they end up in one after inlining, instcombine should be able to simplify the {i32,i32}->i64->{i32,i32} code.</span></div><div class="gmail_quote"><br></div><div class="gmail_quote">On Tue, May 9, 2017 at 10:53 AM, Friedman, Eli via llvm-dev <span dir="ltr"><<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
  
    
  
  <div bgcolor="#FFFFFF"><div><div class="gmail-h5">
    <div class="gmail-m_-2327744573123651316moz-cite-prefix">On 5/9/2017 6:05 AM, Hiroshi 7 Inoue
      via llvm-dev wrote:<br>
    </div>
    <blockquote type="cite">
      <p><font size="2">Hi,</font><br>
        <br>
        <font size="2">I am working to improve SROA to generate better
          code when a method has a struct in its arguments. I would
          appreciate it if I could have any suggestions or comments on
          how I can best proceed with this optimization.</font><br>
        <br>
        <font size="2">* Problem *</font><br>
        <font size="2">I observed that LLVM often generates redundant
          instructions around glibc’s istreambuf_iterator. The problem
          comes from the scalar replacement (SROA) for methods with an
          aggregate as an argument. Here is a simplified example in C. </font><br>
        <br>
        <font size="2">struct record {</font><br>
        <font size="2"> long long a;</font><br>
        <font size="2"> int b;</font><br>
        <font size="2"> int c;</font><br>
        <font size="2">};</font><br>
        <br>
        <font size="2">int func(struct record r) {</font><br>
        <font size="2"> for (int i = 0; i < r.c; i++)</font><br>
        <font size="2"> r.b++;</font><br>
        <font size="2"> return r.b;</font><br>
        <font size="2">}</font><br>
        <br>
        <font size="2">When updating r.b (or r.c as well), SROA
          generates redundant instructions on some platforms (such as
          x86_64 and ppc64); here, r.b and r.c are packed into one
          64-bit GPR when the struct is passed as a method argument. The
          problem is caused when the same memory location is accessed by
          load/store instructions of different types.</font><br>
        <font size="2">For this example, CLANG generates following IRs
          to initialize the struct for ppc64 and x86_64. For both
          platforms, the 64-bit value is stored into memory allocated by
          alloca first. Later, the same memory location is accessed as
          32-bit integer values (r.b and r.c).</font><br>
        <br>
        <font size="2">for ppc64</font><br>
        <font size="2"> %struct.record = type { i64, i32, i32 }</font><br>
        <br>
        <font size="2"> define signext i32 @ppc64le_func([2 x i64]
          %r.coerce) #0 {</font><br>
        <font size="2"> entry:</font><br>
        <font size="2"> %r = alloca %struct.record, align 8</font><br>
        <font size="2"> %0 = bitcast %struct.record* %r to [2 x i64]*</font><br>
        <font size="2"> store [2 x i64] %r.coerce, [2 x i64]* %0, align
          8</font><br>
        <font size="2"> ....</font><br>
        <br>
        <font size="2">for x86_64</font><br>
        <font size="2"> define i32 @x86_64_func(i64 %r.coerce0, i64
          %r.coerce1) #0 {</font><br>
        <font size="2"> entry:</font><br>
        <font size="2"> %r = alloca %struct.record, align 8</font><br>
        <font size="2"> %0 = bitcast %struct.record* %r to { i64, i64 }*</font><br>
        <font size="2"> %1 = getelementptr inbounds { i64, i64 }, { i64,
          i64 }* %0, i32 0, i32 0</font><br>
        <font size="2"> store i64 %r.coerce0, i64* %1, align 8</font><br>
        <font size="2"> %2 = getelementptr inbounds { i64, i64 }, { i64,
          i64 }* %0, i32 0, i32 1</font><br>
        <font size="2"> store i64 %r.coerce1, i64* %2, align 8</font><br>
        <font size="2"> ....</font><br>
        <br>
        <font size="2">For such code sequence, the current SROA
          generates instructions to update only upper (or lower) half of
          the 64-bit value when storing r.b (or r.c). SROA can split an
          i64 value into two i32 values under some conditions (e.g. when
          the struct contains only int b and int c in this example), but
          it is not capable of splitting complex cases.</font><br>
      </p>
    </blockquote>
    </div></div><p>When there are accesses of mixed type to an alloca, SROA just
      treats the whole alloca as a big integer, and generates PHI nodes
      appropriately.  In many cases, instcombine would then slice up the
      generated PHI nodes to use more appropriate types, but that
      doesn't work out here.  (See
      InstCombiner::<wbr>SliceUpIllegalIntegerPHI.)  Probably the right
      solution is to make instcombine more aggressive here; it's hard to
      come up with a generally useful transform in SROA without
      reasoning about control flow.<br>
    </p>
    <p>-Eli<span class="gmail-HOEnZb"><font color="#888888"><br>
    </font></span></p><span class="gmail-HOEnZb"><font color="#888888">
    <pre class="gmail-m_-2327744573123651316moz-signature" cols="72">-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project</pre>
  </font></span></div>

<br>______________________________<wbr>_________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-dev</a><br>
<br></blockquote></div><br></div></div>