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"
1621babe4dSLuo, 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"
2021babe4dSLuo, Yuanke #include "llvm/IR/IRBuilder.h"
219f7d4150SCraig Topper #include "llvm/IR/Instructions.h"
22ca33d74cSWei Xiao #include "llvm/IR/IntrinsicInst.h"
239f7d4150SCraig Topper #include "llvm/IR/IntrinsicsX86.h"
249f7d4150SCraig Topper #include "llvm/IR/Operator.h"
25ca33d74cSWei Xiao #include "llvm/IR/PatternMatch.h"
269f7d4150SCraig Topper #include "llvm/Pass.h"
2721babe4dSLuo, Yuanke #include "llvm/Support/KnownBits.h"
289f7d4150SCraig Topper
299f7d4150SCraig Topper using namespace llvm;
309f7d4150SCraig Topper
319f7d4150SCraig Topper #define DEBUG_TYPE "x86-partial-reduction"
329f7d4150SCraig Topper
339f7d4150SCraig Topper namespace {
349f7d4150SCraig Topper
359f7d4150SCraig Topper class X86PartialReduction : public FunctionPass {
369f7d4150SCraig Topper const DataLayout *DL;
379f7d4150SCraig Topper const X86Subtarget *ST;
389f7d4150SCraig Topper
399f7d4150SCraig Topper public:
409f7d4150SCraig Topper static char ID; // Pass identification, replacement for typeid.
419f7d4150SCraig Topper
X86PartialReduction()429f7d4150SCraig Topper X86PartialReduction() : FunctionPass(ID) { }
439f7d4150SCraig Topper
449f7d4150SCraig Topper bool runOnFunction(Function &Fn) override;
459f7d4150SCraig Topper
getAnalysisUsage(AnalysisUsage & AU) const469f7d4150SCraig Topper void getAnalysisUsage(AnalysisUsage &AU) const override {
479f7d4150SCraig Topper AU.setPreservesCFG();
489f7d4150SCraig Topper }
499f7d4150SCraig Topper
getPassName() const509f7d4150SCraig Topper StringRef getPassName() const override {
519f7d4150SCraig Topper return "X86 Partial Reduction";
529f7d4150SCraig Topper }
539f7d4150SCraig Topper
549f7d4150SCraig Topper private:
5521babe4dSLuo, Yuanke bool tryMAddReplacement(Instruction *Op, bool ReduceInOneBB);
568abe8300SCraig Topper bool trySADReplacement(Instruction *Op);
579f7d4150SCraig Topper };
589f7d4150SCraig Topper }
599f7d4150SCraig Topper
createX86PartialReductionPass()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
6921babe4dSLuo, Yuanke // This function should be aligned with detectExtMul() in X86ISelLowering.cpp.
matchVPDPBUSDPattern(const X86Subtarget * ST,BinaryOperator * Mul,const DataLayout * DL)7021babe4dSLuo, Yuanke static bool matchVPDPBUSDPattern(const X86Subtarget *ST, BinaryOperator *Mul,
7121babe4dSLuo, Yuanke const DataLayout *DL) {
7221babe4dSLuo, Yuanke if (!ST->hasVNNI() && !ST->hasAVXVNNI())
7321babe4dSLuo, Yuanke return false;
7421babe4dSLuo, Yuanke
7521babe4dSLuo, Yuanke Value *LHS = Mul->getOperand(0);
7621babe4dSLuo, Yuanke Value *RHS = Mul->getOperand(1);
7721babe4dSLuo, Yuanke
7821babe4dSLuo, Yuanke if (isa<SExtInst>(LHS))
7921babe4dSLuo, Yuanke std::swap(LHS, RHS);
8021babe4dSLuo, Yuanke
8121babe4dSLuo, Yuanke auto IsFreeTruncation = [&](Value *Op) {
8221babe4dSLuo, Yuanke if (auto *Cast = dyn_cast<CastInst>(Op)) {
8321babe4dSLuo, Yuanke if (Cast->getParent() == Mul->getParent() &&
8421babe4dSLuo, Yuanke (Cast->getOpcode() == Instruction::SExt ||
8521babe4dSLuo, Yuanke Cast->getOpcode() == Instruction::ZExt) &&
8621babe4dSLuo, Yuanke Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 8)
8721babe4dSLuo, Yuanke return true;
8821babe4dSLuo, Yuanke }
895dea7a86SLuo, Yuanke
905dea7a86SLuo, Yuanke return isa<Constant>(Op);
9121babe4dSLuo, Yuanke };
9221babe4dSLuo, Yuanke
9321babe4dSLuo, Yuanke // (dpbusd (zext a), (sext, b)). Since the first operand should be unsigned
9421babe4dSLuo, Yuanke // value, we need to check LHS is zero extended value. RHS should be signed
9521babe4dSLuo, Yuanke // value, so we just check the signed bits.
9621babe4dSLuo, Yuanke if ((IsFreeTruncation(LHS) &&
9721babe4dSLuo, Yuanke computeKnownBits(LHS, *DL).countMaxActiveBits() <= 8) &&
9821babe4dSLuo, Yuanke (IsFreeTruncation(RHS) && ComputeMaxSignificantBits(RHS, *DL) <= 8))
9921babe4dSLuo, Yuanke return true;
10021babe4dSLuo, Yuanke
10121babe4dSLuo, Yuanke return false;
10221babe4dSLuo, Yuanke }
10321babe4dSLuo, Yuanke
tryMAddReplacement(Instruction * Op,bool ReduceInOneBB)10421babe4dSLuo, Yuanke bool X86PartialReduction::tryMAddReplacement(Instruction *Op,
10521babe4dSLuo, Yuanke bool ReduceInOneBB) {
1068abe8300SCraig Topper if (!ST->hasSSE2())
1079f7d4150SCraig Topper return false;
1089f7d4150SCraig Topper
1098abe8300SCraig Topper // Need at least 8 elements.
1100da1e7ebSChristopher Tetreault if (cast<FixedVectorType>(Op->getType())->getNumElements() < 8)
1119f7d4150SCraig Topper return false;
1129f7d4150SCraig Topper
1138abe8300SCraig Topper // Element type should be i32.
1148abe8300SCraig Topper if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32))
1159f7d4150SCraig Topper return false;
1169f7d4150SCraig Topper
1178abe8300SCraig Topper auto *Mul = dyn_cast<BinaryOperator>(Op);
1188abe8300SCraig Topper if (!Mul || Mul->getOpcode() != Instruction::Mul)
1199f7d4150SCraig Topper return false;
1209f7d4150SCraig Topper
1218abe8300SCraig Topper Value *LHS = Mul->getOperand(0);
1228abe8300SCraig Topper Value *RHS = Mul->getOperand(1);
1239f7d4150SCraig Topper
12421babe4dSLuo, Yuanke // If the target support VNNI, leave it to ISel to combine reduce operation
12521babe4dSLuo, Yuanke // to VNNI instruction.
12621babe4dSLuo, Yuanke // TODO: we can support transforming reduce to VNNI intrinsic for across block
12721babe4dSLuo, Yuanke // in this pass.
12821babe4dSLuo, Yuanke if (ReduceInOneBB && matchVPDPBUSDPattern(ST, Mul, DL))
12921babe4dSLuo, Yuanke return false;
13021babe4dSLuo, Yuanke
1319f7d4150SCraig Topper // LHS and RHS should be only used once or if they are the same then only
1329f7d4150SCraig Topper // used twice. Only check this when SSE4.1 is enabled and we have zext/sext
1339f7d4150SCraig Topper // instructions, otherwise we use punpck to emulate zero extend in stages. The
1349f7d4150SCraig Topper // trunc/ we need to do likely won't introduce new instructions in that case.
1359f7d4150SCraig Topper if (ST->hasSSE41()) {
1369f7d4150SCraig Topper if (LHS == RHS) {
1379f7d4150SCraig Topper if (!isa<Constant>(LHS) && !LHS->hasNUses(2))
1389f7d4150SCraig Topper return false;
1399f7d4150SCraig Topper } else {
1409f7d4150SCraig Topper if (!isa<Constant>(LHS) && !LHS->hasOneUse())
1419f7d4150SCraig Topper return false;
1429f7d4150SCraig Topper if (!isa<Constant>(RHS) && !RHS->hasOneUse())
1439f7d4150SCraig Topper return false;
1449f7d4150SCraig Topper }
1459f7d4150SCraig Topper }
1469f7d4150SCraig Topper
1472b0b9b11SCraig Topper auto CanShrinkOp = [&](Value *Op) {
1482b0b9b11SCraig Topper auto IsFreeTruncation = [&](Value *Op) {
1499f7d4150SCraig Topper if (auto *Cast = dyn_cast<CastInst>(Op)) {
1508abe8300SCraig Topper if (Cast->getParent() == Mul->getParent() &&
1519f7d4150SCraig Topper (Cast->getOpcode() == Instruction::SExt ||
1529f7d4150SCraig Topper Cast->getOpcode() == Instruction::ZExt) &&
1532b0b9b11SCraig Topper Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 16)
1542b0b9b11SCraig Topper return true;
1552b0b9b11SCraig Topper }
1562b0b9b11SCraig Topper
1572b0b9b11SCraig Topper return isa<Constant>(Op);
1582b0b9b11SCraig Topper };
1592b0b9b11SCraig Topper
1602b0b9b11SCraig Topper // If the operation can be freely truncated and has enough sign bits we
1612b0b9b11SCraig Topper // can shrink.
1622b0b9b11SCraig Topper if (IsFreeTruncation(Op) &&
1638abe8300SCraig Topper ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16)
1642b0b9b11SCraig Topper return true;
1652b0b9b11SCraig Topper
1662b0b9b11SCraig Topper // SelectionDAG has limited support for truncating through an add or sub if
1672b0b9b11SCraig Topper // the inputs are freely truncatable.
1682b0b9b11SCraig Topper if (auto *BO = dyn_cast<BinaryOperator>(Op)) {
1698abe8300SCraig Topper if (BO->getParent() == Mul->getParent() &&
1702b0b9b11SCraig Topper IsFreeTruncation(BO->getOperand(0)) &&
1712b0b9b11SCraig Topper IsFreeTruncation(BO->getOperand(1)) &&
1728abe8300SCraig Topper ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16)
1739f7d4150SCraig Topper return true;
1749f7d4150SCraig Topper }
1759f7d4150SCraig Topper
1769f7d4150SCraig Topper return false;
1779f7d4150SCraig Topper };
1789f7d4150SCraig Topper
1799f7d4150SCraig Topper // Both Ops need to be shrinkable.
1802b0b9b11SCraig Topper if (!CanShrinkOp(LHS) && !CanShrinkOp(RHS))
1819f7d4150SCraig Topper return false;
1829f7d4150SCraig Topper
1838abe8300SCraig Topper IRBuilder<> Builder(Mul);
1849f7d4150SCraig Topper
1850da1e7ebSChristopher Tetreault auto *MulTy = cast<FixedVectorType>(Op->getType());
186dd24fb38SChristopher Tetreault unsigned NumElts = MulTy->getNumElements();
1879f7d4150SCraig Topper
1889f7d4150SCraig Topper // Extract even elements and odd elements and add them together. This will
1899f7d4150SCraig Topper // be pattern matched by SelectionDAG to pmaddwd. This instruction will be
1909f7d4150SCraig Topper // half the original width.
1916f64dacaSBenjamin Kramer SmallVector<int, 16> EvenMask(NumElts / 2);
1926f64dacaSBenjamin Kramer SmallVector<int, 16> OddMask(NumElts / 2);
1939f7d4150SCraig Topper for (int i = 0, e = NumElts / 2; i != e; ++i) {
1949f7d4150SCraig Topper EvenMask[i] = i * 2;
1959f7d4150SCraig Topper OddMask[i] = i * 2 + 1;
1969f7d4150SCraig Topper }
1978abe8300SCraig Topper // Creating a new mul so the replaceAllUsesWith below doesn't replace the
1988abe8300SCraig Topper // uses in the shuffles we're creating.
1998abe8300SCraig Topper Value *NewMul = Builder.CreateMul(Mul->getOperand(0), Mul->getOperand(1));
2008abe8300SCraig Topper Value *EvenElts = Builder.CreateShuffleVector(NewMul, NewMul, EvenMask);
2018abe8300SCraig Topper Value *OddElts = Builder.CreateShuffleVector(NewMul, NewMul, OddMask);
2029f7d4150SCraig Topper Value *MAdd = Builder.CreateAdd(EvenElts, OddElts);
2039f7d4150SCraig Topper
2049f7d4150SCraig Topper // Concatenate zeroes to extend back to the original type.
2056f64dacaSBenjamin Kramer SmallVector<int, 32> ConcatMask(NumElts);
2069f7d4150SCraig Topper std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
2079f7d4150SCraig Topper Value *Zero = Constant::getNullValue(MAdd->getType());
2089f7d4150SCraig Topper Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask);
2099f7d4150SCraig Topper
2108abe8300SCraig Topper Mul->replaceAllUsesWith(Concat);
2118abe8300SCraig Topper Mul->eraseFromParent();
2129f7d4150SCraig Topper
2139f7d4150SCraig Topper return true;
2149f7d4150SCraig Topper }
2159f7d4150SCraig Topper
trySADReplacement(Instruction * Op)2168abe8300SCraig Topper bool X86PartialReduction::trySADReplacement(Instruction *Op) {
2179f7d4150SCraig Topper if (!ST->hasSSE2())
2189f7d4150SCraig Topper return false;
2199f7d4150SCraig Topper
2208abe8300SCraig Topper // TODO: There's nothing special about i32, any integer type above i16 should
2218abe8300SCraig Topper // work just as well.
2228abe8300SCraig Topper if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32))
2239f7d4150SCraig Topper return false;
2249f7d4150SCraig Topper
225ca33d74cSWei Xiao Value *LHS;
226ca33d74cSWei Xiao if (match(Op, PatternMatch::m_Intrinsic<Intrinsic::abs>())) {
227ca33d74cSWei Xiao LHS = Op->getOperand(0);
228ca33d74cSWei Xiao } else {
2299f7d4150SCraig Topper // Operand should be a select.
2309f7d4150SCraig Topper auto *SI = dyn_cast<SelectInst>(Op);
2319f7d4150SCraig Topper if (!SI)
2329f7d4150SCraig Topper return false;
2339f7d4150SCraig Topper
234ca33d74cSWei Xiao Value *RHS;
2359f7d4150SCraig Topper // Select needs to implement absolute value.
2369f7d4150SCraig Topper auto SPR = matchSelectPattern(SI, LHS, RHS);
2379f7d4150SCraig Topper if (SPR.Flavor != SPF_ABS)
2389f7d4150SCraig Topper return false;
239ca33d74cSWei Xiao }
2409f7d4150SCraig Topper
2419f7d4150SCraig Topper // Need a subtract of two values.
2429f7d4150SCraig Topper auto *Sub = dyn_cast<BinaryOperator>(LHS);
2439f7d4150SCraig Topper if (!Sub || Sub->getOpcode() != Instruction::Sub)
2449f7d4150SCraig Topper return false;
2459f7d4150SCraig Topper
2469f7d4150SCraig Topper // Look for zero extend from i8.
2479f7d4150SCraig Topper auto getZeroExtendedVal = [](Value *Op) -> Value * {
2489f7d4150SCraig Topper if (auto *ZExt = dyn_cast<ZExtInst>(Op))
249dd24fb38SChristopher Tetreault if (cast<VectorType>(ZExt->getOperand(0)->getType())
250dd24fb38SChristopher Tetreault ->getElementType()
251dd24fb38SChristopher Tetreault ->isIntegerTy(8))
2529f7d4150SCraig Topper return ZExt->getOperand(0);
2539f7d4150SCraig Topper
2549f7d4150SCraig Topper return nullptr;
2559f7d4150SCraig Topper };
2569f7d4150SCraig Topper
2579f7d4150SCraig Topper // Both operands of the subtract should be extends from vXi8.
2589f7d4150SCraig Topper Value *Op0 = getZeroExtendedVal(Sub->getOperand(0));
2599f7d4150SCraig Topper Value *Op1 = getZeroExtendedVal(Sub->getOperand(1));
2609f7d4150SCraig Topper if (!Op0 || !Op1)
2619f7d4150SCraig Topper return false;
2629f7d4150SCraig Topper
263ca33d74cSWei Xiao IRBuilder<> Builder(Op);
2649f7d4150SCraig Topper
2650da1e7ebSChristopher Tetreault auto *OpTy = cast<FixedVectorType>(Op->getType());
266dd24fb38SChristopher Tetreault unsigned NumElts = OpTy->getNumElements();
2679f7d4150SCraig Topper
2689f7d4150SCraig Topper unsigned IntrinsicNumElts;
2699f7d4150SCraig Topper Intrinsic::ID IID;
2709f7d4150SCraig Topper if (ST->hasBWI() && NumElts >= 64) {
2719f7d4150SCraig Topper IID = Intrinsic::x86_avx512_psad_bw_512;
2729f7d4150SCraig Topper IntrinsicNumElts = 64;
2739f7d4150SCraig Topper } else if (ST->hasAVX2() && NumElts >= 32) {
2749f7d4150SCraig Topper IID = Intrinsic::x86_avx2_psad_bw;
2759f7d4150SCraig Topper IntrinsicNumElts = 32;
2769f7d4150SCraig Topper } else {
2779f7d4150SCraig Topper IID = Intrinsic::x86_sse2_psad_bw;
2789f7d4150SCraig Topper IntrinsicNumElts = 16;
2799f7d4150SCraig Topper }
2809f7d4150SCraig Topper
281ca33d74cSWei Xiao Function *PSADBWFn = Intrinsic::getDeclaration(Op->getModule(), IID);
2829f7d4150SCraig Topper
2839f7d4150SCraig Topper if (NumElts < 16) {
2849f7d4150SCraig Topper // Pad input with zeroes.
2856f64dacaSBenjamin Kramer SmallVector<int, 32> ConcatMask(16);
2869f7d4150SCraig Topper for (unsigned i = 0; i != NumElts; ++i)
2879f7d4150SCraig Topper ConcatMask[i] = i;
2889f7d4150SCraig Topper for (unsigned i = NumElts; i != 16; ++i)
2899f7d4150SCraig Topper ConcatMask[i] = (i % NumElts) + NumElts;
2909f7d4150SCraig Topper
2919f7d4150SCraig Topper Value *Zero = Constant::getNullValue(Op0->getType());
2929f7d4150SCraig Topper Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask);
2939f7d4150SCraig Topper Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask);
2949f7d4150SCraig Topper NumElts = 16;
2959f7d4150SCraig Topper }
2969f7d4150SCraig Topper
2979f7d4150SCraig Topper // Intrinsics produce vXi64 and need to be casted to vXi32.
2985a99ec10SChristopher Tetreault auto *I32Ty =
2995a99ec10SChristopher Tetreault FixedVectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4);
3009f7d4150SCraig Topper
3019f7d4150SCraig Topper assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!");
3029f7d4150SCraig Topper unsigned NumSplits = NumElts / IntrinsicNumElts;
3039f7d4150SCraig Topper
3049f7d4150SCraig Topper // First collect the pieces we need.
3059f7d4150SCraig Topper SmallVector<Value *, 4> Ops(NumSplits);
3069f7d4150SCraig Topper for (unsigned i = 0; i != NumSplits; ++i) {
3076f64dacaSBenjamin Kramer SmallVector<int, 64> ExtractMask(IntrinsicNumElts);
3089f7d4150SCraig Topper std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
3099f7d4150SCraig Topper Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask);
3109f7d4150SCraig Topper Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask);
3119f7d4150SCraig Topper Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1});
3129f7d4150SCraig Topper Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty);
3139f7d4150SCraig Topper }
3149f7d4150SCraig Topper
3159f7d4150SCraig Topper assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits");
3169f7d4150SCraig Topper unsigned Stages = Log2_32(NumSplits);
3179f7d4150SCraig Topper for (unsigned s = Stages; s > 0; --s) {
318dd24fb38SChristopher Tetreault unsigned NumConcatElts =
3190da1e7ebSChristopher Tetreault cast<FixedVectorType>(Ops[0]->getType())->getNumElements() * 2;
320d2dd0facSMichael Liao for (unsigned i = 0; i != 1U << (s - 1); ++i) {
3216f64dacaSBenjamin Kramer SmallVector<int, 64> ConcatMask(NumConcatElts);
3229f7d4150SCraig Topper std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
3239f7d4150SCraig Topper Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask);
3249f7d4150SCraig Topper }
3259f7d4150SCraig Topper }
3269f7d4150SCraig Topper
3279f7d4150SCraig Topper // At this point the final value should be in Ops[0]. Now we need to adjust
3289f7d4150SCraig Topper // it to the final original type.
3290da1e7ebSChristopher Tetreault NumElts = cast<FixedVectorType>(OpTy)->getNumElements();
3309f7d4150SCraig Topper if (NumElts == 2) {
3319f7d4150SCraig Topper // Extract down to 2 elements.
3321ee6ec2bSEli Friedman Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], ArrayRef<int>{0, 1});
3339f7d4150SCraig Topper } else if (NumElts >= 8) {
3346f64dacaSBenjamin Kramer SmallVector<int, 32> ConcatMask(NumElts);
3350da1e7ebSChristopher Tetreault unsigned SubElts =
3360da1e7ebSChristopher Tetreault cast<FixedVectorType>(Ops[0]->getType())->getNumElements();
3379f7d4150SCraig Topper for (unsigned i = 0; i != SubElts; ++i)
3389f7d4150SCraig Topper ConcatMask[i] = i;
3399f7d4150SCraig Topper for (unsigned i = SubElts; i != NumElts; ++i)
3409f7d4150SCraig Topper ConcatMask[i] = (i % SubElts) + SubElts;
3419f7d4150SCraig Topper
3429f7d4150SCraig Topper Value *Zero = Constant::getNullValue(Ops[0]->getType());
3439f7d4150SCraig Topper Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask);
3449f7d4150SCraig Topper }
3459f7d4150SCraig Topper
346ca33d74cSWei Xiao Op->replaceAllUsesWith(Ops[0]);
347ca33d74cSWei Xiao Op->eraseFromParent();
3489f7d4150SCraig Topper
349fa8c2ae7SCraig Topper return true;
3509f7d4150SCraig Topper }
3519f7d4150SCraig Topper
3528abe8300SCraig Topper // Walk backwards from the ExtractElementInst and determine if it is the end of
3538abe8300SCraig Topper // a horizontal reduction. Return the input to the reduction if we find one.
matchAddReduction(const ExtractElementInst & EE,bool & ReduceInOneBB)35421babe4dSLuo, Yuanke static Value *matchAddReduction(const ExtractElementInst &EE,
35521babe4dSLuo, Yuanke bool &ReduceInOneBB) {
35621babe4dSLuo, Yuanke ReduceInOneBB = true;
3578abe8300SCraig Topper // Make sure we're extracting index 0.
3588abe8300SCraig Topper auto *Index = dyn_cast<ConstantInt>(EE.getIndexOperand());
3598abe8300SCraig Topper if (!Index || !Index->isNullValue())
3608abe8300SCraig Topper return nullptr;
3618abe8300SCraig Topper
3628abe8300SCraig Topper const auto *BO = dyn_cast<BinaryOperator>(EE.getVectorOperand());
3638abe8300SCraig Topper if (!BO || BO->getOpcode() != Instruction::Add || !BO->hasOneUse())
3648abe8300SCraig Topper return nullptr;
36521babe4dSLuo, Yuanke if (EE.getParent() != BO->getParent())
36621babe4dSLuo, Yuanke ReduceInOneBB = false;
3678abe8300SCraig Topper
3680da1e7ebSChristopher Tetreault unsigned NumElems = cast<FixedVectorType>(BO->getType())->getNumElements();
3698abe8300SCraig Topper // Ensure the reduction size is a power of 2.
3708abe8300SCraig Topper if (!isPowerOf2_32(NumElems))
3718abe8300SCraig Topper return nullptr;
3728abe8300SCraig Topper
3738abe8300SCraig Topper const Value *Op = BO;
3748abe8300SCraig Topper unsigned Stages = Log2_32(NumElems);
3758abe8300SCraig Topper for (unsigned i = 0; i != Stages; ++i) {
3768abe8300SCraig Topper const auto *BO = dyn_cast<BinaryOperator>(Op);
3778abe8300SCraig Topper if (!BO || BO->getOpcode() != Instruction::Add)
3788abe8300SCraig Topper return nullptr;
37921babe4dSLuo, Yuanke if (EE.getParent() != BO->getParent())
38021babe4dSLuo, Yuanke ReduceInOneBB = false;
3818abe8300SCraig Topper
3828abe8300SCraig Topper // If this isn't the first add, then it should only have 2 users, the
3838abe8300SCraig Topper // shuffle and another add which we checked in the previous iteration.
3848abe8300SCraig Topper if (i != 0 && !BO->hasNUses(2))
3858abe8300SCraig Topper return nullptr;
3868abe8300SCraig Topper
3878abe8300SCraig Topper Value *LHS = BO->getOperand(0);
3888abe8300SCraig Topper Value *RHS = BO->getOperand(1);
3898abe8300SCraig Topper
3908abe8300SCraig Topper auto *Shuffle = dyn_cast<ShuffleVectorInst>(LHS);
3918abe8300SCraig Topper if (Shuffle) {
3928abe8300SCraig Topper Op = RHS;
3938abe8300SCraig Topper } else {
3948abe8300SCraig Topper Shuffle = dyn_cast<ShuffleVectorInst>(RHS);
3958abe8300SCraig Topper Op = LHS;
3968abe8300SCraig Topper }
3978abe8300SCraig Topper
3988abe8300SCraig Topper // The first operand of the shuffle should be the same as the other operand
3998abe8300SCraig Topper // of the bin op.
4008abe8300SCraig Topper if (!Shuffle || Shuffle->getOperand(0) != Op)
4018abe8300SCraig Topper return nullptr;
4028abe8300SCraig Topper
4038abe8300SCraig Topper // Verify the shuffle has the expected (at this stage of the pyramid) mask.
4048abe8300SCraig Topper unsigned MaskEnd = 1 << i;
4058abe8300SCraig Topper for (unsigned Index = 0; Index < MaskEnd; ++Index)
4068abe8300SCraig Topper if (Shuffle->getMaskValue(Index) != (int)(MaskEnd + Index))
4078abe8300SCraig Topper return nullptr;
4088abe8300SCraig Topper }
4098abe8300SCraig Topper
4108abe8300SCraig Topper return const_cast<Value *>(Op);
4118abe8300SCraig Topper }
4128abe8300SCraig Topper
4138abe8300SCraig Topper // See if this BO is reachable from this Phi by walking forward through single
4148abe8300SCraig Topper // use BinaryOperators with the same opcode. If we get back then we know we've
4158abe8300SCraig Topper // found a loop and it is safe to step through this Add to find more leaves.
isReachableFromPHI(PHINode * Phi,BinaryOperator * BO)4168abe8300SCraig Topper static bool isReachableFromPHI(PHINode *Phi, BinaryOperator *BO) {
4178abe8300SCraig Topper // The PHI itself should only have one use.
4188abe8300SCraig Topper if (!Phi->hasOneUse())
4199f7d4150SCraig Topper return false;
4209f7d4150SCraig Topper
4218abe8300SCraig Topper Instruction *U = cast<Instruction>(*Phi->user_begin());
4228abe8300SCraig Topper if (U == BO)
4238abe8300SCraig Topper return true;
4249f7d4150SCraig Topper
4258abe8300SCraig Topper while (U->hasOneUse() && U->getOpcode() == BO->getOpcode())
4268abe8300SCraig Topper U = cast<Instruction>(*U->user_begin());
4278abe8300SCraig Topper
4288abe8300SCraig Topper return U == BO;
4298abe8300SCraig Topper }
4308abe8300SCraig Topper
4318abe8300SCraig Topper // Collect all the leaves of the tree of adds that feeds into the horizontal
4328abe8300SCraig Topper // reduction. Root is the Value that is used by the horizontal reduction.
4338abe8300SCraig Topper // We look through single use phis, single use adds, or adds that are used by
4348abe8300SCraig Topper // a phi that forms a loop with the add.
collectLeaves(Value * Root,SmallVectorImpl<Instruction * > & Leaves)4358abe8300SCraig Topper static void collectLeaves(Value *Root, SmallVectorImpl<Instruction *> &Leaves) {
4368abe8300SCraig Topper SmallPtrSet<Value *, 8> Visited;
4378abe8300SCraig Topper SmallVector<Value *, 8> Worklist;
4388abe8300SCraig Topper Worklist.push_back(Root);
4398abe8300SCraig Topper
4408abe8300SCraig Topper while (!Worklist.empty()) {
4418abe8300SCraig Topper Value *V = Worklist.pop_back_val();
4428abe8300SCraig Topper if (!Visited.insert(V).second)
4438abe8300SCraig Topper continue;
4448abe8300SCraig Topper
4458abe8300SCraig Topper if (auto *PN = dyn_cast<PHINode>(V)) {
4468abe8300SCraig Topper // PHI node should have single use unless it is the root node, then it
4478abe8300SCraig Topper // has 2 uses.
4488abe8300SCraig Topper if (!PN->hasNUses(PN == Root ? 2 : 1))
4498abe8300SCraig Topper break;
4508abe8300SCraig Topper
4518abe8300SCraig Topper // Push incoming values to the worklist.
45205444417SKazu Hirata append_range(Worklist, PN->incoming_values());
4538abe8300SCraig Topper
4548abe8300SCraig Topper continue;
4558abe8300SCraig Topper }
4568abe8300SCraig Topper
4578abe8300SCraig Topper if (auto *BO = dyn_cast<BinaryOperator>(V)) {
4588abe8300SCraig Topper if (BO->getOpcode() == Instruction::Add) {
4598abe8300SCraig Topper // Simple case. Single use, just push its operands to the worklist.
4608abe8300SCraig Topper if (BO->hasNUses(BO == Root ? 2 : 1)) {
46105444417SKazu Hirata append_range(Worklist, BO->operands());
4628abe8300SCraig Topper continue;
4638abe8300SCraig Topper }
4648abe8300SCraig Topper
4658abe8300SCraig Topper // If there is additional use, make sure it is an unvisited phi that
4668abe8300SCraig Topper // gets us back to this node.
4678abe8300SCraig Topper if (BO->hasNUses(BO == Root ? 3 : 2)) {
4688abe8300SCraig Topper PHINode *PN = nullptr;
469*18a1085eSHaohai Wen for (auto *U : BO->users())
4708abe8300SCraig Topper if (auto *P = dyn_cast<PHINode>(U))
4718abe8300SCraig Topper if (!Visited.count(P))
4728abe8300SCraig Topper PN = P;
4738abe8300SCraig Topper
4748abe8300SCraig Topper // If we didn't find a 2-input PHI then this isn't a case we can
4758abe8300SCraig Topper // handle.
4768abe8300SCraig Topper if (!PN || PN->getNumIncomingValues() != 2)
4778abe8300SCraig Topper continue;
4788abe8300SCraig Topper
4798abe8300SCraig Topper // Walk forward from this phi to see if it reaches back to this add.
4808abe8300SCraig Topper if (!isReachableFromPHI(PN, BO))
4818abe8300SCraig Topper continue;
4828abe8300SCraig Topper
4838abe8300SCraig Topper // The phi forms a loop with this Add, push its operands.
48405444417SKazu Hirata append_range(Worklist, BO->operands());
4858abe8300SCraig Topper }
4868abe8300SCraig Topper }
4878abe8300SCraig Topper }
4888abe8300SCraig Topper
4898abe8300SCraig Topper // Not an add or phi, make it a leaf.
4908abe8300SCraig Topper if (auto *I = dyn_cast<Instruction>(V)) {
4918abe8300SCraig Topper if (!V->hasNUses(I == Root ? 2 : 1))
4928abe8300SCraig Topper continue;
4938abe8300SCraig Topper
4948abe8300SCraig Topper // Add this as a leaf.
4958abe8300SCraig Topper Leaves.push_back(I);
4968abe8300SCraig Topper }
4978abe8300SCraig Topper }
4989f7d4150SCraig Topper }
4999f7d4150SCraig Topper
runOnFunction(Function & F)5009f7d4150SCraig Topper bool X86PartialReduction::runOnFunction(Function &F) {
5019f7d4150SCraig Topper if (skipFunction(F))
5029f7d4150SCraig Topper return false;
5039f7d4150SCraig Topper
5049f7d4150SCraig Topper auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
5059f7d4150SCraig Topper if (!TPC)
5069f7d4150SCraig Topper return false;
5079f7d4150SCraig Topper
5089f7d4150SCraig Topper auto &TM = TPC->getTM<X86TargetMachine>();
5099f7d4150SCraig Topper ST = TM.getSubtargetImpl(F);
5109f7d4150SCraig Topper
5119f7d4150SCraig Topper DL = &F.getParent()->getDataLayout();
5129f7d4150SCraig Topper
5139f7d4150SCraig Topper bool MadeChange = false;
5149f7d4150SCraig Topper for (auto &BB : F) {
5159f7d4150SCraig Topper for (auto &I : BB) {
5168abe8300SCraig Topper auto *EE = dyn_cast<ExtractElementInst>(&I);
5178abe8300SCraig Topper if (!EE)
5189f7d4150SCraig Topper continue;
5199f7d4150SCraig Topper
52021babe4dSLuo, Yuanke bool ReduceInOneBB;
5218abe8300SCraig Topper // First find a reduction tree.
5228abe8300SCraig Topper // FIXME: Do we need to handle other opcodes than Add?
52321babe4dSLuo, Yuanke Value *Root = matchAddReduction(*EE, ReduceInOneBB);
5248abe8300SCraig Topper if (!Root)
5259f7d4150SCraig Topper continue;
5269f7d4150SCraig Topper
5278abe8300SCraig Topper SmallVector<Instruction *, 8> Leaves;
5288abe8300SCraig Topper collectLeaves(Root, Leaves);
5298abe8300SCraig Topper
5308abe8300SCraig Topper for (Instruction *I : Leaves) {
53121babe4dSLuo, Yuanke if (tryMAddReplacement(I, ReduceInOneBB)) {
5329f7d4150SCraig Topper MadeChange = true;
5339f7d4150SCraig Topper continue;
5349f7d4150SCraig Topper }
5358abe8300SCraig Topper
5368abe8300SCraig Topper // Don't do SAD matching on the root node. SelectionDAG already
5378abe8300SCraig Topper // has support for that and currently generates better code.
5388abe8300SCraig Topper if (I != Root && trySADReplacement(I))
5399f7d4150SCraig Topper MadeChange = true;
5409f7d4150SCraig Topper }
5419f7d4150SCraig Topper }
5429f7d4150SCraig Topper }
5439f7d4150SCraig Topper
5449f7d4150SCraig Topper return MadeChange;
5459f7d4150SCraig Topper }
546