<div dir="ltr"><div>This should now be fixed at revision 235509.<br><br></div>-Andrea<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 17, 2015 at 2:01 PM, Filipe Cabecinhas <span dir="ltr"><<a href="mailto:filcab@gmail.com" target="_blank">filcab@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">PR23259 was opened and tracked to this revision. It looks like we're just not matching i64 (nor "converting" between i64 and double to match the broadcast).<div><br><div><a href="https://llvm.org/bugs/show_bug.cgi?id=23259" target="_blank">https://llvm.org/bugs/show_bug.cgi?id=23259</a><span class="HOEnZb"><font color="#888888"><br></font></span></div></div></div><div class="gmail_extra"><span class="HOEnZb"><font color="#888888"><br clear="all"><div><div>  F<br></div></div></font></span><div><div class="h5">
<br><div class="gmail_quote">On Mon, Sep 22, 2014 at 7:54 PM, Sanjay Patel <span dir="ltr"><<a href="mailto:spatel@rotateright.com" target="_blank">spatel@rotateright.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: spatel<br>
Date: Mon Sep 22 13:54:01 2014<br>
New Revision: 218263<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=218263&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=218263&view=rev</a><br>
Log:<br>
Use broadcasts to optimize overall size when loading constant splat vectors (x86-64 with AVX or AVX2).<br>
<br>
We generate broadcast instructions on CPUs with AVX2 to load some constant splat vectors.<br>
This patch should preserve all existing behavior with regular optimization levels,<br>
but also use splats whenever possible when optimizing for *size* on any CPU with AVX or AVX2.<br>
<br>
The tradeoff is up to 5 extra instruction bytes for the broadcast instruction to save<br>
at least 8 bytes (up to 31 bytes) of constant pool data.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D5347" target="_blank">http://reviews.llvm.org/D5347</a><br>
<br>
<br>
Added:<br>
    llvm/trunk/test/CodeGen/X86/splat-for-size.ll<br>
Modified:<br>
    llvm/trunk/lib/Target/X86/X86ISelLowering.cpp<br>
    llvm/trunk/lib/Target/X86/X86InstrSSE.td<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=218263&r1=218262&r2=218263&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=218263&r1=218262&r2=218263&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original)<br>
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Sep 22 13:54:01 2014<br>
@@ -5996,7 +5996,10 @@ static SDValue EltsFromConsecutiveLoads(<br>
 /// or SDValue() otherwise.<br>
 static SDValue LowerVectorBroadcast(SDValue Op, const X86Subtarget* Subtarget,<br>
                                     SelectionDAG &DAG) {<br>
-  if (!Subtarget->hasFp256())<br>
+  // VBROADCAST requires AVX.<br>
+  // TODO: Splats could be generated for non-AVX CPUs using SSE<br>
+  // instructions, but there's less potential gain for only 128-bit vectors.<br>
+  if (!Subtarget->hasAVX())<br>
     return SDValue();<br>
<br>
   MVT VT = Op.getSimpleValueType();<br>
@@ -6073,17 +6076,34 @@ static SDValue LowerVectorBroadcast(SDVa<br>
     }<br>
   }<br>
<br>
+  unsigned ScalarSize = Ld.getValueType().getSizeInBits();<br>
   bool IsGE256 = (VT.getSizeInBits() >= 256);<br>
<br>
-  // Handle the broadcasting a single constant scalar from the constant pool<br>
-  // into a vector. On Sandybridge it is still better to load a constant vector<br>
+  // When optimizing for size, generate up to 5 extra bytes for a broadcast<br>
+  // instruction to save 8 or more bytes of constant pool data.<br>
+  // TODO: If multiple splats are generated to load the same constant,<br>
+  // it may be detrimental to overall size. There needs to be a way to detect<br>
+  // that condition to know if this is truly a size win.<br>
+  const Function *F = DAG.getMachineFunction().getFunction();<br>
+  bool OptForSize = F->getAttributes().<br>
+    hasAttribute(AttributeSet::FunctionIndex, Attribute::OptimizeForSize);<br>
+<br>
+  // Handle broadcasting a single constant scalar from the constant pool<br>
+  // into a vector.<br>
+  // On Sandybridge (no AVX2), it is still better to load a constant vector<br>
   // from the constant pool and not to broadcast it from a scalar.<br>
-  if (ConstSplatVal && Subtarget->hasInt256()) {<br>
+  // But override that restriction when optimizing for size.<br>
+  // TODO: Check if splatting is recommended for other AVX-capable CPUs.<br>
+  if (ConstSplatVal && (Subtarget->hasAVX2() || OptForSize)) {<br>
     EVT CVT = Ld.getValueType();<br>
     assert(!CVT.isVector() && "Must not broadcast a vector type");<br>
-    unsigned ScalarSize = CVT.getSizeInBits();<br>
<br>
-    if (ScalarSize == 32 || (IsGE256 && ScalarSize == 64)) {<br>
+    // Splat f32, i32, v4f64, v4i64 in all cases with AVX2.<br>
+    // For size optimization, also splat v2f64 and v2i64, and for size opt<br>
+    // with AVX2, also splat i8 and i16.<br>
+    // With pattern matching, the VBROADCAST node may become a VMOVDDUP.<br>
+    if (ScalarSize == 32 || (IsGE256 && ScalarSize == 64) ||<br>
+        (OptForSize && (ScalarSize == 64 || Subtarget->hasAVX2()))) {<br>
       const Constant *C = nullptr;<br>
       if (ConstantSDNode *CI = dyn_cast<ConstantSDNode>(Ld))<br>
         C = CI->getConstantIntValue();<br>
@@ -6104,7 +6124,6 @@ static SDValue LowerVectorBroadcast(SDVa<br>
   }<br>
<br>
   bool IsLoad = ISD::isNormalLoad(Ld.getNode());<br>
-  unsigned ScalarSize = Ld.getValueType().getSizeInBits();<br>
<br>
   // Handle AVX2 in-register broadcasts.<br>
   if (!IsLoad && Subtarget->hasInt256() &&<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86InstrSSE.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrSSE.td?rev=218263&r1=218262&r2=218263&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrSSE.td?rev=218263&r1=218262&r2=218263&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86InstrSSE.td (original)<br>
+++ llvm/trunk/lib/Target/X86/X86InstrSSE.td Mon Sep 22 13:54:01 2014<br>
@@ -5290,6 +5290,13 @@ let Predicates = [HasAVX] in {<br>
             (VMOVDDUPYrr VR256:$src)>;<br>
 }<br>
<br>
+let Predicates = [UseAVX, OptForSize] in {<br>
+  def : Pat<(v2f64 (X86VBroadcast (loadf64 addr:$src))),<br>
+  (VMOVDDUPrm addr:$src)>;<br>
+  def : Pat<(v2i64 (X86VBroadcast (loadi64 addr:$src))),<br>
+  (VMOVDDUPrm addr:$src)>;<br>
+}<br>
+<br>
 let Predicates = [UseSSE3] in {<br>
   def : Pat<(X86Movddup (memopv2f64 addr:$src)),<br>
             (MOVDDUPrm addr:$src)>;<br>
<br>
Added: llvm/trunk/test/CodeGen/X86/splat-for-size.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/splat-for-size.ll?rev=218263&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/splat-for-size.ll?rev=218263&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/splat-for-size.ll (added)<br>
+++ llvm/trunk/test/CodeGen/X86/splat-for-size.ll Mon Sep 22 13:54:01 2014<br>
@@ -0,0 +1,141 @@<br>
+; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=avx < %s | FileCheck %s -check-prefix=CHECK --check-prefix=AVX<br>
+; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=avx2 < %s | FileCheck %s -check-prefix=CHECK --check-prefix=AVX2<br>
+<br>
+; Check constant loads of every 128-bit and 256-bit vector type<br>
+; for size optimization using splat ops available with AVX and AVX2.<br>
+<br>
+; There is no AVX broadcast from double to 128-bit vector because movddup has been around since SSE3 (grrr).<br>
+define <2 x double> @splat_v2f64(<2 x double> %x) #0 {<br>
+  %add = fadd <2 x double> %x, <double 1.0, double 1.0><br>
+  ret <2 x double> %add<br>
+; CHECK-LABEL: splat_v2f64<br>
+; CHECK: vmovddup<br>
+; CHECK: vaddpd<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+define <4 x double> @splat_v4f64(<4 x double> %x) #0 {<br>
+  %add = fadd <4 x double> %x, <double 1.0, double 1.0, double 1.0, double 1.0><br>
+  ret <4 x double> %add<br>
+; CHECK-LABEL: splat_v4f64<br>
+; CHECK: vbroadcastsd<br>
+; CHECK-NEXT: vaddpd<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+define <4 x float> @splat_v4f32(<4 x float> %x) #0 {<br>
+  %add = fadd <4 x float> %x, <float 1.0, float 1.0, float 1.0, float 1.0><br>
+  ret <4 x float> %add<br>
+; CHECK-LABEL: splat_v4f32<br>
+; CHECK: vbroadcastss<br>
+; CHECK-NEXT: vaddps<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+define <8 x float> @splat_v8f32(<8 x float> %x) #0 {<br>
+  %add = fadd <8 x float> %x, <float 1.0, float 1.0, float 1.0, float 1.0, float 1.0, float 1.0, float 1.0, float 1.0><br>
+  ret <8 x float> %add<br>
+; CHECK-LABEL: splat_v8f32<br>
+; CHECK: vbroadcastss<br>
+; CHECK-NEXT: vaddps<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, so fake it: use vmovddup to splat 64-bit value.<br>
+; We also generate vmovddup for AVX2 because it's one byte smaller than vpbroadcastq.<br>
+define <2 x i64> @splat_v2i64(<2 x i64> %x) #0 {<br>
+  %add = add <2 x i64> %x, <i64 1, i64 1><br>
+  ret <2 x i64> %add<br>
+; CHECK-LABEL: splat_v2i64<br>
+; CHECK: vmovddup<br>
+; CHECK: vpaddq<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+; AVX can't do 256-bit integer ops, so we split this into two 128-bit vectors,<br>
+; and then we fake it: use vmovddup to splat 64-bit value.<br>
+define <4 x i64> @splat_v4i64(<4 x i64> %x) #0 {<br>
+  %add = add <4 x i64> %x, <i64 1, i64 1, i64 1, i64 1><br>
+  ret <4 x i64> %add<br>
+; CHECK-LABEL: splat_v4i64<br>
+; AVX: vmovddup<br>
+; AVX: vpaddq<br>
+; AVX: vpaddq<br>
+; AVX2: vpbroadcastq<br>
+; AVX2: vpaddq<br>
+; CHECK: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, so fake it: use vbroadcastss to splat 32-bit value.<br>
+define <4 x i32> @splat_v4i32(<4 x i32> %x) #0 {<br>
+  %add = add <4 x i32> %x, <i32 1, i32 1, i32 1, i32 1><br>
+  ret <4 x i32> %add<br>
+; CHECK-LABEL: splat_v4i32<br>
+; AVX: vbroadcastss<br>
+; AVX2: vpbroadcastd<br>
+; CHECK-NEXT: vpaddd<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, so fake it: use vbroadcastss to splat 32-bit value.<br>
+define <8 x i32> @splat_v8i32(<8 x i32> %x) #0 {<br>
+  %add = add <8 x i32> %x, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1><br>
+  ret <8 x i32> %add<br>
+; CHECK-LABEL: splat_v8i32<br>
+; AVX: vbroadcastss<br>
+; AVX: vpaddd<br>
+; AVX: vpaddd<br>
+; AVX2: vpbroadcastd<br>
+; AVX2: vpaddd<br>
+; CHECK: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, and there's no broadcast fakery for 16-bit. Could use pshuflw, etc?<br>
+define <8 x i16> @splat_v8i16(<8 x i16> %x) #0 {<br>
+  %add = add <8 x i16> %x, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1><br>
+  ret <8 x i16> %add<br>
+; CHECK-LABEL: splat_v8i16<br>
+; AVX-NOT: broadcast<br>
+; AVX2: vpbroadcastw<br>
+; CHECK: vpaddw<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, and there's no broadcast fakery for 16-bit. Could use pshuflw, etc?<br>
+define <16 x i16> @splat_v16i16(<16 x i16> %x) #0 {<br>
+  %add = add <16 x i16> %x, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1><br>
+  ret <16 x i16> %add<br>
+; CHECK-LABEL: splat_v16i16<br>
+; AVX-NOT: broadcast<br>
+; AVX: vpaddw<br>
+; AVX: vpaddw<br>
+; AVX2: vpbroadcastw<br>
+; AVX2: vpaddw<br>
+; CHECK: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, and there's no broadcast fakery for 8-bit. Could use pshufb, etc?<br>
+define <16 x i8> @splat_v16i8(<16 x i8> %x) #0 {<br>
+  %add = add <16 x i8> %x, <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1><br>
+  ret <16 x i8> %add<br>
+; CHECK-LABEL: splat_v16i8<br>
+; AVX-NOT: broadcast<br>
+; AVX2: vpbroadcastb<br>
+; CHECK: vpaddb<br>
+; CHECK-NEXT: retq<br>
+}<br>
+<br>
+; AVX can't do integer splats, and there's no broadcast fakery for 8-bit. Could use pshufb, etc?<br>
+define <32 x i8> @splat_v32i8(<32 x i8> %x) #0 {<br>
+  %add = add <32 x i8> %x, <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1><br>
+  ret <32 x i8> %add<br>
+; CHECK-LABEL: splat_v32i8<br>
+; AVX-NOT: broadcast<br>
+; AVX: vpaddb<br>
+; AVX: vpaddb<br>
+; AVX2: vpbroadcastb<br>
+; AVX2: vpaddb<br>
+; CHECK: retq<br>
+}<br>
+<br>
+attributes #0 = { optsize }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">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>
</blockquote></div><br></div></div></div>
<br>_______________________________________________<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>