<div dir="ltr"><div>Hi Andrea,<br><br></div>I don't doubt that blends have better throughput on SB/Haswell, but the change should not have been applied to all subtargets universally because of the size disadvantage of blend instructions.<br><br>If fixing these up after regalloc is the preferred solution, I'll look into that. But does limiting these patterns to match specific chips in tablegen change anything in the shuffle lowering logic? <br><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Apr 2, 2015 at 11:54 AM, Andrea Di Biagio <span dir="ltr"><<a href="mailto:andrea.dibiagio@gmail.com" target="_blank">andrea.dibiagio@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Sanjay,<br>
<span class=""><br>
On Thu, Apr 2, 2015 at 6:01 PM, Sanjay Patel <<a href="mailto:spatel@rotateright.com">spatel@rotateright.com</a>> wrote:<br>
> Patch updated again:<br>
><br>
> I removed all of the changes related to blend vs. movs, so this patch is now purely about adjusting the AddedComplexity to fix PR23073.<br>
><br>
> I did some svn blaming and see the reasoning for the blend patterns. These were added in r219022 by Chandler. But I think that change overstepped, so I've put some FIXMEs in here. I think the procedure is to follow-up on the commit mail for that checkin, so I'll do that next<br>
<br>
</span>Hi Sanjay,<br>
<br>
I don't think those patterns are a mistake. Blend instructions always<br>
have better reciprocal throughput than movss on<br>
SandyBridge/IvyBridge/Haswell. On Haswell, a blend instruction has<br>
0.33 reciprocal throughput because it can be scheduled for execution<br>
on three different ports. On Jaguar and other AMD chips, blendps<br>
doesn't have a better throughput with respect to movss; so movss may<br>
be a better choice.<br>
<br>
I remember this problem was raised a while ago during the evaluation<br>
of the new shuffle lowering, and Chandler suggested to add some logic<br>
to simplify the machine code (after regalloc) matching all the complex<br>
variants of movs[s|d] (and potentially converting blends to movs if<br>
necessary).<br>
>From a 'shuffle lowering' (and ISel) point of view, it was easier to<br>
reason in terms of blends rather than movss. movss/d have a<br>
memory-register form that is quite complicated to match..<br>
<br>
-Andrea<br>
<div><div class="h5"><br>
><br>
><br>
> <a href="http://reviews.llvm.org/D8794" target="_blank">http://reviews.llvm.org/D8794</a><br>
><br>
> Files:<br>
>   lib/Target/X86/X86InstrSSE.td<br>
>   test/CodeGen/X86/vector-shuffle-256-v4.ll<br>
>   test/CodeGen/X86/vector-shuffle-256-v8.ll<br>
><br>
> Index: lib/Target/X86/X86InstrSSE.td<br>
> ===================================================================<br>
> --- lib/Target/X86/X86InstrSSE.td<br>
> +++ lib/Target/X86/X86InstrSSE.td<br>
> @@ -7168,6 +7168,10 @@<br>
>  }<br>
><br>
>  // Patterns<br>
> +// FIXME: Prefer a movss or movsd over a blendps when optimizing for size or<br>
> +// on targets where they have equal performance. These were changed to use<br>
> +// blends because blends have better throughput on SandyBridge and Haswell, but<br>
> +// movs[s/d] are 1-2 byte shorter instructions.<br>
>  let Predicates = [UseAVX] in {<br>
>    let AddedComplexity = 15 in {<br>
>    // Move scalar to XMM zero-extended, zeroing a VR128 then do a<br>
> @@ -7184,8 +7188,10 @@<br>
>    // Move low f32 and clear high bits.<br>
>    def : Pat<(v8f32 (X86vzmovl (v8f32 VR256:$src))),<br>
>              (VBLENDPSYrri (v8f32 (AVX_SET0)), VR256:$src, (i8 1))>;<br>
> -  def : Pat<(v8i32 (X86vzmovl (v8i32 VR256:$src))),<br>
> -            (VBLENDPSYrri (v8i32 (AVX_SET0)), VR256:$src, (i8 1))>;<br>
> +<br>
> +  // Move low f64 and clear high bits.<br>
> +  def : Pat<(v4f64 (X86vzmovl (v4f64 VR256:$src))),<br>
> +            (VBLENDPDYrri (v4f64 (AVX_SET0)), VR256:$src, (i8 1))>;<br>
>    }<br>
><br>
>    def : Pat<(v8f32 (X86vzmovl (insert_subvector undef,<br>
> @@ -7199,14 +7205,19 @@<br>
>                             (v2f64 (VMOVSDrr (v2f64 (V_SET0)), FR64:$src)),<br>
>                             sub_xmm)>;<br>
><br>
> -  // Move low f64 and clear high bits.<br>
> -  def : Pat<(v4f64 (X86vzmovl (v4f64 VR256:$src))),<br>
> -            (VBLENDPDYrri (v4f64 (AVX_SET0)), VR256:$src, (i8 1))>;<br>
> -<br>
> +  // These will incur an FP/int domain crossing penalty, but it may be the only<br>
> +  // way without AVX2. Do not add any complexity because we may be able to match<br>
> +  // more optimal patterns defined earlier in this file.<br>
> +  def : Pat<(v8i32 (X86vzmovl (v8i32 VR256:$src))),<br>
> +            (VBLENDPSYrri (v8i32 (AVX_SET0)), VR256:$src, (i8 1))>;<br>
>    def : Pat<(v4i64 (X86vzmovl (v4i64 VR256:$src))),<br>
>              (VBLENDPDYrri (v4i64 (AVX_SET0)), VR256:$src, (i8 1))>;<br>
>  }<br>
><br>
> +// FIXME: Prefer a movss or movsd over a blendps when optimizing for size or<br>
> +// on targets where they have equal performance. These were changed to use<br>
> +// blends because blends have better throughput on SandyBridge and Haswell, but<br>
> +// movs[s/d] are 1-2 byte shorter instructions.<br>
>  let Predicates = [UseSSE41] in {<br>
>    // With SSE41 we can use blends for these patterns.<br>
>    def : Pat<(v4f32 (X86vzmovl (v4f32 VR128:$src))),<br>
> Index: test/CodeGen/X86/vector-shuffle-256-v4.ll<br>
> ===================================================================<br>
> --- test/CodeGen/X86/vector-shuffle-256-v4.ll<br>
> +++ test/CodeGen/X86/vector-shuffle-256-v4.ll<br>
> @@ -843,8 +843,9 @@<br>
>  define <4 x double> @insert_reg_and_zero_v4f64(double %a) {<br>
>  ; ALL-LABEL: insert_reg_and_zero_v4f64:<br>
>  ; ALL:       # BB#0:<br>
> -; ALL-NEXT:    vxorpd %xmm1, %xmm1, %xmm1<br>
> -; ALL-NEXT:    vmovsd {{.*#+}} xmm0 = xmm0[0],xmm1[1]<br>
> +; ALL-NEXT:    # kill: XMM0<def> XMM0<kill> YMM0<def><br>
> +; ALL-NEXT:    vxorpd %ymm1, %ymm1, %ymm1<br>
> +; ALL-NEXT:    vblendpd {{.*#+}} ymm0 = ymm0[0],ymm1[1,2,3]<br>
>  ; ALL-NEXT:    retq<br>
>    %v = insertelement <4 x double> undef, double %a, i32 0<br>
>    %shuffle = shufflevector <4 x double> %v, <4 x double> zeroinitializer, <4 x i32> <i32 0, i32 5, i32 6, i32 7><br>
> Index: test/CodeGen/X86/vector-shuffle-256-v8.ll<br>
> ===================================================================<br>
> --- test/CodeGen/X86/vector-shuffle-256-v8.ll<br>
> +++ test/CodeGen/X86/vector-shuffle-256-v8.ll<br>
> @@ -133,8 +133,6 @@<br>
>  ; AVX2:       # BB#0:<br>
>  ; AVX2-NEXT:    movl $7, %eax<br>
>  ; AVX2-NEXT:    vmovd %eax, %xmm1<br>
> -; AVX2-NEXT:    vxorps %ymm2, %ymm2, %ymm2<br>
> -; AVX2-NEXT:    vblendps {{.*#+}} ymm1 = ymm1[0],ymm2[1,2,3,4,5,6,7]<br>
>  ; AVX2-NEXT:    vpermps %ymm0, %ymm1, %ymm0<br>
>  ; AVX2-NEXT:    retq<br>
>    %shuffle = shufflevector <8 x float> %a, <8 x float> %b, <8 x i32> <i32 7, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0><br>
> @@ -962,8 +960,6 @@<br>
>  ; AVX2:       # BB#0:<br>
>  ; AVX2-NEXT:    movl $7, %eax<br>
>  ; AVX2-NEXT:    vmovd %eax, %xmm1<br>
> -; AVX2-NEXT:    vxorps %ymm2, %ymm2, %ymm2<br>
> -; AVX2-NEXT:    vblendps {{.*#+}} ymm1 = ymm1[0],ymm2[1,2,3,4,5,6,7]<br>
>  ; AVX2-NEXT:    vpermd %ymm0, %ymm1, %ymm0<br>
>  ; AVX2-NEXT:    retq<br>
>    %shuffle = shufflevector <8 x i32> %a, <8 x i32> %b, <8 x i32> <i32 7, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0><br>
><br>
> EMAIL PREFERENCES<br>
>   <a href="http://reviews.llvm.org/settings/panel/emailpreferences/" target="_blank">http://reviews.llvm.org/settings/panel/emailpreferences/</a><br>
><br>
</div></div>> _______________________________________________<br>
> llvm-commits mailing list<br>
> <a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
><br>
</blockquote></div><br></div>