[PATCH] X86: sink splat-shuffle into block doing a shift.

Nadav Rotem nrotem at apple.com
Mon Feb 17 08:38:24 PST 2014


Hi Tim! 

Thanks for working on this. I think that your approach makes sense. Did you look at the AVX512 instruction set? 

 A few comments below:

+bool X86TargetLowering::isVariableVectorShiftExpensive(Type *Ty) const {
+  // Before SSE2 there are no vector shift instructions that LLVM can use, so it
+  // doesn't particularly matter either way whether a shift is variable or not.
+  if (!Subtarget->hasSSE2())
+    return false;
+
+  // With SSE2 and above, there are no 8-bit shifts by vector or scalar: don't
+  // take special steps.
+  unsigned Bits = Ty->getScalarSizeInBits();
+  if (Bits == 8)
+    return false;
+
+  // SSE2 introduced vector-shift-by-scalar instructions (e.g psllw), but before
+  // AVX2 there were no variable shift instructions so it's worth sinking splat
+  // shuffles so they're visible to CodeGen.
+  if (!Subtarget->hasInt256())
+    return true;
+
+  // With AVX2 there are 32-bit and 64-bit variable shifts so they're not
+  // expensive. 8-bit shifts were handled above, leaving 16-bit shifts. It turns
+  // out scalar is still preferable there.
+  return Bits == 16;
+}
+


I think we can handle the 8bit and 16bit together.  I would just write this long function like this: 

bool X86TargetLowering::isVariableVectorShiftExpensive(Type *Ty) const {
 if (Subtarget->hasInt256() && (Bits == 32 || Bits == 64))
   return false;

  return true;
}


This can be extracted into a helper function - isBroadcast / isSplat.

+  SmallVector<int, 16> Mask(SVI->getShuffleMask());
+  int SplatElem = -1;
+  for (unsigned i = 0; i < Mask.size(); ++i) {
+    if (SplatElem != -1 && Mask[i] != -1 && Mask[i] != SplatElem)
+      return false;
+    SplatElem = Mask[i];
+  }


Do we really need this check?  Won’t SelectionDAG CSE it for us?

+  // InsertedShuffles - Only insert a shuffle in each block once.
+  DenseMap<BasicBlock*, Instruction*> InsertedShuffles;
+
+  bool MadeChange = false;
+  for (Value::use_iterator UI = SVI->use_begin(), E = SVI->use_end();
+       UI != E; ++UI) {
+    Instruction *User = cast<Instruction>(*UI);

Won’t SDAG do it for us?

+  // If we removed all uses, nuke the shuffle.
+  if (SVI->use_empty()) {
+    SVI->eraseFromParent();
+    MadeChange = true;
+  }


On Feb 17, 2014, at 7:26 AM, Tim Northover <t.p.northover at gmail.com> wrote:

> <D2816.1.patch>





More information about the llvm-commits mailing list