1*9f7d4150SCraig Topper //===-- X86PartialReduction.cpp -------------------------------------------===//
2*9f7d4150SCraig Topper //
3*9f7d4150SCraig Topper // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*9f7d4150SCraig Topper // See https://llvm.org/LICENSE.txt for license information.
5*9f7d4150SCraig Topper // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*9f7d4150SCraig Topper //
7*9f7d4150SCraig Topper //===----------------------------------------------------------------------===//
8*9f7d4150SCraig Topper //
9*9f7d4150SCraig Topper // This pass looks for add instructions used by a horizontal reduction to see
10*9f7d4150SCraig Topper // if we might be able to use pmaddwd or psadbw. Some cases of this require
11*9f7d4150SCraig Topper // cross basic block knowledge and can't be done in SelectionDAG.
12*9f7d4150SCraig Topper //
13*9f7d4150SCraig Topper //===----------------------------------------------------------------------===//
14*9f7d4150SCraig Topper 
15*9f7d4150SCraig Topper #include "X86.h"
16*9f7d4150SCraig Topper #include "llvm/Analysis/ValueTracking.h"
17*9f7d4150SCraig Topper #include "llvm/CodeGen/TargetPassConfig.h"
18*9f7d4150SCraig Topper #include "llvm/IR/Constants.h"
19*9f7d4150SCraig Topper #include "llvm/IR/Instructions.h"
20*9f7d4150SCraig Topper #include "llvm/IR/IntrinsicsX86.h"
21*9f7d4150SCraig Topper #include "llvm/IR/IRBuilder.h"
22*9f7d4150SCraig Topper #include "llvm/IR/Operator.h"
23*9f7d4150SCraig Topper #include "llvm/Pass.h"
24*9f7d4150SCraig Topper #include "X86TargetMachine.h"
25*9f7d4150SCraig Topper 
26*9f7d4150SCraig Topper using namespace llvm;
27*9f7d4150SCraig Topper 
28*9f7d4150SCraig Topper #define DEBUG_TYPE "x86-partial-reduction"
29*9f7d4150SCraig Topper 
30*9f7d4150SCraig Topper namespace {
31*9f7d4150SCraig Topper 
32*9f7d4150SCraig Topper class X86PartialReduction : public FunctionPass {
33*9f7d4150SCraig Topper   const DataLayout *DL;
34*9f7d4150SCraig Topper   const X86Subtarget *ST;
35*9f7d4150SCraig Topper 
36*9f7d4150SCraig Topper public:
37*9f7d4150SCraig Topper   static char ID; // Pass identification, replacement for typeid.
38*9f7d4150SCraig Topper 
39*9f7d4150SCraig Topper   X86PartialReduction() : FunctionPass(ID) { }
40*9f7d4150SCraig Topper 
41*9f7d4150SCraig Topper   bool runOnFunction(Function &Fn) override;
42*9f7d4150SCraig Topper 
43*9f7d4150SCraig Topper   void getAnalysisUsage(AnalysisUsage &AU) const override {
44*9f7d4150SCraig Topper     AU.setPreservesCFG();
45*9f7d4150SCraig Topper   }
46*9f7d4150SCraig Topper 
47*9f7d4150SCraig Topper   StringRef getPassName() const override {
48*9f7d4150SCraig Topper     return "X86 Partial Reduction";
49*9f7d4150SCraig Topper   }
50*9f7d4150SCraig Topper 
51*9f7d4150SCraig Topper private:
52*9f7d4150SCraig Topper   bool tryMAddPattern(BinaryOperator *BO);
53*9f7d4150SCraig Topper   bool tryMAddReplacement(Value *Op, BinaryOperator *Add);
54*9f7d4150SCraig Topper 
55*9f7d4150SCraig Topper   bool trySADPattern(BinaryOperator *BO);
56*9f7d4150SCraig Topper   bool trySADReplacement(Value *Op, BinaryOperator *Add);
57*9f7d4150SCraig Topper };
58*9f7d4150SCraig Topper }
59*9f7d4150SCraig Topper 
60*9f7d4150SCraig Topper FunctionPass *llvm::createX86PartialReductionPass() {
61*9f7d4150SCraig Topper   return new X86PartialReduction();
62*9f7d4150SCraig Topper }
63*9f7d4150SCraig Topper 
64*9f7d4150SCraig Topper char X86PartialReduction::ID = 0;
65*9f7d4150SCraig Topper 
66*9f7d4150SCraig Topper INITIALIZE_PASS(X86PartialReduction, DEBUG_TYPE,
67*9f7d4150SCraig Topper                 "X86 Partial Reduction", false, false)
68*9f7d4150SCraig Topper 
69*9f7d4150SCraig Topper static bool isVectorReductionOp(const BinaryOperator &BO) {
70*9f7d4150SCraig Topper   if (!BO.getType()->isVectorTy())
71*9f7d4150SCraig Topper     return false;
72*9f7d4150SCraig Topper 
73*9f7d4150SCraig Topper   unsigned Opcode = BO.getOpcode();
74*9f7d4150SCraig Topper 
75*9f7d4150SCraig Topper   switch (Opcode) {
76*9f7d4150SCraig Topper   case Instruction::Add:
77*9f7d4150SCraig Topper   case Instruction::Mul:
78*9f7d4150SCraig Topper   case Instruction::And:
79*9f7d4150SCraig Topper   case Instruction::Or:
80*9f7d4150SCraig Topper   case Instruction::Xor:
81*9f7d4150SCraig Topper     break;
82*9f7d4150SCraig Topper   case Instruction::FAdd:
83*9f7d4150SCraig Topper   case Instruction::FMul:
84*9f7d4150SCraig Topper     if (auto *FPOp = dyn_cast<FPMathOperator>(&BO))
85*9f7d4150SCraig Topper       if (FPOp->getFastMathFlags().isFast())
86*9f7d4150SCraig Topper         break;
87*9f7d4150SCraig Topper     LLVM_FALLTHROUGH;
88*9f7d4150SCraig Topper   default:
89*9f7d4150SCraig Topper     return false;
90*9f7d4150SCraig Topper   }
91*9f7d4150SCraig Topper 
92*9f7d4150SCraig Topper   unsigned ElemNum = BO.getType()->getVectorNumElements();
93*9f7d4150SCraig Topper   // Ensure the reduction size is a power of 2.
94*9f7d4150SCraig Topper   if (!isPowerOf2_32(ElemNum))
95*9f7d4150SCraig Topper     return false;
96*9f7d4150SCraig Topper 
97*9f7d4150SCraig Topper   unsigned ElemNumToReduce = ElemNum;
98*9f7d4150SCraig Topper 
99*9f7d4150SCraig Topper   // Do DFS search on the def-use chain from the given instruction. We only
100*9f7d4150SCraig Topper   // allow four kinds of operations during the search until we reach the
101*9f7d4150SCraig Topper   // instruction that extracts the first element from the vector:
102*9f7d4150SCraig Topper   //
103*9f7d4150SCraig Topper   //   1. The reduction operation of the same opcode as the given instruction.
104*9f7d4150SCraig Topper   //
105*9f7d4150SCraig Topper   //   2. PHI node.
106*9f7d4150SCraig Topper   //
107*9f7d4150SCraig Topper   //   3. ShuffleVector instruction together with a reduction operation that
108*9f7d4150SCraig Topper   //      does a partial reduction.
109*9f7d4150SCraig Topper   //
110*9f7d4150SCraig Topper   //   4. ExtractElement that extracts the first element from the vector, and we
111*9f7d4150SCraig Topper   //      stop searching the def-use chain here.
112*9f7d4150SCraig Topper   //
113*9f7d4150SCraig Topper   // 3 & 4 above perform a reduction on all elements of the vector. We push defs
114*9f7d4150SCraig Topper   // from 1-3 to the stack to continue the DFS. The given instruction is not
115*9f7d4150SCraig Topper   // a reduction operation if we meet any other instructions other than those
116*9f7d4150SCraig Topper   // listed above.
117*9f7d4150SCraig Topper 
118*9f7d4150SCraig Topper   SmallVector<const User *, 16> UsersToVisit{&BO};
119*9f7d4150SCraig Topper   SmallPtrSet<const User *, 16> Visited;
120*9f7d4150SCraig Topper   bool ReduxExtracted = false;
121*9f7d4150SCraig Topper 
122*9f7d4150SCraig Topper   while (!UsersToVisit.empty()) {
123*9f7d4150SCraig Topper     auto User = UsersToVisit.back();
124*9f7d4150SCraig Topper     UsersToVisit.pop_back();
125*9f7d4150SCraig Topper     if (!Visited.insert(User).second)
126*9f7d4150SCraig Topper       continue;
127*9f7d4150SCraig Topper 
128*9f7d4150SCraig Topper     for (const auto *U : User->users()) {
129*9f7d4150SCraig Topper       auto *Inst = dyn_cast<Instruction>(U);
130*9f7d4150SCraig Topper       if (!Inst)
131*9f7d4150SCraig Topper         return false;
132*9f7d4150SCraig Topper 
133*9f7d4150SCraig Topper       if (Inst->getOpcode() == Opcode || isa<PHINode>(U)) {
134*9f7d4150SCraig Topper         if (auto *FPOp = dyn_cast<FPMathOperator>(Inst))
135*9f7d4150SCraig Topper           if (!isa<PHINode>(FPOp) && !FPOp->getFastMathFlags().isFast())
136*9f7d4150SCraig Topper             return false;
137*9f7d4150SCraig Topper         UsersToVisit.push_back(U);
138*9f7d4150SCraig Topper       } else if (auto *ShufInst = dyn_cast<ShuffleVectorInst>(U)) {
139*9f7d4150SCraig Topper         // Detect the following pattern: A ShuffleVector instruction together
140*9f7d4150SCraig Topper         // with a reduction that do partial reduction on the first and second
141*9f7d4150SCraig Topper         // ElemNumToReduce / 2 elements, and store the result in
142*9f7d4150SCraig Topper         // ElemNumToReduce / 2 elements in another vector.
143*9f7d4150SCraig Topper 
144*9f7d4150SCraig Topper         unsigned ResultElements = ShufInst->getType()->getVectorNumElements();
145*9f7d4150SCraig Topper         if (ResultElements < ElemNum)
146*9f7d4150SCraig Topper           return false;
147*9f7d4150SCraig Topper 
148*9f7d4150SCraig Topper         if (ElemNumToReduce == 1)
149*9f7d4150SCraig Topper           return false;
150*9f7d4150SCraig Topper         if (!isa<UndefValue>(U->getOperand(1)))
151*9f7d4150SCraig Topper           return false;
152*9f7d4150SCraig Topper         for (unsigned i = 0; i < ElemNumToReduce / 2; ++i)
153*9f7d4150SCraig Topper           if (ShufInst->getMaskValue(i) != int(i + ElemNumToReduce / 2))
154*9f7d4150SCraig Topper             return false;
155*9f7d4150SCraig Topper         for (unsigned i = ElemNumToReduce / 2; i < ElemNum; ++i)
156*9f7d4150SCraig Topper           if (ShufInst->getMaskValue(i) != -1)
157*9f7d4150SCraig Topper             return false;
158*9f7d4150SCraig Topper 
159*9f7d4150SCraig Topper         // There is only one user of this ShuffleVector instruction, which
160*9f7d4150SCraig Topper         // must be a reduction operation.
161*9f7d4150SCraig Topper         if (!U->hasOneUse())
162*9f7d4150SCraig Topper           return false;
163*9f7d4150SCraig Topper 
164*9f7d4150SCraig Topper         auto *U2 = dyn_cast<BinaryOperator>(*U->user_begin());
165*9f7d4150SCraig Topper         if (!U2 || U2->getOpcode() != Opcode)
166*9f7d4150SCraig Topper           return false;
167*9f7d4150SCraig Topper 
168*9f7d4150SCraig Topper         // Check operands of the reduction operation.
169*9f7d4150SCraig Topper         if ((U2->getOperand(0) == U->getOperand(0) && U2->getOperand(1) == U) ||
170*9f7d4150SCraig Topper             (U2->getOperand(1) == U->getOperand(0) && U2->getOperand(0) == U)) {
171*9f7d4150SCraig Topper           UsersToVisit.push_back(U2);
172*9f7d4150SCraig Topper           ElemNumToReduce /= 2;
173*9f7d4150SCraig Topper         } else
174*9f7d4150SCraig Topper           return false;
175*9f7d4150SCraig Topper       } else if (isa<ExtractElementInst>(U)) {
176*9f7d4150SCraig Topper         // At this moment we should have reduced all elements in the vector.
177*9f7d4150SCraig Topper         if (ElemNumToReduce != 1)
178*9f7d4150SCraig Topper           return false;
179*9f7d4150SCraig Topper 
180*9f7d4150SCraig Topper         auto *Val = dyn_cast<ConstantInt>(U->getOperand(1));
181*9f7d4150SCraig Topper         if (!Val || !Val->isZero())
182*9f7d4150SCraig Topper           return false;
183*9f7d4150SCraig Topper 
184*9f7d4150SCraig Topper         ReduxExtracted = true;
185*9f7d4150SCraig Topper       } else
186*9f7d4150SCraig Topper         return false;
187*9f7d4150SCraig Topper     }
188*9f7d4150SCraig Topper   }
189*9f7d4150SCraig Topper   return ReduxExtracted;
190*9f7d4150SCraig Topper }
191*9f7d4150SCraig Topper 
192*9f7d4150SCraig Topper bool X86PartialReduction::tryMAddReplacement(Value *Op, BinaryOperator *Add) {
193*9f7d4150SCraig Topper   BasicBlock *BB = Add->getParent();
194*9f7d4150SCraig Topper 
195*9f7d4150SCraig Topper   auto *BO = dyn_cast<BinaryOperator>(Op);
196*9f7d4150SCraig Topper   if (!BO || BO->getOpcode() != Instruction::Mul || !BO->hasOneUse() ||
197*9f7d4150SCraig Topper       BO->getParent() != BB)
198*9f7d4150SCraig Topper     return false;
199*9f7d4150SCraig Topper 
200*9f7d4150SCraig Topper   Value *LHS = BO->getOperand(0);
201*9f7d4150SCraig Topper   Value *RHS = BO->getOperand(1);
202*9f7d4150SCraig Topper 
203*9f7d4150SCraig Topper   // LHS and RHS should be only used once or if they are the same then only
204*9f7d4150SCraig Topper   // used twice. Only check this when SSE4.1 is enabled and we have zext/sext
205*9f7d4150SCraig Topper   // instructions, otherwise we use punpck to emulate zero extend in stages. The
206*9f7d4150SCraig Topper   // trunc/ we need to do likely won't introduce new instructions in that case.
207*9f7d4150SCraig Topper   if (ST->hasSSE41()) {
208*9f7d4150SCraig Topper     if (LHS == RHS) {
209*9f7d4150SCraig Topper       if (!isa<Constant>(LHS) && !LHS->hasNUses(2))
210*9f7d4150SCraig Topper         return false;
211*9f7d4150SCraig Topper     } else {
212*9f7d4150SCraig Topper       if (!isa<Constant>(LHS) && !LHS->hasOneUse())
213*9f7d4150SCraig Topper         return false;
214*9f7d4150SCraig Topper       if (!isa<Constant>(RHS) && !RHS->hasOneUse())
215*9f7d4150SCraig Topper         return false;
216*9f7d4150SCraig Topper     }
217*9f7d4150SCraig Topper   }
218*9f7d4150SCraig Topper 
219*9f7d4150SCraig Topper   auto canShrinkOp = [&](Value *Op) {
220*9f7d4150SCraig Topper     if (isa<Constant>(Op) && ComputeNumSignBits(Op, *DL, 0, nullptr, BO) > 16)
221*9f7d4150SCraig Topper       return true;
222*9f7d4150SCraig Topper     if (auto *Cast = dyn_cast<CastInst>(Op)) {
223*9f7d4150SCraig Topper       if (Cast->getParent() == BB &&
224*9f7d4150SCraig Topper           (Cast->getOpcode() == Instruction::SExt ||
225*9f7d4150SCraig Topper            Cast->getOpcode() == Instruction::ZExt) &&
226*9f7d4150SCraig Topper           ComputeNumSignBits(Op, *DL, 0, nullptr, BO) > 16)
227*9f7d4150SCraig Topper         return true;
228*9f7d4150SCraig Topper     }
229*9f7d4150SCraig Topper 
230*9f7d4150SCraig Topper     return false;
231*9f7d4150SCraig Topper   };
232*9f7d4150SCraig Topper 
233*9f7d4150SCraig Topper   // Both Ops need to be shrinkable.
234*9f7d4150SCraig Topper   if (!canShrinkOp(LHS) && !canShrinkOp(RHS))
235*9f7d4150SCraig Topper     return false;
236*9f7d4150SCraig Topper 
237*9f7d4150SCraig Topper   IRBuilder<> Builder(Add);
238*9f7d4150SCraig Topper 
239*9f7d4150SCraig Topper   Type *MulTy = Op->getType();
240*9f7d4150SCraig Topper   unsigned NumElts = MulTy->getVectorNumElements();
241*9f7d4150SCraig Topper 
242*9f7d4150SCraig Topper   // Extract even elements and odd elements and add them together. This will
243*9f7d4150SCraig Topper   // be pattern matched by SelectionDAG to pmaddwd. This instruction will be
244*9f7d4150SCraig Topper   // half the original width.
245*9f7d4150SCraig Topper   SmallVector<uint32_t, 16> EvenMask(NumElts / 2);
246*9f7d4150SCraig Topper   SmallVector<uint32_t, 16> OddMask(NumElts / 2);
247*9f7d4150SCraig Topper   for (int i = 0, e = NumElts / 2; i != e; ++i) {
248*9f7d4150SCraig Topper     EvenMask[i] = i * 2;
249*9f7d4150SCraig Topper     OddMask[i] = i * 2 + 1;
250*9f7d4150SCraig Topper   }
251*9f7d4150SCraig Topper   Value *EvenElts = Builder.CreateShuffleVector(BO, BO, EvenMask);
252*9f7d4150SCraig Topper   Value *OddElts = Builder.CreateShuffleVector(BO, BO, OddMask);
253*9f7d4150SCraig Topper   Value *MAdd = Builder.CreateAdd(EvenElts, OddElts);
254*9f7d4150SCraig Topper 
255*9f7d4150SCraig Topper   // Concatenate zeroes to extend back to the original type.
256*9f7d4150SCraig Topper   SmallVector<uint32_t, 32> ConcatMask(NumElts);
257*9f7d4150SCraig Topper   std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
258*9f7d4150SCraig Topper   Value *Zero = Constant::getNullValue(MAdd->getType());
259*9f7d4150SCraig Topper   Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask);
260*9f7d4150SCraig Topper 
261*9f7d4150SCraig Topper   // Replaces the use of mul in the original Add with the pmaddwd and zeroes.
262*9f7d4150SCraig Topper   Add->replaceUsesOfWith(BO, Concat);
263*9f7d4150SCraig Topper   Add->setHasNoSignedWrap(false);
264*9f7d4150SCraig Topper   Add->setHasNoUnsignedWrap(false);
265*9f7d4150SCraig Topper 
266*9f7d4150SCraig Topper   return true;
267*9f7d4150SCraig Topper }
268*9f7d4150SCraig Topper 
269*9f7d4150SCraig Topper // Try to replace operans of this add with pmaddwd patterns.
270*9f7d4150SCraig Topper bool X86PartialReduction::tryMAddPattern(BinaryOperator *BO) {
271*9f7d4150SCraig Topper   if (!ST->hasSSE2())
272*9f7d4150SCraig Topper     return false;
273*9f7d4150SCraig Topper 
274*9f7d4150SCraig Topper   // Need at least 8 elements.
275*9f7d4150SCraig Topper   if (BO->getType()->getVectorNumElements() < 8)
276*9f7d4150SCraig Topper     return false;
277*9f7d4150SCraig Topper 
278*9f7d4150SCraig Topper   // Element type should be i32.
279*9f7d4150SCraig Topper   if (!BO->getType()->getVectorElementType()->isIntegerTy(32))
280*9f7d4150SCraig Topper     return false;
281*9f7d4150SCraig Topper 
282*9f7d4150SCraig Topper   bool Changed = false;
283*9f7d4150SCraig Topper   Changed |= tryMAddReplacement(BO->getOperand(0), BO);
284*9f7d4150SCraig Topper   Changed |= tryMAddReplacement(BO->getOperand(1), BO);
285*9f7d4150SCraig Topper   return Changed;
286*9f7d4150SCraig Topper }
287*9f7d4150SCraig Topper 
288*9f7d4150SCraig Topper bool X86PartialReduction::trySADReplacement(Value *Op, BinaryOperator *Add) {
289*9f7d4150SCraig Topper   // Operand should be a select.
290*9f7d4150SCraig Topper   auto *SI = dyn_cast<SelectInst>(Op);
291*9f7d4150SCraig Topper   if (!SI)
292*9f7d4150SCraig Topper     return false;
293*9f7d4150SCraig Topper 
294*9f7d4150SCraig Topper   // Select needs to implement absolute value.
295*9f7d4150SCraig Topper   Value *LHS, *RHS;
296*9f7d4150SCraig Topper   auto SPR = matchSelectPattern(SI, LHS, RHS);
297*9f7d4150SCraig Topper   if (SPR.Flavor != SPF_ABS)
298*9f7d4150SCraig Topper     return false;
299*9f7d4150SCraig Topper 
300*9f7d4150SCraig Topper   // Need a subtract of two values.
301*9f7d4150SCraig Topper   auto *Sub = dyn_cast<BinaryOperator>(LHS);
302*9f7d4150SCraig Topper   if (!Sub || Sub->getOpcode() != Instruction::Sub)
303*9f7d4150SCraig Topper     return false;
304*9f7d4150SCraig Topper 
305*9f7d4150SCraig Topper   // Look for zero extend from i8.
306*9f7d4150SCraig Topper   auto getZeroExtendedVal = [](Value *Op) -> Value * {
307*9f7d4150SCraig Topper     if (auto *ZExt = dyn_cast<ZExtInst>(Op))
308*9f7d4150SCraig Topper       if (ZExt->getOperand(0)->getType()->getVectorElementType()->isIntegerTy(8))
309*9f7d4150SCraig Topper         return ZExt->getOperand(0);
310*9f7d4150SCraig Topper 
311*9f7d4150SCraig Topper     return nullptr;
312*9f7d4150SCraig Topper   };
313*9f7d4150SCraig Topper 
314*9f7d4150SCraig Topper   // Both operands of the subtract should be extends from vXi8.
315*9f7d4150SCraig Topper   Value *Op0 = getZeroExtendedVal(Sub->getOperand(0));
316*9f7d4150SCraig Topper   Value *Op1 = getZeroExtendedVal(Sub->getOperand(1));
317*9f7d4150SCraig Topper   if (!Op0 || !Op1)
318*9f7d4150SCraig Topper     return false;
319*9f7d4150SCraig Topper 
320*9f7d4150SCraig Topper   IRBuilder<> Builder(Add);
321*9f7d4150SCraig Topper 
322*9f7d4150SCraig Topper   Type *OpTy = Op->getType();
323*9f7d4150SCraig Topper   unsigned NumElts = OpTy->getVectorNumElements();
324*9f7d4150SCraig Topper 
325*9f7d4150SCraig Topper   unsigned IntrinsicNumElts;
326*9f7d4150SCraig Topper   Intrinsic::ID IID;
327*9f7d4150SCraig Topper   if (ST->hasBWI() && NumElts >= 64) {
328*9f7d4150SCraig Topper     IID = Intrinsic::x86_avx512_psad_bw_512;
329*9f7d4150SCraig Topper     IntrinsicNumElts = 64;
330*9f7d4150SCraig Topper   } else if (ST->hasAVX2() && NumElts >= 32) {
331*9f7d4150SCraig Topper     IID = Intrinsic::x86_avx2_psad_bw;
332*9f7d4150SCraig Topper     IntrinsicNumElts = 32;
333*9f7d4150SCraig Topper   } else {
334*9f7d4150SCraig Topper     IID = Intrinsic::x86_sse2_psad_bw;
335*9f7d4150SCraig Topper     IntrinsicNumElts = 16;
336*9f7d4150SCraig Topper   }
337*9f7d4150SCraig Topper 
338*9f7d4150SCraig Topper   Function *PSADBWFn = Intrinsic::getDeclaration(Add->getModule(), IID);
339*9f7d4150SCraig Topper 
340*9f7d4150SCraig Topper   if (NumElts < 16) {
341*9f7d4150SCraig Topper     // Pad input with zeroes.
342*9f7d4150SCraig Topper     SmallVector<uint32_t, 32> ConcatMask(16);
343*9f7d4150SCraig Topper     for (unsigned i = 0; i != NumElts; ++i)
344*9f7d4150SCraig Topper       ConcatMask[i] = i;
345*9f7d4150SCraig Topper     for (unsigned i = NumElts; i != 16; ++i)
346*9f7d4150SCraig Topper       ConcatMask[i] = (i % NumElts) + NumElts;
347*9f7d4150SCraig Topper 
348*9f7d4150SCraig Topper     Value *Zero = Constant::getNullValue(Op0->getType());
349*9f7d4150SCraig Topper     Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask);
350*9f7d4150SCraig Topper     Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask);
351*9f7d4150SCraig Topper     NumElts = 16;
352*9f7d4150SCraig Topper   }
353*9f7d4150SCraig Topper 
354*9f7d4150SCraig Topper   // Intrinsics produce vXi64 and need to be casted to vXi32.
355*9f7d4150SCraig Topper   Type *I32Ty = VectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4);
356*9f7d4150SCraig Topper 
357*9f7d4150SCraig Topper   assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!");
358*9f7d4150SCraig Topper   unsigned NumSplits = NumElts / IntrinsicNumElts;
359*9f7d4150SCraig Topper 
360*9f7d4150SCraig Topper   // First collect the pieces we need.
361*9f7d4150SCraig Topper   SmallVector<Value *, 4> Ops(NumSplits);
362*9f7d4150SCraig Topper   for (unsigned i = 0; i != NumSplits; ++i) {
363*9f7d4150SCraig Topper     SmallVector<uint32_t, 64> ExtractMask(IntrinsicNumElts);
364*9f7d4150SCraig Topper     std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
365*9f7d4150SCraig Topper     Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask);
366*9f7d4150SCraig Topper     Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask);
367*9f7d4150SCraig Topper     Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1});
368*9f7d4150SCraig Topper     Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty);
369*9f7d4150SCraig Topper   }
370*9f7d4150SCraig Topper 
371*9f7d4150SCraig Topper   assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits");
372*9f7d4150SCraig Topper   unsigned Stages = Log2_32(NumSplits);
373*9f7d4150SCraig Topper   for (unsigned s = Stages; s > 0; --s) {
374*9f7d4150SCraig Topper     unsigned NumConcatElts = Ops[0]->getType()->getVectorNumElements() * 2;
375*9f7d4150SCraig Topper     for (unsigned i = 0; i != 1 << (s - 1); ++i) {
376*9f7d4150SCraig Topper       SmallVector<uint32_t, 64> ConcatMask(NumConcatElts);
377*9f7d4150SCraig Topper       std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
378*9f7d4150SCraig Topper       Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask);
379*9f7d4150SCraig Topper     }
380*9f7d4150SCraig Topper   }
381*9f7d4150SCraig Topper 
382*9f7d4150SCraig Topper   // At this point the final value should be in Ops[0]. Now we need to adjust
383*9f7d4150SCraig Topper   // it to the final original type.
384*9f7d4150SCraig Topper   NumElts = OpTy->getVectorNumElements();
385*9f7d4150SCraig Topper   if (NumElts == 2) {
386*9f7d4150SCraig Topper     // Extract down to 2 elements.
387*9f7d4150SCraig Topper     Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], {0, 1});
388*9f7d4150SCraig Topper   } else if (NumElts >= 8) {
389*9f7d4150SCraig Topper     SmallVector<uint32_t, 32> ConcatMask(NumElts);
390*9f7d4150SCraig Topper     unsigned SubElts = Ops[0]->getType()->getVectorNumElements();
391*9f7d4150SCraig Topper     for (unsigned i = 0; i != SubElts; ++i)
392*9f7d4150SCraig Topper       ConcatMask[i] = i;
393*9f7d4150SCraig Topper     for (unsigned i = SubElts; i != NumElts; ++i)
394*9f7d4150SCraig Topper       ConcatMask[i] = (i % SubElts) + SubElts;
395*9f7d4150SCraig Topper 
396*9f7d4150SCraig Topper     Value *Zero = Constant::getNullValue(Ops[0]->getType());
397*9f7d4150SCraig Topper     Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask);
398*9f7d4150SCraig Topper   }
399*9f7d4150SCraig Topper 
400*9f7d4150SCraig Topper   // Replaces the uses of Op in Add with the new sequence.
401*9f7d4150SCraig Topper   Add->replaceUsesOfWith(Op, Ops[0]);
402*9f7d4150SCraig Topper   Add->setHasNoSignedWrap(false);
403*9f7d4150SCraig Topper   Add->setHasNoUnsignedWrap(false);
404*9f7d4150SCraig Topper 
405*9f7d4150SCraig Topper   return false;
406*9f7d4150SCraig Topper }
407*9f7d4150SCraig Topper 
408*9f7d4150SCraig Topper bool X86PartialReduction::trySADPattern(BinaryOperator *BO) {
409*9f7d4150SCraig Topper   if (!ST->hasSSE2())
410*9f7d4150SCraig Topper     return false;
411*9f7d4150SCraig Topper 
412*9f7d4150SCraig Topper   // TODO: There's nothing special about i32, any integer type above i16 should
413*9f7d4150SCraig Topper   // work just as well.
414*9f7d4150SCraig Topper   if (!BO->getType()->getVectorElementType()->isIntegerTy(32))
415*9f7d4150SCraig Topper     return false;
416*9f7d4150SCraig Topper 
417*9f7d4150SCraig Topper   bool Changed = false;
418*9f7d4150SCraig Topper   Changed |= trySADReplacement(BO->getOperand(0), BO);
419*9f7d4150SCraig Topper   Changed |= trySADReplacement(BO->getOperand(1), BO);
420*9f7d4150SCraig Topper   return Changed;
421*9f7d4150SCraig Topper }
422*9f7d4150SCraig Topper 
423*9f7d4150SCraig Topper bool X86PartialReduction::runOnFunction(Function &F) {
424*9f7d4150SCraig Topper   if (skipFunction(F))
425*9f7d4150SCraig Topper     return false;
426*9f7d4150SCraig Topper 
427*9f7d4150SCraig Topper   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
428*9f7d4150SCraig Topper   if (!TPC)
429*9f7d4150SCraig Topper     return false;
430*9f7d4150SCraig Topper 
431*9f7d4150SCraig Topper   auto &TM = TPC->getTM<X86TargetMachine>();
432*9f7d4150SCraig Topper   ST = TM.getSubtargetImpl(F);
433*9f7d4150SCraig Topper 
434*9f7d4150SCraig Topper   DL = &F.getParent()->getDataLayout();
435*9f7d4150SCraig Topper 
436*9f7d4150SCraig Topper   bool MadeChange = false;
437*9f7d4150SCraig Topper   for (auto &BB : F) {
438*9f7d4150SCraig Topper     for (auto &I : BB) {
439*9f7d4150SCraig Topper       auto *BO = dyn_cast<BinaryOperator>(&I);
440*9f7d4150SCraig Topper       if (!BO)
441*9f7d4150SCraig Topper         continue;
442*9f7d4150SCraig Topper 
443*9f7d4150SCraig Topper       if (!isVectorReductionOp(*BO))
444*9f7d4150SCraig Topper         continue;
445*9f7d4150SCraig Topper 
446*9f7d4150SCraig Topper       if (BO->getOpcode() == Instruction::Add) {
447*9f7d4150SCraig Topper         if (tryMAddPattern(BO)) {
448*9f7d4150SCraig Topper           MadeChange = true;
449*9f7d4150SCraig Topper           continue;
450*9f7d4150SCraig Topper         }
451*9f7d4150SCraig Topper         if (trySADPattern(BO)) {
452*9f7d4150SCraig Topper           MadeChange = true;
453*9f7d4150SCraig Topper           continue;
454*9f7d4150SCraig Topper         }
455*9f7d4150SCraig Topper       }
456*9f7d4150SCraig Topper     }
457*9f7d4150SCraig Topper   }
458*9f7d4150SCraig Topper 
459*9f7d4150SCraig Topper   return MadeChange;
460*9f7d4150SCraig Topper }
461