19f7d4150SCraig Topper //===-- X86PartialReduction.cpp -------------------------------------------===//
29f7d4150SCraig Topper //
39f7d4150SCraig Topper // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49f7d4150SCraig Topper // See https://llvm.org/LICENSE.txt for license information.
59f7d4150SCraig Topper // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69f7d4150SCraig Topper //
79f7d4150SCraig Topper //===----------------------------------------------------------------------===//
89f7d4150SCraig Topper //
99f7d4150SCraig Topper // This pass looks for add instructions used by a horizontal reduction to see
109f7d4150SCraig Topper // if we might be able to use pmaddwd or psadbw. Some cases of this require
119f7d4150SCraig Topper // cross basic block knowledge and can't be done in SelectionDAG.
129f7d4150SCraig Topper //
139f7d4150SCraig Topper //===----------------------------------------------------------------------===//
149f7d4150SCraig Topper 
159f7d4150SCraig Topper #include "X86.h"
169f7d4150SCraig Topper #include "llvm/Analysis/ValueTracking.h"
179f7d4150SCraig Topper #include "llvm/CodeGen/TargetPassConfig.h"
189f7d4150SCraig Topper #include "llvm/IR/Constants.h"
199f7d4150SCraig Topper #include "llvm/IR/Instructions.h"
209f7d4150SCraig Topper #include "llvm/IR/IntrinsicsX86.h"
219f7d4150SCraig Topper #include "llvm/IR/IRBuilder.h"
229f7d4150SCraig Topper #include "llvm/IR/Operator.h"
239f7d4150SCraig Topper #include "llvm/Pass.h"
249f7d4150SCraig Topper #include "X86TargetMachine.h"
259f7d4150SCraig Topper 
269f7d4150SCraig Topper using namespace llvm;
279f7d4150SCraig Topper 
289f7d4150SCraig Topper #define DEBUG_TYPE "x86-partial-reduction"
299f7d4150SCraig Topper 
309f7d4150SCraig Topper namespace {
319f7d4150SCraig Topper 
329f7d4150SCraig Topper class X86PartialReduction : public FunctionPass {
339f7d4150SCraig Topper   const DataLayout *DL;
349f7d4150SCraig Topper   const X86Subtarget *ST;
359f7d4150SCraig Topper 
369f7d4150SCraig Topper public:
379f7d4150SCraig Topper   static char ID; // Pass identification, replacement for typeid.
389f7d4150SCraig Topper 
399f7d4150SCraig Topper   X86PartialReduction() : FunctionPass(ID) { }
409f7d4150SCraig Topper 
419f7d4150SCraig Topper   bool runOnFunction(Function &Fn) override;
429f7d4150SCraig Topper 
439f7d4150SCraig Topper   void getAnalysisUsage(AnalysisUsage &AU) const override {
449f7d4150SCraig Topper     AU.setPreservesCFG();
459f7d4150SCraig Topper   }
469f7d4150SCraig Topper 
479f7d4150SCraig Topper   StringRef getPassName() const override {
489f7d4150SCraig Topper     return "X86 Partial Reduction";
499f7d4150SCraig Topper   }
509f7d4150SCraig Topper 
519f7d4150SCraig Topper private:
529f7d4150SCraig Topper   bool tryMAddPattern(BinaryOperator *BO);
539f7d4150SCraig Topper   bool tryMAddReplacement(Value *Op, BinaryOperator *Add);
549f7d4150SCraig Topper 
559f7d4150SCraig Topper   bool trySADPattern(BinaryOperator *BO);
569f7d4150SCraig Topper   bool trySADReplacement(Value *Op, BinaryOperator *Add);
579f7d4150SCraig Topper };
589f7d4150SCraig Topper }
599f7d4150SCraig Topper 
609f7d4150SCraig Topper FunctionPass *llvm::createX86PartialReductionPass() {
619f7d4150SCraig Topper   return new X86PartialReduction();
629f7d4150SCraig Topper }
639f7d4150SCraig Topper 
649f7d4150SCraig Topper char X86PartialReduction::ID = 0;
659f7d4150SCraig Topper 
669f7d4150SCraig Topper INITIALIZE_PASS(X86PartialReduction, DEBUG_TYPE,
679f7d4150SCraig Topper                 "X86 Partial Reduction", false, false)
689f7d4150SCraig Topper 
699f7d4150SCraig Topper static bool isVectorReductionOp(const BinaryOperator &BO) {
709f7d4150SCraig Topper   if (!BO.getType()->isVectorTy())
719f7d4150SCraig Topper     return false;
729f7d4150SCraig Topper 
739f7d4150SCraig Topper   unsigned Opcode = BO.getOpcode();
749f7d4150SCraig Topper 
759f7d4150SCraig Topper   switch (Opcode) {
769f7d4150SCraig Topper   case Instruction::Add:
779f7d4150SCraig Topper   case Instruction::Mul:
789f7d4150SCraig Topper   case Instruction::And:
799f7d4150SCraig Topper   case Instruction::Or:
809f7d4150SCraig Topper   case Instruction::Xor:
819f7d4150SCraig Topper     break;
829f7d4150SCraig Topper   case Instruction::FAdd:
839f7d4150SCraig Topper   case Instruction::FMul:
849f7d4150SCraig Topper     if (auto *FPOp = dyn_cast<FPMathOperator>(&BO))
859f7d4150SCraig Topper       if (FPOp->getFastMathFlags().isFast())
869f7d4150SCraig Topper         break;
879f7d4150SCraig Topper     LLVM_FALLTHROUGH;
889f7d4150SCraig Topper   default:
899f7d4150SCraig Topper     return false;
909f7d4150SCraig Topper   }
919f7d4150SCraig Topper 
929f7d4150SCraig Topper   unsigned ElemNum = BO.getType()->getVectorNumElements();
939f7d4150SCraig Topper   // Ensure the reduction size is a power of 2.
949f7d4150SCraig Topper   if (!isPowerOf2_32(ElemNum))
959f7d4150SCraig Topper     return false;
969f7d4150SCraig Topper 
979f7d4150SCraig Topper   unsigned ElemNumToReduce = ElemNum;
989f7d4150SCraig Topper 
999f7d4150SCraig Topper   // Do DFS search on the def-use chain from the given instruction. We only
1009f7d4150SCraig Topper   // allow four kinds of operations during the search until we reach the
1019f7d4150SCraig Topper   // instruction that extracts the first element from the vector:
1029f7d4150SCraig Topper   //
1039f7d4150SCraig Topper   //   1. The reduction operation of the same opcode as the given instruction.
1049f7d4150SCraig Topper   //
1059f7d4150SCraig Topper   //   2. PHI node.
1069f7d4150SCraig Topper   //
1079f7d4150SCraig Topper   //   3. ShuffleVector instruction together with a reduction operation that
1089f7d4150SCraig Topper   //      does a partial reduction.
1099f7d4150SCraig Topper   //
1109f7d4150SCraig Topper   //   4. ExtractElement that extracts the first element from the vector, and we
1119f7d4150SCraig Topper   //      stop searching the def-use chain here.
1129f7d4150SCraig Topper   //
1139f7d4150SCraig Topper   // 3 & 4 above perform a reduction on all elements of the vector. We push defs
1149f7d4150SCraig Topper   // from 1-3 to the stack to continue the DFS. The given instruction is not
1159f7d4150SCraig Topper   // a reduction operation if we meet any other instructions other than those
1169f7d4150SCraig Topper   // listed above.
1179f7d4150SCraig Topper 
1189f7d4150SCraig Topper   SmallVector<const User *, 16> UsersToVisit{&BO};
1199f7d4150SCraig Topper   SmallPtrSet<const User *, 16> Visited;
1209f7d4150SCraig Topper   bool ReduxExtracted = false;
1219f7d4150SCraig Topper 
1229f7d4150SCraig Topper   while (!UsersToVisit.empty()) {
1239f7d4150SCraig Topper     auto User = UsersToVisit.back();
1249f7d4150SCraig Topper     UsersToVisit.pop_back();
1259f7d4150SCraig Topper     if (!Visited.insert(User).second)
1269f7d4150SCraig Topper       continue;
1279f7d4150SCraig Topper 
1289f7d4150SCraig Topper     for (const auto *U : User->users()) {
1299f7d4150SCraig Topper       auto *Inst = dyn_cast<Instruction>(U);
1309f7d4150SCraig Topper       if (!Inst)
1319f7d4150SCraig Topper         return false;
1329f7d4150SCraig Topper 
1339f7d4150SCraig Topper       if (Inst->getOpcode() == Opcode || isa<PHINode>(U)) {
1349f7d4150SCraig Topper         if (auto *FPOp = dyn_cast<FPMathOperator>(Inst))
1359f7d4150SCraig Topper           if (!isa<PHINode>(FPOp) && !FPOp->getFastMathFlags().isFast())
1369f7d4150SCraig Topper             return false;
1379f7d4150SCraig Topper         UsersToVisit.push_back(U);
1389f7d4150SCraig Topper       } else if (auto *ShufInst = dyn_cast<ShuffleVectorInst>(U)) {
1399f7d4150SCraig Topper         // Detect the following pattern: A ShuffleVector instruction together
1409f7d4150SCraig Topper         // with a reduction that do partial reduction on the first and second
1419f7d4150SCraig Topper         // ElemNumToReduce / 2 elements, and store the result in
1429f7d4150SCraig Topper         // ElemNumToReduce / 2 elements in another vector.
1439f7d4150SCraig Topper 
1449f7d4150SCraig Topper         unsigned ResultElements = ShufInst->getType()->getVectorNumElements();
1459f7d4150SCraig Topper         if (ResultElements < ElemNum)
1469f7d4150SCraig Topper           return false;
1479f7d4150SCraig Topper 
1489f7d4150SCraig Topper         if (ElemNumToReduce == 1)
1499f7d4150SCraig Topper           return false;
1509f7d4150SCraig Topper         if (!isa<UndefValue>(U->getOperand(1)))
1519f7d4150SCraig Topper           return false;
1529f7d4150SCraig Topper         for (unsigned i = 0; i < ElemNumToReduce / 2; ++i)
1539f7d4150SCraig Topper           if (ShufInst->getMaskValue(i) != int(i + ElemNumToReduce / 2))
1549f7d4150SCraig Topper             return false;
1559f7d4150SCraig Topper         for (unsigned i = ElemNumToReduce / 2; i < ElemNum; ++i)
1569f7d4150SCraig Topper           if (ShufInst->getMaskValue(i) != -1)
1579f7d4150SCraig Topper             return false;
1589f7d4150SCraig Topper 
1599f7d4150SCraig Topper         // There is only one user of this ShuffleVector instruction, which
1609f7d4150SCraig Topper         // must be a reduction operation.
1619f7d4150SCraig Topper         if (!U->hasOneUse())
1629f7d4150SCraig Topper           return false;
1639f7d4150SCraig Topper 
1649f7d4150SCraig Topper         auto *U2 = dyn_cast<BinaryOperator>(*U->user_begin());
1659f7d4150SCraig Topper         if (!U2 || U2->getOpcode() != Opcode)
1669f7d4150SCraig Topper           return false;
1679f7d4150SCraig Topper 
1689f7d4150SCraig Topper         // Check operands of the reduction operation.
1699f7d4150SCraig Topper         if ((U2->getOperand(0) == U->getOperand(0) && U2->getOperand(1) == U) ||
1709f7d4150SCraig Topper             (U2->getOperand(1) == U->getOperand(0) && U2->getOperand(0) == U)) {
1719f7d4150SCraig Topper           UsersToVisit.push_back(U2);
1729f7d4150SCraig Topper           ElemNumToReduce /= 2;
1739f7d4150SCraig Topper         } else
1749f7d4150SCraig Topper           return false;
1759f7d4150SCraig Topper       } else if (isa<ExtractElementInst>(U)) {
1769f7d4150SCraig Topper         // At this moment we should have reduced all elements in the vector.
1779f7d4150SCraig Topper         if (ElemNumToReduce != 1)
1789f7d4150SCraig Topper           return false;
1799f7d4150SCraig Topper 
1809f7d4150SCraig Topper         auto *Val = dyn_cast<ConstantInt>(U->getOperand(1));
1819f7d4150SCraig Topper         if (!Val || !Val->isZero())
1829f7d4150SCraig Topper           return false;
1839f7d4150SCraig Topper 
1849f7d4150SCraig Topper         ReduxExtracted = true;
1859f7d4150SCraig Topper       } else
1869f7d4150SCraig Topper         return false;
1879f7d4150SCraig Topper     }
1889f7d4150SCraig Topper   }
1899f7d4150SCraig Topper   return ReduxExtracted;
1909f7d4150SCraig Topper }
1919f7d4150SCraig Topper 
1929f7d4150SCraig Topper bool X86PartialReduction::tryMAddReplacement(Value *Op, BinaryOperator *Add) {
1939f7d4150SCraig Topper   BasicBlock *BB = Add->getParent();
1949f7d4150SCraig Topper 
1959f7d4150SCraig Topper   auto *BO = dyn_cast<BinaryOperator>(Op);
1969f7d4150SCraig Topper   if (!BO || BO->getOpcode() != Instruction::Mul || !BO->hasOneUse() ||
1979f7d4150SCraig Topper       BO->getParent() != BB)
1989f7d4150SCraig Topper     return false;
1999f7d4150SCraig Topper 
2009f7d4150SCraig Topper   Value *LHS = BO->getOperand(0);
2019f7d4150SCraig Topper   Value *RHS = BO->getOperand(1);
2029f7d4150SCraig Topper 
2039f7d4150SCraig Topper   // LHS and RHS should be only used once or if they are the same then only
2049f7d4150SCraig Topper   // used twice. Only check this when SSE4.1 is enabled and we have zext/sext
2059f7d4150SCraig Topper   // instructions, otherwise we use punpck to emulate zero extend in stages. The
2069f7d4150SCraig Topper   // trunc/ we need to do likely won't introduce new instructions in that case.
2079f7d4150SCraig Topper   if (ST->hasSSE41()) {
2089f7d4150SCraig Topper     if (LHS == RHS) {
2099f7d4150SCraig Topper       if (!isa<Constant>(LHS) && !LHS->hasNUses(2))
2109f7d4150SCraig Topper         return false;
2119f7d4150SCraig Topper     } else {
2129f7d4150SCraig Topper       if (!isa<Constant>(LHS) && !LHS->hasOneUse())
2139f7d4150SCraig Topper         return false;
2149f7d4150SCraig Topper       if (!isa<Constant>(RHS) && !RHS->hasOneUse())
2159f7d4150SCraig Topper         return false;
2169f7d4150SCraig Topper     }
2179f7d4150SCraig Topper   }
2189f7d4150SCraig Topper 
2199f7d4150SCraig Topper   auto canShrinkOp = [&](Value *Op) {
2209f7d4150SCraig Topper     if (isa<Constant>(Op) && ComputeNumSignBits(Op, *DL, 0, nullptr, BO) > 16)
2219f7d4150SCraig Topper       return true;
2229f7d4150SCraig Topper     if (auto *Cast = dyn_cast<CastInst>(Op)) {
2239f7d4150SCraig Topper       if (Cast->getParent() == BB &&
2249f7d4150SCraig Topper           (Cast->getOpcode() == Instruction::SExt ||
2259f7d4150SCraig Topper            Cast->getOpcode() == Instruction::ZExt) &&
2269f7d4150SCraig Topper           ComputeNumSignBits(Op, *DL, 0, nullptr, BO) > 16)
2279f7d4150SCraig Topper         return true;
2289f7d4150SCraig Topper     }
2299f7d4150SCraig Topper 
2309f7d4150SCraig Topper     return false;
2319f7d4150SCraig Topper   };
2329f7d4150SCraig Topper 
2339f7d4150SCraig Topper   // Both Ops need to be shrinkable.
2349f7d4150SCraig Topper   if (!canShrinkOp(LHS) && !canShrinkOp(RHS))
2359f7d4150SCraig Topper     return false;
2369f7d4150SCraig Topper 
2379f7d4150SCraig Topper   IRBuilder<> Builder(Add);
2389f7d4150SCraig Topper 
2399f7d4150SCraig Topper   Type *MulTy = Op->getType();
2409f7d4150SCraig Topper   unsigned NumElts = MulTy->getVectorNumElements();
2419f7d4150SCraig Topper 
2429f7d4150SCraig Topper   // Extract even elements and odd elements and add them together. This will
2439f7d4150SCraig Topper   // be pattern matched by SelectionDAG to pmaddwd. This instruction will be
2449f7d4150SCraig Topper   // half the original width.
2459f7d4150SCraig Topper   SmallVector<uint32_t, 16> EvenMask(NumElts / 2);
2469f7d4150SCraig Topper   SmallVector<uint32_t, 16> OddMask(NumElts / 2);
2479f7d4150SCraig Topper   for (int i = 0, e = NumElts / 2; i != e; ++i) {
2489f7d4150SCraig Topper     EvenMask[i] = i * 2;
2499f7d4150SCraig Topper     OddMask[i] = i * 2 + 1;
2509f7d4150SCraig Topper   }
2519f7d4150SCraig Topper   Value *EvenElts = Builder.CreateShuffleVector(BO, BO, EvenMask);
2529f7d4150SCraig Topper   Value *OddElts = Builder.CreateShuffleVector(BO, BO, OddMask);
2539f7d4150SCraig Topper   Value *MAdd = Builder.CreateAdd(EvenElts, OddElts);
2549f7d4150SCraig Topper 
2559f7d4150SCraig Topper   // Concatenate zeroes to extend back to the original type.
2569f7d4150SCraig Topper   SmallVector<uint32_t, 32> ConcatMask(NumElts);
2579f7d4150SCraig Topper   std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
2589f7d4150SCraig Topper   Value *Zero = Constant::getNullValue(MAdd->getType());
2599f7d4150SCraig Topper   Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask);
2609f7d4150SCraig Topper 
2619f7d4150SCraig Topper   // Replaces the use of mul in the original Add with the pmaddwd and zeroes.
2629f7d4150SCraig Topper   Add->replaceUsesOfWith(BO, Concat);
2639f7d4150SCraig Topper   Add->setHasNoSignedWrap(false);
2649f7d4150SCraig Topper   Add->setHasNoUnsignedWrap(false);
2659f7d4150SCraig Topper 
2669f7d4150SCraig Topper   return true;
2679f7d4150SCraig Topper }
2689f7d4150SCraig Topper 
2699f7d4150SCraig Topper // Try to replace operans of this add with pmaddwd patterns.
2709f7d4150SCraig Topper bool X86PartialReduction::tryMAddPattern(BinaryOperator *BO) {
2719f7d4150SCraig Topper   if (!ST->hasSSE2())
2729f7d4150SCraig Topper     return false;
2739f7d4150SCraig Topper 
2749f7d4150SCraig Topper   // Need at least 8 elements.
2759f7d4150SCraig Topper   if (BO->getType()->getVectorNumElements() < 8)
2769f7d4150SCraig Topper     return false;
2779f7d4150SCraig Topper 
2789f7d4150SCraig Topper   // Element type should be i32.
2799f7d4150SCraig Topper   if (!BO->getType()->getVectorElementType()->isIntegerTy(32))
2809f7d4150SCraig Topper     return false;
2819f7d4150SCraig Topper 
2829f7d4150SCraig Topper   bool Changed = false;
2839f7d4150SCraig Topper   Changed |= tryMAddReplacement(BO->getOperand(0), BO);
2849f7d4150SCraig Topper   Changed |= tryMAddReplacement(BO->getOperand(1), BO);
2859f7d4150SCraig Topper   return Changed;
2869f7d4150SCraig Topper }
2879f7d4150SCraig Topper 
2889f7d4150SCraig Topper bool X86PartialReduction::trySADReplacement(Value *Op, BinaryOperator *Add) {
2899f7d4150SCraig Topper   // Operand should be a select.
2909f7d4150SCraig Topper   auto *SI = dyn_cast<SelectInst>(Op);
2919f7d4150SCraig Topper   if (!SI)
2929f7d4150SCraig Topper     return false;
2939f7d4150SCraig Topper 
2949f7d4150SCraig Topper   // Select needs to implement absolute value.
2959f7d4150SCraig Topper   Value *LHS, *RHS;
2969f7d4150SCraig Topper   auto SPR = matchSelectPattern(SI, LHS, RHS);
2979f7d4150SCraig Topper   if (SPR.Flavor != SPF_ABS)
2989f7d4150SCraig Topper     return false;
2999f7d4150SCraig Topper 
3009f7d4150SCraig Topper   // Need a subtract of two values.
3019f7d4150SCraig Topper   auto *Sub = dyn_cast<BinaryOperator>(LHS);
3029f7d4150SCraig Topper   if (!Sub || Sub->getOpcode() != Instruction::Sub)
3039f7d4150SCraig Topper     return false;
3049f7d4150SCraig Topper 
3059f7d4150SCraig Topper   // Look for zero extend from i8.
3069f7d4150SCraig Topper   auto getZeroExtendedVal = [](Value *Op) -> Value * {
3079f7d4150SCraig Topper     if (auto *ZExt = dyn_cast<ZExtInst>(Op))
3089f7d4150SCraig Topper       if (ZExt->getOperand(0)->getType()->getVectorElementType()->isIntegerTy(8))
3099f7d4150SCraig Topper         return ZExt->getOperand(0);
3109f7d4150SCraig Topper 
3119f7d4150SCraig Topper     return nullptr;
3129f7d4150SCraig Topper   };
3139f7d4150SCraig Topper 
3149f7d4150SCraig Topper   // Both operands of the subtract should be extends from vXi8.
3159f7d4150SCraig Topper   Value *Op0 = getZeroExtendedVal(Sub->getOperand(0));
3169f7d4150SCraig Topper   Value *Op1 = getZeroExtendedVal(Sub->getOperand(1));
3179f7d4150SCraig Topper   if (!Op0 || !Op1)
3189f7d4150SCraig Topper     return false;
3199f7d4150SCraig Topper 
3209f7d4150SCraig Topper   IRBuilder<> Builder(Add);
3219f7d4150SCraig Topper 
3229f7d4150SCraig Topper   Type *OpTy = Op->getType();
3239f7d4150SCraig Topper   unsigned NumElts = OpTy->getVectorNumElements();
3249f7d4150SCraig Topper 
3259f7d4150SCraig Topper   unsigned IntrinsicNumElts;
3269f7d4150SCraig Topper   Intrinsic::ID IID;
3279f7d4150SCraig Topper   if (ST->hasBWI() && NumElts >= 64) {
3289f7d4150SCraig Topper     IID = Intrinsic::x86_avx512_psad_bw_512;
3299f7d4150SCraig Topper     IntrinsicNumElts = 64;
3309f7d4150SCraig Topper   } else if (ST->hasAVX2() && NumElts >= 32) {
3319f7d4150SCraig Topper     IID = Intrinsic::x86_avx2_psad_bw;
3329f7d4150SCraig Topper     IntrinsicNumElts = 32;
3339f7d4150SCraig Topper   } else {
3349f7d4150SCraig Topper     IID = Intrinsic::x86_sse2_psad_bw;
3359f7d4150SCraig Topper     IntrinsicNumElts = 16;
3369f7d4150SCraig Topper   }
3379f7d4150SCraig Topper 
3389f7d4150SCraig Topper   Function *PSADBWFn = Intrinsic::getDeclaration(Add->getModule(), IID);
3399f7d4150SCraig Topper 
3409f7d4150SCraig Topper   if (NumElts < 16) {
3419f7d4150SCraig Topper     // Pad input with zeroes.
3429f7d4150SCraig Topper     SmallVector<uint32_t, 32> ConcatMask(16);
3439f7d4150SCraig Topper     for (unsigned i = 0; i != NumElts; ++i)
3449f7d4150SCraig Topper       ConcatMask[i] = i;
3459f7d4150SCraig Topper     for (unsigned i = NumElts; i != 16; ++i)
3469f7d4150SCraig Topper       ConcatMask[i] = (i % NumElts) + NumElts;
3479f7d4150SCraig Topper 
3489f7d4150SCraig Topper     Value *Zero = Constant::getNullValue(Op0->getType());
3499f7d4150SCraig Topper     Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask);
3509f7d4150SCraig Topper     Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask);
3519f7d4150SCraig Topper     NumElts = 16;
3529f7d4150SCraig Topper   }
3539f7d4150SCraig Topper 
3549f7d4150SCraig Topper   // Intrinsics produce vXi64 and need to be casted to vXi32.
3559f7d4150SCraig Topper   Type *I32Ty = VectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4);
3569f7d4150SCraig Topper 
3579f7d4150SCraig Topper   assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!");
3589f7d4150SCraig Topper   unsigned NumSplits = NumElts / IntrinsicNumElts;
3599f7d4150SCraig Topper 
3609f7d4150SCraig Topper   // First collect the pieces we need.
3619f7d4150SCraig Topper   SmallVector<Value *, 4> Ops(NumSplits);
3629f7d4150SCraig Topper   for (unsigned i = 0; i != NumSplits; ++i) {
3639f7d4150SCraig Topper     SmallVector<uint32_t, 64> ExtractMask(IntrinsicNumElts);
3649f7d4150SCraig Topper     std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
3659f7d4150SCraig Topper     Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask);
3669f7d4150SCraig Topper     Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask);
3679f7d4150SCraig Topper     Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1});
3689f7d4150SCraig Topper     Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty);
3699f7d4150SCraig Topper   }
3709f7d4150SCraig Topper 
3719f7d4150SCraig Topper   assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits");
3729f7d4150SCraig Topper   unsigned Stages = Log2_32(NumSplits);
3739f7d4150SCraig Topper   for (unsigned s = Stages; s > 0; --s) {
3749f7d4150SCraig Topper     unsigned NumConcatElts = Ops[0]->getType()->getVectorNumElements() * 2;
375d2dd0facSMichael Liao     for (unsigned i = 0; i != 1U << (s - 1); ++i) {
3769f7d4150SCraig Topper       SmallVector<uint32_t, 64> ConcatMask(NumConcatElts);
3779f7d4150SCraig Topper       std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
3789f7d4150SCraig Topper       Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask);
3799f7d4150SCraig Topper     }
3809f7d4150SCraig Topper   }
3819f7d4150SCraig Topper 
3829f7d4150SCraig Topper   // At this point the final value should be in Ops[0]. Now we need to adjust
3839f7d4150SCraig Topper   // it to the final original type.
3849f7d4150SCraig Topper   NumElts = OpTy->getVectorNumElements();
3859f7d4150SCraig Topper   if (NumElts == 2) {
3869f7d4150SCraig Topper     // Extract down to 2 elements.
387*1ee6ec2bSEli Friedman     Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], ArrayRef<int>{0, 1});
3889f7d4150SCraig Topper   } else if (NumElts >= 8) {
3899f7d4150SCraig Topper     SmallVector<uint32_t, 32> ConcatMask(NumElts);
3909f7d4150SCraig Topper     unsigned SubElts = Ops[0]->getType()->getVectorNumElements();
3919f7d4150SCraig Topper     for (unsigned i = 0; i != SubElts; ++i)
3929f7d4150SCraig Topper       ConcatMask[i] = i;
3939f7d4150SCraig Topper     for (unsigned i = SubElts; i != NumElts; ++i)
3949f7d4150SCraig Topper       ConcatMask[i] = (i % SubElts) + SubElts;
3959f7d4150SCraig Topper 
3969f7d4150SCraig Topper     Value *Zero = Constant::getNullValue(Ops[0]->getType());
3979f7d4150SCraig Topper     Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask);
3989f7d4150SCraig Topper   }
3999f7d4150SCraig Topper 
4009f7d4150SCraig Topper   // Replaces the uses of Op in Add with the new sequence.
4019f7d4150SCraig Topper   Add->replaceUsesOfWith(Op, Ops[0]);
4029f7d4150SCraig Topper   Add->setHasNoSignedWrap(false);
4039f7d4150SCraig Topper   Add->setHasNoUnsignedWrap(false);
4049f7d4150SCraig Topper 
4059f7d4150SCraig Topper   return false;
4069f7d4150SCraig Topper }
4079f7d4150SCraig Topper 
4089f7d4150SCraig Topper bool X86PartialReduction::trySADPattern(BinaryOperator *BO) {
4099f7d4150SCraig Topper   if (!ST->hasSSE2())
4109f7d4150SCraig Topper     return false;
4119f7d4150SCraig Topper 
4129f7d4150SCraig Topper   // TODO: There's nothing special about i32, any integer type above i16 should
4139f7d4150SCraig Topper   // work just as well.
4149f7d4150SCraig Topper   if (!BO->getType()->getVectorElementType()->isIntegerTy(32))
4159f7d4150SCraig Topper     return false;
4169f7d4150SCraig Topper 
4179f7d4150SCraig Topper   bool Changed = false;
4189f7d4150SCraig Topper   Changed |= trySADReplacement(BO->getOperand(0), BO);
4199f7d4150SCraig Topper   Changed |= trySADReplacement(BO->getOperand(1), BO);
4209f7d4150SCraig Topper   return Changed;
4219f7d4150SCraig Topper }
4229f7d4150SCraig Topper 
4239f7d4150SCraig Topper bool X86PartialReduction::runOnFunction(Function &F) {
4249f7d4150SCraig Topper   if (skipFunction(F))
4259f7d4150SCraig Topper     return false;
4269f7d4150SCraig Topper 
4279f7d4150SCraig Topper   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
4289f7d4150SCraig Topper   if (!TPC)
4299f7d4150SCraig Topper     return false;
4309f7d4150SCraig Topper 
4319f7d4150SCraig Topper   auto &TM = TPC->getTM<X86TargetMachine>();
4329f7d4150SCraig Topper   ST = TM.getSubtargetImpl(F);
4339f7d4150SCraig Topper 
4349f7d4150SCraig Topper   DL = &F.getParent()->getDataLayout();
4359f7d4150SCraig Topper 
4369f7d4150SCraig Topper   bool MadeChange = false;
4379f7d4150SCraig Topper   for (auto &BB : F) {
4389f7d4150SCraig Topper     for (auto &I : BB) {
4399f7d4150SCraig Topper       auto *BO = dyn_cast<BinaryOperator>(&I);
4409f7d4150SCraig Topper       if (!BO)
4419f7d4150SCraig Topper         continue;
4429f7d4150SCraig Topper 
4439f7d4150SCraig Topper       if (!isVectorReductionOp(*BO))
4449f7d4150SCraig Topper         continue;
4459f7d4150SCraig Topper 
4469f7d4150SCraig Topper       if (BO->getOpcode() == Instruction::Add) {
4479f7d4150SCraig Topper         if (tryMAddPattern(BO)) {
4489f7d4150SCraig Topper           MadeChange = true;
4499f7d4150SCraig Topper           continue;
4509f7d4150SCraig Topper         }
4519f7d4150SCraig Topper         if (trySADPattern(BO)) {
4529f7d4150SCraig Topper           MadeChange = true;
4539f7d4150SCraig Topper           continue;
4549f7d4150SCraig Topper         }
4559f7d4150SCraig Topper       }
4569f7d4150SCraig Topper     }
4579f7d4150SCraig Topper   }
4589f7d4150SCraig Topper 
4599f7d4150SCraig Topper   return MadeChange;
4609f7d4150SCraig Topper }
461