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" 22*ca33d74cSWei Xiao #include "llvm/IR/IntrinsicInst.h" 239f7d4150SCraig Topper #include "llvm/IR/IntrinsicsX86.h" 249f7d4150SCraig Topper #include "llvm/IR/Operator.h" 25*ca33d74cSWei 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 429f7d4150SCraig Topper X86PartialReduction() : FunctionPass(ID) { } 439f7d4150SCraig Topper 449f7d4150SCraig Topper bool runOnFunction(Function &Fn) override; 459f7d4150SCraig Topper 469f7d4150SCraig Topper void getAnalysisUsage(AnalysisUsage &AU) const override { 479f7d4150SCraig Topper AU.setPreservesCFG(); 489f7d4150SCraig Topper } 499f7d4150SCraig Topper 509f7d4150SCraig 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 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. 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 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 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 225*ca33d74cSWei Xiao Value *LHS; 226*ca33d74cSWei Xiao if (match(Op, PatternMatch::m_Intrinsic<Intrinsic::abs>())) { 227*ca33d74cSWei Xiao LHS = Op->getOperand(0); 228*ca33d74cSWei 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 234*ca33d74cSWei 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; 239*ca33d74cSWei 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 263*ca33d74cSWei 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 281*ca33d74cSWei 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 346*ca33d74cSWei Xiao Op->replaceAllUsesWith(Ops[0]); 347*ca33d74cSWei 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. 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. 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. 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; 4698abe8300SCraig Topper for (auto *U : Root->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 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