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"
16*21babe4dSLuo, Yuanke #include "X86TargetMachine.h"
179f7d4150SCraig Topper #include "llvm/Analysis/ValueTracking.h"
189f7d4150SCraig Topper #include "llvm/CodeGen/TargetPassConfig.h"
199f7d4150SCraig Topper #include "llvm/IR/Constants.h"
20*21babe4dSLuo, Yuanke #include "llvm/IR/IRBuilder.h"
219f7d4150SCraig Topper #include "llvm/IR/Instructions.h"
229f7d4150SCraig Topper #include "llvm/IR/IntrinsicsX86.h"
239f7d4150SCraig Topper #include "llvm/IR/Operator.h"
249f7d4150SCraig Topper #include "llvm/Pass.h"
25*21babe4dSLuo, Yuanke #include "llvm/Support/KnownBits.h"
269f7d4150SCraig Topper 
279f7d4150SCraig Topper using namespace llvm;
289f7d4150SCraig Topper 
299f7d4150SCraig Topper #define DEBUG_TYPE "x86-partial-reduction"
309f7d4150SCraig Topper 
319f7d4150SCraig Topper namespace {
329f7d4150SCraig Topper 
339f7d4150SCraig Topper class X86PartialReduction : public FunctionPass {
349f7d4150SCraig Topper   const DataLayout *DL;
359f7d4150SCraig Topper   const X86Subtarget *ST;
369f7d4150SCraig Topper 
379f7d4150SCraig Topper public:
389f7d4150SCraig Topper   static char ID; // Pass identification, replacement for typeid.
399f7d4150SCraig Topper 
409f7d4150SCraig Topper   X86PartialReduction() : FunctionPass(ID) { }
419f7d4150SCraig Topper 
429f7d4150SCraig Topper   bool runOnFunction(Function &Fn) override;
439f7d4150SCraig Topper 
449f7d4150SCraig Topper   void getAnalysisUsage(AnalysisUsage &AU) const override {
459f7d4150SCraig Topper     AU.setPreservesCFG();
469f7d4150SCraig Topper   }
479f7d4150SCraig Topper 
489f7d4150SCraig Topper   StringRef getPassName() const override {
499f7d4150SCraig Topper     return "X86 Partial Reduction";
509f7d4150SCraig Topper   }
519f7d4150SCraig Topper 
529f7d4150SCraig Topper private:
53*21babe4dSLuo, Yuanke   bool tryMAddReplacement(Instruction *Op, bool ReduceInOneBB);
548abe8300SCraig Topper   bool trySADReplacement(Instruction *Op);
559f7d4150SCraig Topper };
569f7d4150SCraig Topper }
579f7d4150SCraig Topper 
589f7d4150SCraig Topper FunctionPass *llvm::createX86PartialReductionPass() {
599f7d4150SCraig Topper   return new X86PartialReduction();
609f7d4150SCraig Topper }
619f7d4150SCraig Topper 
629f7d4150SCraig Topper char X86PartialReduction::ID = 0;
639f7d4150SCraig Topper 
649f7d4150SCraig Topper INITIALIZE_PASS(X86PartialReduction, DEBUG_TYPE,
659f7d4150SCraig Topper                 "X86 Partial Reduction", false, false)
669f7d4150SCraig Topper 
67*21babe4dSLuo, Yuanke // This function should be aligned with detectExtMul() in X86ISelLowering.cpp.
68*21babe4dSLuo, Yuanke static bool matchVPDPBUSDPattern(const X86Subtarget *ST, BinaryOperator *Mul,
69*21babe4dSLuo, Yuanke                                  const DataLayout *DL) {
70*21babe4dSLuo, Yuanke   if (!ST->hasVNNI() && !ST->hasAVXVNNI())
71*21babe4dSLuo, Yuanke     return false;
72*21babe4dSLuo, Yuanke 
73*21babe4dSLuo, Yuanke   Value *LHS = Mul->getOperand(0);
74*21babe4dSLuo, Yuanke   Value *RHS = Mul->getOperand(1);
75*21babe4dSLuo, Yuanke 
76*21babe4dSLuo, Yuanke   if (isa<SExtInst>(LHS))
77*21babe4dSLuo, Yuanke     std::swap(LHS, RHS);
78*21babe4dSLuo, Yuanke 
79*21babe4dSLuo, Yuanke   if (!isa<ZExtInst>(LHS))
80*21babe4dSLuo, Yuanke     return false;
81*21babe4dSLuo, Yuanke 
82*21babe4dSLuo, Yuanke   auto IsFreeTruncation = [&](Value *Op) {
83*21babe4dSLuo, Yuanke     if (auto *Cast = dyn_cast<CastInst>(Op)) {
84*21babe4dSLuo, Yuanke       if (Cast->getParent() == Mul->getParent() &&
85*21babe4dSLuo, Yuanke           (Cast->getOpcode() == Instruction::SExt ||
86*21babe4dSLuo, Yuanke            Cast->getOpcode() == Instruction::ZExt) &&
87*21babe4dSLuo, Yuanke           Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 8)
88*21babe4dSLuo, Yuanke         return true;
89*21babe4dSLuo, Yuanke     }
90*21babe4dSLuo, Yuanke     // TODO: Support constant in ISel.
91*21babe4dSLuo, Yuanke     return false;
92*21babe4dSLuo, Yuanke   };
93*21babe4dSLuo, Yuanke 
94*21babe4dSLuo, Yuanke   // (dpbusd (zext a), (sext, b)). Since the first operand should be unsigned
95*21babe4dSLuo, Yuanke   // value, we need to check LHS is zero extended value. RHS should be signed
96*21babe4dSLuo, Yuanke   // value, so we just check the signed bits.
97*21babe4dSLuo, Yuanke   if ((IsFreeTruncation(LHS) &&
98*21babe4dSLuo, Yuanke        computeKnownBits(LHS, *DL).countMaxActiveBits() <= 8) &&
99*21babe4dSLuo, Yuanke       (IsFreeTruncation(RHS) && ComputeMaxSignificantBits(RHS, *DL) <= 8))
100*21babe4dSLuo, Yuanke     return true;
101*21babe4dSLuo, Yuanke 
102*21babe4dSLuo, Yuanke   return false;
103*21babe4dSLuo, Yuanke }
104*21babe4dSLuo, Yuanke 
105*21babe4dSLuo, Yuanke bool X86PartialReduction::tryMAddReplacement(Instruction *Op,
106*21babe4dSLuo, Yuanke                                              bool ReduceInOneBB) {
1078abe8300SCraig Topper   if (!ST->hasSSE2())
1089f7d4150SCraig Topper     return false;
1099f7d4150SCraig Topper 
1108abe8300SCraig Topper   // Need at least 8 elements.
1110da1e7ebSChristopher Tetreault   if (cast<FixedVectorType>(Op->getType())->getNumElements() < 8)
1129f7d4150SCraig Topper     return false;
1139f7d4150SCraig Topper 
1148abe8300SCraig Topper   // Element type should be i32.
1158abe8300SCraig Topper   if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32))
1169f7d4150SCraig Topper     return false;
1179f7d4150SCraig Topper 
1188abe8300SCraig Topper   auto *Mul = dyn_cast<BinaryOperator>(Op);
1198abe8300SCraig Topper   if (!Mul || Mul->getOpcode() != Instruction::Mul)
1209f7d4150SCraig Topper     return false;
1219f7d4150SCraig Topper 
1228abe8300SCraig Topper   Value *LHS = Mul->getOperand(0);
1238abe8300SCraig Topper   Value *RHS = Mul->getOperand(1);
1249f7d4150SCraig Topper 
125*21babe4dSLuo, Yuanke   // If the target support VNNI, leave it to ISel to combine reduce operation
126*21babe4dSLuo, Yuanke   // to VNNI instruction.
127*21babe4dSLuo, Yuanke   // TODO: we can support transforming reduce to VNNI intrinsic for across block
128*21babe4dSLuo, Yuanke   // in this pass.
129*21babe4dSLuo, Yuanke   if (ReduceInOneBB && matchVPDPBUSDPattern(ST, Mul, DL))
130*21babe4dSLuo, Yuanke     return false;
131*21babe4dSLuo, Yuanke 
1329f7d4150SCraig Topper   // LHS and RHS should be only used once or if they are the same then only
1339f7d4150SCraig Topper   // used twice. Only check this when SSE4.1 is enabled and we have zext/sext
1349f7d4150SCraig Topper   // instructions, otherwise we use punpck to emulate zero extend in stages. The
1359f7d4150SCraig Topper   // trunc/ we need to do likely won't introduce new instructions in that case.
1369f7d4150SCraig Topper   if (ST->hasSSE41()) {
1379f7d4150SCraig Topper     if (LHS == RHS) {
1389f7d4150SCraig Topper       if (!isa<Constant>(LHS) && !LHS->hasNUses(2))
1399f7d4150SCraig Topper         return false;
1409f7d4150SCraig Topper     } else {
1419f7d4150SCraig Topper       if (!isa<Constant>(LHS) && !LHS->hasOneUse())
1429f7d4150SCraig Topper         return false;
1439f7d4150SCraig Topper       if (!isa<Constant>(RHS) && !RHS->hasOneUse())
1449f7d4150SCraig Topper         return false;
1459f7d4150SCraig Topper     }
1469f7d4150SCraig Topper   }
1479f7d4150SCraig Topper 
1482b0b9b11SCraig Topper   auto CanShrinkOp = [&](Value *Op) {
1492b0b9b11SCraig Topper     auto IsFreeTruncation = [&](Value *Op) {
1509f7d4150SCraig Topper       if (auto *Cast = dyn_cast<CastInst>(Op)) {
1518abe8300SCraig Topper         if (Cast->getParent() == Mul->getParent() &&
1529f7d4150SCraig Topper             (Cast->getOpcode() == Instruction::SExt ||
1539f7d4150SCraig Topper              Cast->getOpcode() == Instruction::ZExt) &&
1542b0b9b11SCraig Topper             Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 16)
1552b0b9b11SCraig Topper           return true;
1562b0b9b11SCraig Topper       }
1572b0b9b11SCraig Topper 
1582b0b9b11SCraig Topper       return isa<Constant>(Op);
1592b0b9b11SCraig Topper     };
1602b0b9b11SCraig Topper 
1612b0b9b11SCraig Topper     // If the operation can be freely truncated and has enough sign bits we
1622b0b9b11SCraig Topper     // can shrink.
1632b0b9b11SCraig Topper     if (IsFreeTruncation(Op) &&
1648abe8300SCraig Topper         ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16)
1652b0b9b11SCraig Topper       return true;
1662b0b9b11SCraig Topper 
1672b0b9b11SCraig Topper     // SelectionDAG has limited support for truncating through an add or sub if
1682b0b9b11SCraig Topper     // the inputs are freely truncatable.
1692b0b9b11SCraig Topper     if (auto *BO = dyn_cast<BinaryOperator>(Op)) {
1708abe8300SCraig Topper       if (BO->getParent() == Mul->getParent() &&
1712b0b9b11SCraig Topper           IsFreeTruncation(BO->getOperand(0)) &&
1722b0b9b11SCraig Topper           IsFreeTruncation(BO->getOperand(1)) &&
1738abe8300SCraig Topper           ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16)
1749f7d4150SCraig Topper         return true;
1759f7d4150SCraig Topper     }
1769f7d4150SCraig Topper 
1779f7d4150SCraig Topper     return false;
1789f7d4150SCraig Topper   };
1799f7d4150SCraig Topper 
1809f7d4150SCraig Topper   // Both Ops need to be shrinkable.
1812b0b9b11SCraig Topper   if (!CanShrinkOp(LHS) && !CanShrinkOp(RHS))
1829f7d4150SCraig Topper     return false;
1839f7d4150SCraig Topper 
1848abe8300SCraig Topper   IRBuilder<> Builder(Mul);
1859f7d4150SCraig Topper 
1860da1e7ebSChristopher Tetreault   auto *MulTy = cast<FixedVectorType>(Op->getType());
187dd24fb38SChristopher Tetreault   unsigned NumElts = MulTy->getNumElements();
1889f7d4150SCraig Topper 
1899f7d4150SCraig Topper   // Extract even elements and odd elements and add them together. This will
1909f7d4150SCraig Topper   // be pattern matched by SelectionDAG to pmaddwd. This instruction will be
1919f7d4150SCraig Topper   // half the original width.
1926f64dacaSBenjamin Kramer   SmallVector<int, 16> EvenMask(NumElts / 2);
1936f64dacaSBenjamin Kramer   SmallVector<int, 16> OddMask(NumElts / 2);
1949f7d4150SCraig Topper   for (int i = 0, e = NumElts / 2; i != e; ++i) {
1959f7d4150SCraig Topper     EvenMask[i] = i * 2;
1969f7d4150SCraig Topper     OddMask[i] = i * 2 + 1;
1979f7d4150SCraig Topper   }
1988abe8300SCraig Topper   // Creating a new mul so the replaceAllUsesWith below doesn't replace the
1998abe8300SCraig Topper   // uses in the shuffles we're creating.
2008abe8300SCraig Topper   Value *NewMul = Builder.CreateMul(Mul->getOperand(0), Mul->getOperand(1));
2018abe8300SCraig Topper   Value *EvenElts = Builder.CreateShuffleVector(NewMul, NewMul, EvenMask);
2028abe8300SCraig Topper   Value *OddElts = Builder.CreateShuffleVector(NewMul, NewMul, OddMask);
2039f7d4150SCraig Topper   Value *MAdd = Builder.CreateAdd(EvenElts, OddElts);
2049f7d4150SCraig Topper 
2059f7d4150SCraig Topper   // Concatenate zeroes to extend back to the original type.
2066f64dacaSBenjamin Kramer   SmallVector<int, 32> ConcatMask(NumElts);
2079f7d4150SCraig Topper   std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
2089f7d4150SCraig Topper   Value *Zero = Constant::getNullValue(MAdd->getType());
2099f7d4150SCraig Topper   Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask);
2109f7d4150SCraig Topper 
2118abe8300SCraig Topper   Mul->replaceAllUsesWith(Concat);
2128abe8300SCraig Topper   Mul->eraseFromParent();
2139f7d4150SCraig Topper 
2149f7d4150SCraig Topper   return true;
2159f7d4150SCraig Topper }
2169f7d4150SCraig Topper 
2178abe8300SCraig Topper bool X86PartialReduction::trySADReplacement(Instruction *Op) {
2189f7d4150SCraig Topper   if (!ST->hasSSE2())
2199f7d4150SCraig Topper     return false;
2209f7d4150SCraig Topper 
2218abe8300SCraig Topper   // TODO: There's nothing special about i32, any integer type above i16 should
2228abe8300SCraig Topper   // work just as well.
2238abe8300SCraig Topper   if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32))
2249f7d4150SCraig Topper     return false;
2259f7d4150SCraig Topper 
2269f7d4150SCraig Topper   // Operand should be a select.
2279f7d4150SCraig Topper   auto *SI = dyn_cast<SelectInst>(Op);
2289f7d4150SCraig Topper   if (!SI)
2299f7d4150SCraig Topper     return false;
2309f7d4150SCraig Topper 
2319f7d4150SCraig Topper   // Select needs to implement absolute value.
2329f7d4150SCraig Topper   Value *LHS, *RHS;
2339f7d4150SCraig Topper   auto SPR = matchSelectPattern(SI, LHS, RHS);
2349f7d4150SCraig Topper   if (SPR.Flavor != SPF_ABS)
2359f7d4150SCraig Topper     return false;
2369f7d4150SCraig Topper 
2379f7d4150SCraig Topper   // Need a subtract of two values.
2389f7d4150SCraig Topper   auto *Sub = dyn_cast<BinaryOperator>(LHS);
2399f7d4150SCraig Topper   if (!Sub || Sub->getOpcode() != Instruction::Sub)
2409f7d4150SCraig Topper     return false;
2419f7d4150SCraig Topper 
2429f7d4150SCraig Topper   // Look for zero extend from i8.
2439f7d4150SCraig Topper   auto getZeroExtendedVal = [](Value *Op) -> Value * {
2449f7d4150SCraig Topper     if (auto *ZExt = dyn_cast<ZExtInst>(Op))
245dd24fb38SChristopher Tetreault       if (cast<VectorType>(ZExt->getOperand(0)->getType())
246dd24fb38SChristopher Tetreault               ->getElementType()
247dd24fb38SChristopher Tetreault               ->isIntegerTy(8))
2489f7d4150SCraig Topper         return ZExt->getOperand(0);
2499f7d4150SCraig Topper 
2509f7d4150SCraig Topper     return nullptr;
2519f7d4150SCraig Topper   };
2529f7d4150SCraig Topper 
2539f7d4150SCraig Topper   // Both operands of the subtract should be extends from vXi8.
2549f7d4150SCraig Topper   Value *Op0 = getZeroExtendedVal(Sub->getOperand(0));
2559f7d4150SCraig Topper   Value *Op1 = getZeroExtendedVal(Sub->getOperand(1));
2569f7d4150SCraig Topper   if (!Op0 || !Op1)
2579f7d4150SCraig Topper     return false;
2589f7d4150SCraig Topper 
2598abe8300SCraig Topper   IRBuilder<> Builder(SI);
2609f7d4150SCraig Topper 
2610da1e7ebSChristopher Tetreault   auto *OpTy = cast<FixedVectorType>(Op->getType());
262dd24fb38SChristopher Tetreault   unsigned NumElts = OpTy->getNumElements();
2639f7d4150SCraig Topper 
2649f7d4150SCraig Topper   unsigned IntrinsicNumElts;
2659f7d4150SCraig Topper   Intrinsic::ID IID;
2669f7d4150SCraig Topper   if (ST->hasBWI() && NumElts >= 64) {
2679f7d4150SCraig Topper     IID = Intrinsic::x86_avx512_psad_bw_512;
2689f7d4150SCraig Topper     IntrinsicNumElts = 64;
2699f7d4150SCraig Topper   } else if (ST->hasAVX2() && NumElts >= 32) {
2709f7d4150SCraig Topper     IID = Intrinsic::x86_avx2_psad_bw;
2719f7d4150SCraig Topper     IntrinsicNumElts = 32;
2729f7d4150SCraig Topper   } else {
2739f7d4150SCraig Topper     IID = Intrinsic::x86_sse2_psad_bw;
2749f7d4150SCraig Topper     IntrinsicNumElts = 16;
2759f7d4150SCraig Topper   }
2769f7d4150SCraig Topper 
2778abe8300SCraig Topper   Function *PSADBWFn = Intrinsic::getDeclaration(SI->getModule(), IID);
2789f7d4150SCraig Topper 
2799f7d4150SCraig Topper   if (NumElts < 16) {
2809f7d4150SCraig Topper     // Pad input with zeroes.
2816f64dacaSBenjamin Kramer     SmallVector<int, 32> ConcatMask(16);
2829f7d4150SCraig Topper     for (unsigned i = 0; i != NumElts; ++i)
2839f7d4150SCraig Topper       ConcatMask[i] = i;
2849f7d4150SCraig Topper     for (unsigned i = NumElts; i != 16; ++i)
2859f7d4150SCraig Topper       ConcatMask[i] = (i % NumElts) + NumElts;
2869f7d4150SCraig Topper 
2879f7d4150SCraig Topper     Value *Zero = Constant::getNullValue(Op0->getType());
2889f7d4150SCraig Topper     Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask);
2899f7d4150SCraig Topper     Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask);
2909f7d4150SCraig Topper     NumElts = 16;
2919f7d4150SCraig Topper   }
2929f7d4150SCraig Topper 
2939f7d4150SCraig Topper   // Intrinsics produce vXi64 and need to be casted to vXi32.
2945a99ec10SChristopher Tetreault   auto *I32Ty =
2955a99ec10SChristopher Tetreault       FixedVectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4);
2969f7d4150SCraig Topper 
2979f7d4150SCraig Topper   assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!");
2989f7d4150SCraig Topper   unsigned NumSplits = NumElts / IntrinsicNumElts;
2999f7d4150SCraig Topper 
3009f7d4150SCraig Topper   // First collect the pieces we need.
3019f7d4150SCraig Topper   SmallVector<Value *, 4> Ops(NumSplits);
3029f7d4150SCraig Topper   for (unsigned i = 0; i != NumSplits; ++i) {
3036f64dacaSBenjamin Kramer     SmallVector<int, 64> ExtractMask(IntrinsicNumElts);
3049f7d4150SCraig Topper     std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
3059f7d4150SCraig Topper     Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask);
3069f7d4150SCraig Topper     Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask);
3079f7d4150SCraig Topper     Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1});
3089f7d4150SCraig Topper     Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty);
3099f7d4150SCraig Topper   }
3109f7d4150SCraig Topper 
3119f7d4150SCraig Topper   assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits");
3129f7d4150SCraig Topper   unsigned Stages = Log2_32(NumSplits);
3139f7d4150SCraig Topper   for (unsigned s = Stages; s > 0; --s) {
314dd24fb38SChristopher Tetreault     unsigned NumConcatElts =
3150da1e7ebSChristopher Tetreault         cast<FixedVectorType>(Ops[0]->getType())->getNumElements() * 2;
316d2dd0facSMichael Liao     for (unsigned i = 0; i != 1U << (s - 1); ++i) {
3176f64dacaSBenjamin Kramer       SmallVector<int, 64> ConcatMask(NumConcatElts);
3189f7d4150SCraig Topper       std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
3199f7d4150SCraig Topper       Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask);
3209f7d4150SCraig Topper     }
3219f7d4150SCraig Topper   }
3229f7d4150SCraig Topper 
3239f7d4150SCraig Topper   // At this point the final value should be in Ops[0]. Now we need to adjust
3249f7d4150SCraig Topper   // it to the final original type.
3250da1e7ebSChristopher Tetreault   NumElts = cast<FixedVectorType>(OpTy)->getNumElements();
3269f7d4150SCraig Topper   if (NumElts == 2) {
3279f7d4150SCraig Topper     // Extract down to 2 elements.
3281ee6ec2bSEli Friedman     Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], ArrayRef<int>{0, 1});
3299f7d4150SCraig Topper   } else if (NumElts >= 8) {
3306f64dacaSBenjamin Kramer     SmallVector<int, 32> ConcatMask(NumElts);
3310da1e7ebSChristopher Tetreault     unsigned SubElts =
3320da1e7ebSChristopher Tetreault         cast<FixedVectorType>(Ops[0]->getType())->getNumElements();
3339f7d4150SCraig Topper     for (unsigned i = 0; i != SubElts; ++i)
3349f7d4150SCraig Topper       ConcatMask[i] = i;
3359f7d4150SCraig Topper     for (unsigned i = SubElts; i != NumElts; ++i)
3369f7d4150SCraig Topper       ConcatMask[i] = (i % SubElts) + SubElts;
3379f7d4150SCraig Topper 
3389f7d4150SCraig Topper     Value *Zero = Constant::getNullValue(Ops[0]->getType());
3399f7d4150SCraig Topper     Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask);
3409f7d4150SCraig Topper   }
3419f7d4150SCraig Topper 
3428abe8300SCraig Topper   SI->replaceAllUsesWith(Ops[0]);
3438abe8300SCraig Topper   SI->eraseFromParent();
3449f7d4150SCraig Topper 
345fa8c2ae7SCraig Topper   return true;
3469f7d4150SCraig Topper }
3479f7d4150SCraig Topper 
3488abe8300SCraig Topper // Walk backwards from the ExtractElementInst and determine if it is the end of
3498abe8300SCraig Topper // a horizontal reduction. Return the input to the reduction if we find one.
350*21babe4dSLuo, Yuanke static Value *matchAddReduction(const ExtractElementInst &EE,
351*21babe4dSLuo, Yuanke                                 bool &ReduceInOneBB) {
352*21babe4dSLuo, Yuanke   ReduceInOneBB = true;
3538abe8300SCraig Topper   // Make sure we're extracting index 0.
3548abe8300SCraig Topper   auto *Index = dyn_cast<ConstantInt>(EE.getIndexOperand());
3558abe8300SCraig Topper   if (!Index || !Index->isNullValue())
3568abe8300SCraig Topper     return nullptr;
3578abe8300SCraig Topper 
3588abe8300SCraig Topper   const auto *BO = dyn_cast<BinaryOperator>(EE.getVectorOperand());
3598abe8300SCraig Topper   if (!BO || BO->getOpcode() != Instruction::Add || !BO->hasOneUse())
3608abe8300SCraig Topper     return nullptr;
361*21babe4dSLuo, Yuanke   if (EE.getParent() != BO->getParent())
362*21babe4dSLuo, Yuanke     ReduceInOneBB = false;
3638abe8300SCraig Topper 
3640da1e7ebSChristopher Tetreault   unsigned NumElems = cast<FixedVectorType>(BO->getType())->getNumElements();
3658abe8300SCraig Topper   // Ensure the reduction size is a power of 2.
3668abe8300SCraig Topper   if (!isPowerOf2_32(NumElems))
3678abe8300SCraig Topper     return nullptr;
3688abe8300SCraig Topper 
3698abe8300SCraig Topper   const Value *Op = BO;
3708abe8300SCraig Topper   unsigned Stages = Log2_32(NumElems);
3718abe8300SCraig Topper   for (unsigned i = 0; i != Stages; ++i) {
3728abe8300SCraig Topper     const auto *BO = dyn_cast<BinaryOperator>(Op);
3738abe8300SCraig Topper     if (!BO || BO->getOpcode() != Instruction::Add)
3748abe8300SCraig Topper       return nullptr;
375*21babe4dSLuo, Yuanke     if (EE.getParent() != BO->getParent())
376*21babe4dSLuo, Yuanke       ReduceInOneBB = false;
3778abe8300SCraig Topper 
3788abe8300SCraig Topper     // If this isn't the first add, then it should only have 2 users, the
3798abe8300SCraig Topper     // shuffle and another add which we checked in the previous iteration.
3808abe8300SCraig Topper     if (i != 0 && !BO->hasNUses(2))
3818abe8300SCraig Topper       return nullptr;
3828abe8300SCraig Topper 
3838abe8300SCraig Topper     Value *LHS = BO->getOperand(0);
3848abe8300SCraig Topper     Value *RHS = BO->getOperand(1);
3858abe8300SCraig Topper 
3868abe8300SCraig Topper     auto *Shuffle = dyn_cast<ShuffleVectorInst>(LHS);
3878abe8300SCraig Topper     if (Shuffle) {
3888abe8300SCraig Topper       Op = RHS;
3898abe8300SCraig Topper     } else {
3908abe8300SCraig Topper       Shuffle = dyn_cast<ShuffleVectorInst>(RHS);
3918abe8300SCraig Topper       Op = LHS;
3928abe8300SCraig Topper     }
3938abe8300SCraig Topper 
3948abe8300SCraig Topper     // The first operand of the shuffle should be the same as the other operand
3958abe8300SCraig Topper     // of the bin op.
3968abe8300SCraig Topper     if (!Shuffle || Shuffle->getOperand(0) != Op)
3978abe8300SCraig Topper       return nullptr;
3988abe8300SCraig Topper 
3998abe8300SCraig Topper     // Verify the shuffle has the expected (at this stage of the pyramid) mask.
4008abe8300SCraig Topper     unsigned MaskEnd = 1 << i;
4018abe8300SCraig Topper     for (unsigned Index = 0; Index < MaskEnd; ++Index)
4028abe8300SCraig Topper       if (Shuffle->getMaskValue(Index) != (int)(MaskEnd + Index))
4038abe8300SCraig Topper         return nullptr;
4048abe8300SCraig Topper   }
4058abe8300SCraig Topper 
4068abe8300SCraig Topper   return const_cast<Value *>(Op);
4078abe8300SCraig Topper }
4088abe8300SCraig Topper 
4098abe8300SCraig Topper // See if this BO is reachable from this Phi by walking forward through single
4108abe8300SCraig Topper // use BinaryOperators with the same opcode. If we get back then we know we've
4118abe8300SCraig Topper // found a loop and it is safe to step through this Add to find more leaves.
4128abe8300SCraig Topper static bool isReachableFromPHI(PHINode *Phi, BinaryOperator *BO) {
4138abe8300SCraig Topper   // The PHI itself should only have one use.
4148abe8300SCraig Topper   if (!Phi->hasOneUse())
4159f7d4150SCraig Topper     return false;
4169f7d4150SCraig Topper 
4178abe8300SCraig Topper   Instruction *U = cast<Instruction>(*Phi->user_begin());
4188abe8300SCraig Topper   if (U == BO)
4198abe8300SCraig Topper     return true;
4209f7d4150SCraig Topper 
4218abe8300SCraig Topper   while (U->hasOneUse() && U->getOpcode() == BO->getOpcode())
4228abe8300SCraig Topper     U = cast<Instruction>(*U->user_begin());
4238abe8300SCraig Topper 
4248abe8300SCraig Topper   return U == BO;
4258abe8300SCraig Topper }
4268abe8300SCraig Topper 
4278abe8300SCraig Topper // Collect all the leaves of the tree of adds that feeds into the horizontal
4288abe8300SCraig Topper // reduction. Root is the Value that is used by the horizontal reduction.
4298abe8300SCraig Topper // We look through single use phis, single use adds, or adds that are used by
4308abe8300SCraig Topper // a phi that forms a loop with the add.
4318abe8300SCraig Topper static void collectLeaves(Value *Root, SmallVectorImpl<Instruction *> &Leaves) {
4328abe8300SCraig Topper   SmallPtrSet<Value *, 8> Visited;
4338abe8300SCraig Topper   SmallVector<Value *, 8> Worklist;
4348abe8300SCraig Topper   Worklist.push_back(Root);
4358abe8300SCraig Topper 
4368abe8300SCraig Topper   while (!Worklist.empty()) {
4378abe8300SCraig Topper     Value *V = Worklist.pop_back_val();
4388abe8300SCraig Topper      if (!Visited.insert(V).second)
4398abe8300SCraig Topper        continue;
4408abe8300SCraig Topper 
4418abe8300SCraig Topper     if (auto *PN = dyn_cast<PHINode>(V)) {
4428abe8300SCraig Topper       // PHI node should have single use unless it is the root node, then it
4438abe8300SCraig Topper       // has 2 uses.
4448abe8300SCraig Topper       if (!PN->hasNUses(PN == Root ? 2 : 1))
4458abe8300SCraig Topper         break;
4468abe8300SCraig Topper 
4478abe8300SCraig Topper       // Push incoming values to the worklist.
44805444417SKazu Hirata       append_range(Worklist, PN->incoming_values());
4498abe8300SCraig Topper 
4508abe8300SCraig Topper       continue;
4518abe8300SCraig Topper     }
4528abe8300SCraig Topper 
4538abe8300SCraig Topper     if (auto *BO = dyn_cast<BinaryOperator>(V)) {
4548abe8300SCraig Topper       if (BO->getOpcode() == Instruction::Add) {
4558abe8300SCraig Topper         // Simple case. Single use, just push its operands to the worklist.
4568abe8300SCraig Topper         if (BO->hasNUses(BO == Root ? 2 : 1)) {
45705444417SKazu Hirata           append_range(Worklist, BO->operands());
4588abe8300SCraig Topper           continue;
4598abe8300SCraig Topper         }
4608abe8300SCraig Topper 
4618abe8300SCraig Topper         // If there is additional use, make sure it is an unvisited phi that
4628abe8300SCraig Topper         // gets us back to this node.
4638abe8300SCraig Topper         if (BO->hasNUses(BO == Root ? 3 : 2)) {
4648abe8300SCraig Topper           PHINode *PN = nullptr;
4658abe8300SCraig Topper           for (auto *U : Root->users())
4668abe8300SCraig Topper             if (auto *P = dyn_cast<PHINode>(U))
4678abe8300SCraig Topper               if (!Visited.count(P))
4688abe8300SCraig Topper                 PN = P;
4698abe8300SCraig Topper 
4708abe8300SCraig Topper           // If we didn't find a 2-input PHI then this isn't a case we can
4718abe8300SCraig Topper           // handle.
4728abe8300SCraig Topper           if (!PN || PN->getNumIncomingValues() != 2)
4738abe8300SCraig Topper             continue;
4748abe8300SCraig Topper 
4758abe8300SCraig Topper           // Walk forward from this phi to see if it reaches back to this add.
4768abe8300SCraig Topper           if (!isReachableFromPHI(PN, BO))
4778abe8300SCraig Topper             continue;
4788abe8300SCraig Topper 
4798abe8300SCraig Topper           // The phi forms a loop with this Add, push its operands.
48005444417SKazu Hirata           append_range(Worklist, BO->operands());
4818abe8300SCraig Topper         }
4828abe8300SCraig Topper       }
4838abe8300SCraig Topper     }
4848abe8300SCraig Topper 
4858abe8300SCraig Topper     // Not an add or phi, make it a leaf.
4868abe8300SCraig Topper     if (auto *I = dyn_cast<Instruction>(V)) {
4878abe8300SCraig Topper       if (!V->hasNUses(I == Root ? 2 : 1))
4888abe8300SCraig Topper         continue;
4898abe8300SCraig Topper 
4908abe8300SCraig Topper       // Add this as a leaf.
4918abe8300SCraig Topper       Leaves.push_back(I);
4928abe8300SCraig Topper     }
4938abe8300SCraig Topper   }
4949f7d4150SCraig Topper }
4959f7d4150SCraig Topper 
4969f7d4150SCraig Topper bool X86PartialReduction::runOnFunction(Function &F) {
4979f7d4150SCraig Topper   if (skipFunction(F))
4989f7d4150SCraig Topper     return false;
4999f7d4150SCraig Topper 
5009f7d4150SCraig Topper   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
5019f7d4150SCraig Topper   if (!TPC)
5029f7d4150SCraig Topper     return false;
5039f7d4150SCraig Topper 
5049f7d4150SCraig Topper   auto &TM = TPC->getTM<X86TargetMachine>();
5059f7d4150SCraig Topper   ST = TM.getSubtargetImpl(F);
5069f7d4150SCraig Topper 
5079f7d4150SCraig Topper   DL = &F.getParent()->getDataLayout();
5089f7d4150SCraig Topper 
5099f7d4150SCraig Topper   bool MadeChange = false;
5109f7d4150SCraig Topper   for (auto &BB : F) {
5119f7d4150SCraig Topper     for (auto &I : BB) {
5128abe8300SCraig Topper       auto *EE = dyn_cast<ExtractElementInst>(&I);
5138abe8300SCraig Topper       if (!EE)
5149f7d4150SCraig Topper         continue;
5159f7d4150SCraig Topper 
516*21babe4dSLuo, Yuanke       bool ReduceInOneBB;
5178abe8300SCraig Topper       // First find a reduction tree.
5188abe8300SCraig Topper       // FIXME: Do we need to handle other opcodes than Add?
519*21babe4dSLuo, Yuanke       Value *Root = matchAddReduction(*EE, ReduceInOneBB);
5208abe8300SCraig Topper       if (!Root)
5219f7d4150SCraig Topper         continue;
5229f7d4150SCraig Topper 
5238abe8300SCraig Topper       SmallVector<Instruction *, 8> Leaves;
5248abe8300SCraig Topper       collectLeaves(Root, Leaves);
5258abe8300SCraig Topper 
5268abe8300SCraig Topper       for (Instruction *I : Leaves) {
527*21babe4dSLuo, Yuanke         if (tryMAddReplacement(I, ReduceInOneBB)) {
5289f7d4150SCraig Topper           MadeChange = true;
5299f7d4150SCraig Topper           continue;
5309f7d4150SCraig Topper         }
5318abe8300SCraig Topper 
5328abe8300SCraig Topper         // Don't do SAD matching on the root node. SelectionDAG already
5338abe8300SCraig Topper         // has support for that and currently generates better code.
5348abe8300SCraig Topper         if (I != Root && trySADReplacement(I))
5359f7d4150SCraig Topper           MadeChange = true;
5369f7d4150SCraig Topper       }
5379f7d4150SCraig Topper     }
5389f7d4150SCraig Topper   }
5399f7d4150SCraig Topper 
5409f7d4150SCraig Topper   return MadeChange;
5419f7d4150SCraig Topper }
542