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: 528abe8300SCraig Topper bool tryMAddReplacement(Instruction *Op); 538abe8300SCraig Topper bool trySADReplacement(Instruction *Op); 549f7d4150SCraig Topper }; 559f7d4150SCraig Topper } 569f7d4150SCraig Topper 579f7d4150SCraig Topper FunctionPass *llvm::createX86PartialReductionPass() { 589f7d4150SCraig Topper return new X86PartialReduction(); 599f7d4150SCraig Topper } 609f7d4150SCraig Topper 619f7d4150SCraig Topper char X86PartialReduction::ID = 0; 629f7d4150SCraig Topper 639f7d4150SCraig Topper INITIALIZE_PASS(X86PartialReduction, DEBUG_TYPE, 649f7d4150SCraig Topper "X86 Partial Reduction", false, false) 659f7d4150SCraig Topper 668abe8300SCraig Topper bool X86PartialReduction::tryMAddReplacement(Instruction *Op) { 678abe8300SCraig Topper if (!ST->hasSSE2()) 689f7d4150SCraig Topper return false; 699f7d4150SCraig Topper 708abe8300SCraig Topper // Need at least 8 elements. 710da1e7ebSChristopher Tetreault if (cast<FixedVectorType>(Op->getType())->getNumElements() < 8) 729f7d4150SCraig Topper return false; 739f7d4150SCraig Topper 748abe8300SCraig Topper // Element type should be i32. 758abe8300SCraig Topper if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32)) 769f7d4150SCraig Topper return false; 779f7d4150SCraig Topper 788abe8300SCraig Topper auto *Mul = dyn_cast<BinaryOperator>(Op); 798abe8300SCraig Topper if (!Mul || Mul->getOpcode() != Instruction::Mul) 809f7d4150SCraig Topper return false; 819f7d4150SCraig Topper 828abe8300SCraig Topper Value *LHS = Mul->getOperand(0); 838abe8300SCraig Topper Value *RHS = Mul->getOperand(1); 849f7d4150SCraig Topper 859f7d4150SCraig Topper // LHS and RHS should be only used once or if they are the same then only 869f7d4150SCraig Topper // used twice. Only check this when SSE4.1 is enabled and we have zext/sext 879f7d4150SCraig Topper // instructions, otherwise we use punpck to emulate zero extend in stages. The 889f7d4150SCraig Topper // trunc/ we need to do likely won't introduce new instructions in that case. 899f7d4150SCraig Topper if (ST->hasSSE41()) { 909f7d4150SCraig Topper if (LHS == RHS) { 919f7d4150SCraig Topper if (!isa<Constant>(LHS) && !LHS->hasNUses(2)) 929f7d4150SCraig Topper return false; 939f7d4150SCraig Topper } else { 949f7d4150SCraig Topper if (!isa<Constant>(LHS) && !LHS->hasOneUse()) 959f7d4150SCraig Topper return false; 969f7d4150SCraig Topper if (!isa<Constant>(RHS) && !RHS->hasOneUse()) 979f7d4150SCraig Topper return false; 989f7d4150SCraig Topper } 999f7d4150SCraig Topper } 1009f7d4150SCraig Topper 1012b0b9b11SCraig Topper auto CanShrinkOp = [&](Value *Op) { 1022b0b9b11SCraig Topper auto IsFreeTruncation = [&](Value *Op) { 1039f7d4150SCraig Topper if (auto *Cast = dyn_cast<CastInst>(Op)) { 1048abe8300SCraig Topper if (Cast->getParent() == Mul->getParent() && 1059f7d4150SCraig Topper (Cast->getOpcode() == Instruction::SExt || 1069f7d4150SCraig Topper Cast->getOpcode() == Instruction::ZExt) && 1072b0b9b11SCraig Topper Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 16) 1082b0b9b11SCraig Topper return true; 1092b0b9b11SCraig Topper } 1102b0b9b11SCraig Topper 1112b0b9b11SCraig Topper return isa<Constant>(Op); 1122b0b9b11SCraig Topper }; 1132b0b9b11SCraig Topper 1142b0b9b11SCraig Topper // If the operation can be freely truncated and has enough sign bits we 1152b0b9b11SCraig Topper // can shrink. 1162b0b9b11SCraig Topper if (IsFreeTruncation(Op) && 1178abe8300SCraig Topper ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16) 1182b0b9b11SCraig Topper return true; 1192b0b9b11SCraig Topper 1202b0b9b11SCraig Topper // SelectionDAG has limited support for truncating through an add or sub if 1212b0b9b11SCraig Topper // the inputs are freely truncatable. 1222b0b9b11SCraig Topper if (auto *BO = dyn_cast<BinaryOperator>(Op)) { 1238abe8300SCraig Topper if (BO->getParent() == Mul->getParent() && 1242b0b9b11SCraig Topper IsFreeTruncation(BO->getOperand(0)) && 1252b0b9b11SCraig Topper IsFreeTruncation(BO->getOperand(1)) && 1268abe8300SCraig Topper ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16) 1279f7d4150SCraig Topper return true; 1289f7d4150SCraig Topper } 1299f7d4150SCraig Topper 1309f7d4150SCraig Topper return false; 1319f7d4150SCraig Topper }; 1329f7d4150SCraig Topper 1339f7d4150SCraig Topper // Both Ops need to be shrinkable. 1342b0b9b11SCraig Topper if (!CanShrinkOp(LHS) && !CanShrinkOp(RHS)) 1359f7d4150SCraig Topper return false; 1369f7d4150SCraig Topper 1378abe8300SCraig Topper IRBuilder<> Builder(Mul); 1389f7d4150SCraig Topper 1390da1e7ebSChristopher Tetreault auto *MulTy = cast<FixedVectorType>(Op->getType()); 140dd24fb38SChristopher Tetreault unsigned NumElts = MulTy->getNumElements(); 1419f7d4150SCraig Topper 1429f7d4150SCraig Topper // Extract even elements and odd elements and add them together. This will 1439f7d4150SCraig Topper // be pattern matched by SelectionDAG to pmaddwd. This instruction will be 1449f7d4150SCraig Topper // half the original width. 1456f64dacaSBenjamin Kramer SmallVector<int, 16> EvenMask(NumElts / 2); 1466f64dacaSBenjamin Kramer SmallVector<int, 16> OddMask(NumElts / 2); 1479f7d4150SCraig Topper for (int i = 0, e = NumElts / 2; i != e; ++i) { 1489f7d4150SCraig Topper EvenMask[i] = i * 2; 1499f7d4150SCraig Topper OddMask[i] = i * 2 + 1; 1509f7d4150SCraig Topper } 1518abe8300SCraig Topper // Creating a new mul so the replaceAllUsesWith below doesn't replace the 1528abe8300SCraig Topper // uses in the shuffles we're creating. 1538abe8300SCraig Topper Value *NewMul = Builder.CreateMul(Mul->getOperand(0), Mul->getOperand(1)); 1548abe8300SCraig Topper Value *EvenElts = Builder.CreateShuffleVector(NewMul, NewMul, EvenMask); 1558abe8300SCraig Topper Value *OddElts = Builder.CreateShuffleVector(NewMul, NewMul, OddMask); 1569f7d4150SCraig Topper Value *MAdd = Builder.CreateAdd(EvenElts, OddElts); 1579f7d4150SCraig Topper 1589f7d4150SCraig Topper // Concatenate zeroes to extend back to the original type. 1596f64dacaSBenjamin Kramer SmallVector<int, 32> ConcatMask(NumElts); 1609f7d4150SCraig Topper std::iota(ConcatMask.begin(), ConcatMask.end(), 0); 1619f7d4150SCraig Topper Value *Zero = Constant::getNullValue(MAdd->getType()); 1629f7d4150SCraig Topper Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask); 1639f7d4150SCraig Topper 1648abe8300SCraig Topper Mul->replaceAllUsesWith(Concat); 1658abe8300SCraig Topper Mul->eraseFromParent(); 1669f7d4150SCraig Topper 1679f7d4150SCraig Topper return true; 1689f7d4150SCraig Topper } 1699f7d4150SCraig Topper 1708abe8300SCraig Topper bool X86PartialReduction::trySADReplacement(Instruction *Op) { 1719f7d4150SCraig Topper if (!ST->hasSSE2()) 1729f7d4150SCraig Topper return false; 1739f7d4150SCraig Topper 1748abe8300SCraig Topper // TODO: There's nothing special about i32, any integer type above i16 should 1758abe8300SCraig Topper // work just as well. 1768abe8300SCraig Topper if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32)) 1779f7d4150SCraig Topper return false; 1789f7d4150SCraig Topper 1799f7d4150SCraig Topper // Operand should be a select. 1809f7d4150SCraig Topper auto *SI = dyn_cast<SelectInst>(Op); 1819f7d4150SCraig Topper if (!SI) 1829f7d4150SCraig Topper return false; 1839f7d4150SCraig Topper 1849f7d4150SCraig Topper // Select needs to implement absolute value. 1859f7d4150SCraig Topper Value *LHS, *RHS; 1869f7d4150SCraig Topper auto SPR = matchSelectPattern(SI, LHS, RHS); 1879f7d4150SCraig Topper if (SPR.Flavor != SPF_ABS) 1889f7d4150SCraig Topper return false; 1899f7d4150SCraig Topper 1909f7d4150SCraig Topper // Need a subtract of two values. 1919f7d4150SCraig Topper auto *Sub = dyn_cast<BinaryOperator>(LHS); 1929f7d4150SCraig Topper if (!Sub || Sub->getOpcode() != Instruction::Sub) 1939f7d4150SCraig Topper return false; 1949f7d4150SCraig Topper 1959f7d4150SCraig Topper // Look for zero extend from i8. 1969f7d4150SCraig Topper auto getZeroExtendedVal = [](Value *Op) -> Value * { 1979f7d4150SCraig Topper if (auto *ZExt = dyn_cast<ZExtInst>(Op)) 198dd24fb38SChristopher Tetreault if (cast<VectorType>(ZExt->getOperand(0)->getType()) 199dd24fb38SChristopher Tetreault ->getElementType() 200dd24fb38SChristopher Tetreault ->isIntegerTy(8)) 2019f7d4150SCraig Topper return ZExt->getOperand(0); 2029f7d4150SCraig Topper 2039f7d4150SCraig Topper return nullptr; 2049f7d4150SCraig Topper }; 2059f7d4150SCraig Topper 2069f7d4150SCraig Topper // Both operands of the subtract should be extends from vXi8. 2079f7d4150SCraig Topper Value *Op0 = getZeroExtendedVal(Sub->getOperand(0)); 2089f7d4150SCraig Topper Value *Op1 = getZeroExtendedVal(Sub->getOperand(1)); 2099f7d4150SCraig Topper if (!Op0 || !Op1) 2109f7d4150SCraig Topper return false; 2119f7d4150SCraig Topper 2128abe8300SCraig Topper IRBuilder<> Builder(SI); 2139f7d4150SCraig Topper 2140da1e7ebSChristopher Tetreault auto *OpTy = cast<FixedVectorType>(Op->getType()); 215dd24fb38SChristopher Tetreault unsigned NumElts = OpTy->getNumElements(); 2169f7d4150SCraig Topper 2179f7d4150SCraig Topper unsigned IntrinsicNumElts; 2189f7d4150SCraig Topper Intrinsic::ID IID; 2199f7d4150SCraig Topper if (ST->hasBWI() && NumElts >= 64) { 2209f7d4150SCraig Topper IID = Intrinsic::x86_avx512_psad_bw_512; 2219f7d4150SCraig Topper IntrinsicNumElts = 64; 2229f7d4150SCraig Topper } else if (ST->hasAVX2() && NumElts >= 32) { 2239f7d4150SCraig Topper IID = Intrinsic::x86_avx2_psad_bw; 2249f7d4150SCraig Topper IntrinsicNumElts = 32; 2259f7d4150SCraig Topper } else { 2269f7d4150SCraig Topper IID = Intrinsic::x86_sse2_psad_bw; 2279f7d4150SCraig Topper IntrinsicNumElts = 16; 2289f7d4150SCraig Topper } 2299f7d4150SCraig Topper 2308abe8300SCraig Topper Function *PSADBWFn = Intrinsic::getDeclaration(SI->getModule(), IID); 2319f7d4150SCraig Topper 2329f7d4150SCraig Topper if (NumElts < 16) { 2339f7d4150SCraig Topper // Pad input with zeroes. 2346f64dacaSBenjamin Kramer SmallVector<int, 32> ConcatMask(16); 2359f7d4150SCraig Topper for (unsigned i = 0; i != NumElts; ++i) 2369f7d4150SCraig Topper ConcatMask[i] = i; 2379f7d4150SCraig Topper for (unsigned i = NumElts; i != 16; ++i) 2389f7d4150SCraig Topper ConcatMask[i] = (i % NumElts) + NumElts; 2399f7d4150SCraig Topper 2409f7d4150SCraig Topper Value *Zero = Constant::getNullValue(Op0->getType()); 2419f7d4150SCraig Topper Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask); 2429f7d4150SCraig Topper Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask); 2439f7d4150SCraig Topper NumElts = 16; 2449f7d4150SCraig Topper } 2459f7d4150SCraig Topper 2469f7d4150SCraig Topper // Intrinsics produce vXi64 and need to be casted to vXi32. 2475a99ec10SChristopher Tetreault auto *I32Ty = 2485a99ec10SChristopher Tetreault FixedVectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4); 2499f7d4150SCraig Topper 2509f7d4150SCraig Topper assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!"); 2519f7d4150SCraig Topper unsigned NumSplits = NumElts / IntrinsicNumElts; 2529f7d4150SCraig Topper 2539f7d4150SCraig Topper // First collect the pieces we need. 2549f7d4150SCraig Topper SmallVector<Value *, 4> Ops(NumSplits); 2559f7d4150SCraig Topper for (unsigned i = 0; i != NumSplits; ++i) { 2566f64dacaSBenjamin Kramer SmallVector<int, 64> ExtractMask(IntrinsicNumElts); 2579f7d4150SCraig Topper std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts); 2589f7d4150SCraig Topper Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask); 2599f7d4150SCraig Topper Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask); 2609f7d4150SCraig Topper Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1}); 2619f7d4150SCraig Topper Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty); 2629f7d4150SCraig Topper } 2639f7d4150SCraig Topper 2649f7d4150SCraig Topper assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits"); 2659f7d4150SCraig Topper unsigned Stages = Log2_32(NumSplits); 2669f7d4150SCraig Topper for (unsigned s = Stages; s > 0; --s) { 267dd24fb38SChristopher Tetreault unsigned NumConcatElts = 2680da1e7ebSChristopher Tetreault cast<FixedVectorType>(Ops[0]->getType())->getNumElements() * 2; 269d2dd0facSMichael Liao for (unsigned i = 0; i != 1U << (s - 1); ++i) { 2706f64dacaSBenjamin Kramer SmallVector<int, 64> ConcatMask(NumConcatElts); 2719f7d4150SCraig Topper std::iota(ConcatMask.begin(), ConcatMask.end(), 0); 2729f7d4150SCraig Topper Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask); 2739f7d4150SCraig Topper } 2749f7d4150SCraig Topper } 2759f7d4150SCraig Topper 2769f7d4150SCraig Topper // At this point the final value should be in Ops[0]. Now we need to adjust 2779f7d4150SCraig Topper // it to the final original type. 2780da1e7ebSChristopher Tetreault NumElts = cast<FixedVectorType>(OpTy)->getNumElements(); 2799f7d4150SCraig Topper if (NumElts == 2) { 2809f7d4150SCraig Topper // Extract down to 2 elements. 2811ee6ec2bSEli Friedman Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], ArrayRef<int>{0, 1}); 2829f7d4150SCraig Topper } else if (NumElts >= 8) { 2836f64dacaSBenjamin Kramer SmallVector<int, 32> ConcatMask(NumElts); 2840da1e7ebSChristopher Tetreault unsigned SubElts = 2850da1e7ebSChristopher Tetreault cast<FixedVectorType>(Ops[0]->getType())->getNumElements(); 2869f7d4150SCraig Topper for (unsigned i = 0; i != SubElts; ++i) 2879f7d4150SCraig Topper ConcatMask[i] = i; 2889f7d4150SCraig Topper for (unsigned i = SubElts; i != NumElts; ++i) 2899f7d4150SCraig Topper ConcatMask[i] = (i % SubElts) + SubElts; 2909f7d4150SCraig Topper 2919f7d4150SCraig Topper Value *Zero = Constant::getNullValue(Ops[0]->getType()); 2929f7d4150SCraig Topper Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask); 2939f7d4150SCraig Topper } 2949f7d4150SCraig Topper 2958abe8300SCraig Topper SI->replaceAllUsesWith(Ops[0]); 2968abe8300SCraig Topper SI->eraseFromParent(); 2979f7d4150SCraig Topper 298fa8c2ae7SCraig Topper return true; 2999f7d4150SCraig Topper } 3009f7d4150SCraig Topper 3018abe8300SCraig Topper // Walk backwards from the ExtractElementInst and determine if it is the end of 3028abe8300SCraig Topper // a horizontal reduction. Return the input to the reduction if we find one. 3038abe8300SCraig Topper static Value *matchAddReduction(const ExtractElementInst &EE) { 3048abe8300SCraig Topper // Make sure we're extracting index 0. 3058abe8300SCraig Topper auto *Index = dyn_cast<ConstantInt>(EE.getIndexOperand()); 3068abe8300SCraig Topper if (!Index || !Index->isNullValue()) 3078abe8300SCraig Topper return nullptr; 3088abe8300SCraig Topper 3098abe8300SCraig Topper const auto *BO = dyn_cast<BinaryOperator>(EE.getVectorOperand()); 3108abe8300SCraig Topper if (!BO || BO->getOpcode() != Instruction::Add || !BO->hasOneUse()) 3118abe8300SCraig Topper return nullptr; 3128abe8300SCraig Topper 3130da1e7ebSChristopher Tetreault unsigned NumElems = cast<FixedVectorType>(BO->getType())->getNumElements(); 3148abe8300SCraig Topper // Ensure the reduction size is a power of 2. 3158abe8300SCraig Topper if (!isPowerOf2_32(NumElems)) 3168abe8300SCraig Topper return nullptr; 3178abe8300SCraig Topper 3188abe8300SCraig Topper const Value *Op = BO; 3198abe8300SCraig Topper unsigned Stages = Log2_32(NumElems); 3208abe8300SCraig Topper for (unsigned i = 0; i != Stages; ++i) { 3218abe8300SCraig Topper const auto *BO = dyn_cast<BinaryOperator>(Op); 3228abe8300SCraig Topper if (!BO || BO->getOpcode() != Instruction::Add) 3238abe8300SCraig Topper return nullptr; 3248abe8300SCraig Topper 3258abe8300SCraig Topper // If this isn't the first add, then it should only have 2 users, the 3268abe8300SCraig Topper // shuffle and another add which we checked in the previous iteration. 3278abe8300SCraig Topper if (i != 0 && !BO->hasNUses(2)) 3288abe8300SCraig Topper return nullptr; 3298abe8300SCraig Topper 3308abe8300SCraig Topper Value *LHS = BO->getOperand(0); 3318abe8300SCraig Topper Value *RHS = BO->getOperand(1); 3328abe8300SCraig Topper 3338abe8300SCraig Topper auto *Shuffle = dyn_cast<ShuffleVectorInst>(LHS); 3348abe8300SCraig Topper if (Shuffle) { 3358abe8300SCraig Topper Op = RHS; 3368abe8300SCraig Topper } else { 3378abe8300SCraig Topper Shuffle = dyn_cast<ShuffleVectorInst>(RHS); 3388abe8300SCraig Topper Op = LHS; 3398abe8300SCraig Topper } 3408abe8300SCraig Topper 3418abe8300SCraig Topper // The first operand of the shuffle should be the same as the other operand 3428abe8300SCraig Topper // of the bin op. 3438abe8300SCraig Topper if (!Shuffle || Shuffle->getOperand(0) != Op) 3448abe8300SCraig Topper return nullptr; 3458abe8300SCraig Topper 3468abe8300SCraig Topper // Verify the shuffle has the expected (at this stage of the pyramid) mask. 3478abe8300SCraig Topper unsigned MaskEnd = 1 << i; 3488abe8300SCraig Topper for (unsigned Index = 0; Index < MaskEnd; ++Index) 3498abe8300SCraig Topper if (Shuffle->getMaskValue(Index) != (int)(MaskEnd + Index)) 3508abe8300SCraig Topper return nullptr; 3518abe8300SCraig Topper } 3528abe8300SCraig Topper 3538abe8300SCraig Topper return const_cast<Value *>(Op); 3548abe8300SCraig Topper } 3558abe8300SCraig Topper 3568abe8300SCraig Topper // See if this BO is reachable from this Phi by walking forward through single 3578abe8300SCraig Topper // use BinaryOperators with the same opcode. If we get back then we know we've 3588abe8300SCraig Topper // found a loop and it is safe to step through this Add to find more leaves. 3598abe8300SCraig Topper static bool isReachableFromPHI(PHINode *Phi, BinaryOperator *BO) { 3608abe8300SCraig Topper // The PHI itself should only have one use. 3618abe8300SCraig Topper if (!Phi->hasOneUse()) 3629f7d4150SCraig Topper return false; 3639f7d4150SCraig Topper 3648abe8300SCraig Topper Instruction *U = cast<Instruction>(*Phi->user_begin()); 3658abe8300SCraig Topper if (U == BO) 3668abe8300SCraig Topper return true; 3679f7d4150SCraig Topper 3688abe8300SCraig Topper while (U->hasOneUse() && U->getOpcode() == BO->getOpcode()) 3698abe8300SCraig Topper U = cast<Instruction>(*U->user_begin()); 3708abe8300SCraig Topper 3718abe8300SCraig Topper return U == BO; 3728abe8300SCraig Topper } 3738abe8300SCraig Topper 3748abe8300SCraig Topper // Collect all the leaves of the tree of adds that feeds into the horizontal 3758abe8300SCraig Topper // reduction. Root is the Value that is used by the horizontal reduction. 3768abe8300SCraig Topper // We look through single use phis, single use adds, or adds that are used by 3778abe8300SCraig Topper // a phi that forms a loop with the add. 3788abe8300SCraig Topper static void collectLeaves(Value *Root, SmallVectorImpl<Instruction *> &Leaves) { 3798abe8300SCraig Topper SmallPtrSet<Value *, 8> Visited; 3808abe8300SCraig Topper SmallVector<Value *, 8> Worklist; 3818abe8300SCraig Topper Worklist.push_back(Root); 3828abe8300SCraig Topper 3838abe8300SCraig Topper while (!Worklist.empty()) { 3848abe8300SCraig Topper Value *V = Worklist.pop_back_val(); 3858abe8300SCraig Topper if (!Visited.insert(V).second) 3868abe8300SCraig Topper continue; 3878abe8300SCraig Topper 3888abe8300SCraig Topper if (auto *PN = dyn_cast<PHINode>(V)) { 3898abe8300SCraig Topper // PHI node should have single use unless it is the root node, then it 3908abe8300SCraig Topper // has 2 uses. 3918abe8300SCraig Topper if (!PN->hasNUses(PN == Root ? 2 : 1)) 3928abe8300SCraig Topper break; 3938abe8300SCraig Topper 3948abe8300SCraig Topper // Push incoming values to the worklist. 395*05444417SKazu Hirata append_range(Worklist, PN->incoming_values()); 3968abe8300SCraig Topper 3978abe8300SCraig Topper continue; 3988abe8300SCraig Topper } 3998abe8300SCraig Topper 4008abe8300SCraig Topper if (auto *BO = dyn_cast<BinaryOperator>(V)) { 4018abe8300SCraig Topper if (BO->getOpcode() == Instruction::Add) { 4028abe8300SCraig Topper // Simple case. Single use, just push its operands to the worklist. 4038abe8300SCraig Topper if (BO->hasNUses(BO == Root ? 2 : 1)) { 404*05444417SKazu Hirata append_range(Worklist, BO->operands()); 4058abe8300SCraig Topper continue; 4068abe8300SCraig Topper } 4078abe8300SCraig Topper 4088abe8300SCraig Topper // If there is additional use, make sure it is an unvisited phi that 4098abe8300SCraig Topper // gets us back to this node. 4108abe8300SCraig Topper if (BO->hasNUses(BO == Root ? 3 : 2)) { 4118abe8300SCraig Topper PHINode *PN = nullptr; 4128abe8300SCraig Topper for (auto *U : Root->users()) 4138abe8300SCraig Topper if (auto *P = dyn_cast<PHINode>(U)) 4148abe8300SCraig Topper if (!Visited.count(P)) 4158abe8300SCraig Topper PN = P; 4168abe8300SCraig Topper 4178abe8300SCraig Topper // If we didn't find a 2-input PHI then this isn't a case we can 4188abe8300SCraig Topper // handle. 4198abe8300SCraig Topper if (!PN || PN->getNumIncomingValues() != 2) 4208abe8300SCraig Topper continue; 4218abe8300SCraig Topper 4228abe8300SCraig Topper // Walk forward from this phi to see if it reaches back to this add. 4238abe8300SCraig Topper if (!isReachableFromPHI(PN, BO)) 4248abe8300SCraig Topper continue; 4258abe8300SCraig Topper 4268abe8300SCraig Topper // The phi forms a loop with this Add, push its operands. 427*05444417SKazu Hirata append_range(Worklist, BO->operands()); 4288abe8300SCraig Topper } 4298abe8300SCraig Topper } 4308abe8300SCraig Topper } 4318abe8300SCraig Topper 4328abe8300SCraig Topper // Not an add or phi, make it a leaf. 4338abe8300SCraig Topper if (auto *I = dyn_cast<Instruction>(V)) { 4348abe8300SCraig Topper if (!V->hasNUses(I == Root ? 2 : 1)) 4358abe8300SCraig Topper continue; 4368abe8300SCraig Topper 4378abe8300SCraig Topper // Add this as a leaf. 4388abe8300SCraig Topper Leaves.push_back(I); 4398abe8300SCraig Topper } 4408abe8300SCraig Topper } 4419f7d4150SCraig Topper } 4429f7d4150SCraig Topper 4439f7d4150SCraig Topper bool X86PartialReduction::runOnFunction(Function &F) { 4449f7d4150SCraig Topper if (skipFunction(F)) 4459f7d4150SCraig Topper return false; 4469f7d4150SCraig Topper 4479f7d4150SCraig Topper auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 4489f7d4150SCraig Topper if (!TPC) 4499f7d4150SCraig Topper return false; 4509f7d4150SCraig Topper 4519f7d4150SCraig Topper auto &TM = TPC->getTM<X86TargetMachine>(); 4529f7d4150SCraig Topper ST = TM.getSubtargetImpl(F); 4539f7d4150SCraig Topper 4549f7d4150SCraig Topper DL = &F.getParent()->getDataLayout(); 4559f7d4150SCraig Topper 4569f7d4150SCraig Topper bool MadeChange = false; 4579f7d4150SCraig Topper for (auto &BB : F) { 4589f7d4150SCraig Topper for (auto &I : BB) { 4598abe8300SCraig Topper auto *EE = dyn_cast<ExtractElementInst>(&I); 4608abe8300SCraig Topper if (!EE) 4619f7d4150SCraig Topper continue; 4629f7d4150SCraig Topper 4638abe8300SCraig Topper // First find a reduction tree. 4648abe8300SCraig Topper // FIXME: Do we need to handle other opcodes than Add? 4658abe8300SCraig Topper Value *Root = matchAddReduction(*EE); 4668abe8300SCraig Topper if (!Root) 4679f7d4150SCraig Topper continue; 4689f7d4150SCraig Topper 4698abe8300SCraig Topper SmallVector<Instruction *, 8> Leaves; 4708abe8300SCraig Topper collectLeaves(Root, Leaves); 4718abe8300SCraig Topper 4728abe8300SCraig Topper for (Instruction *I : Leaves) { 4738abe8300SCraig Topper if (tryMAddReplacement(I)) { 4749f7d4150SCraig Topper MadeChange = true; 4759f7d4150SCraig Topper continue; 4769f7d4150SCraig Topper } 4778abe8300SCraig Topper 4788abe8300SCraig Topper // Don't do SAD matching on the root node. SelectionDAG already 4798abe8300SCraig Topper // has support for that and currently generates better code. 4808abe8300SCraig Topper if (I != Root && trySADReplacement(I)) 4819f7d4150SCraig Topper MadeChange = true; 4829f7d4150SCraig Topper } 4839f7d4150SCraig Topper } 4849f7d4150SCraig Topper } 4859f7d4150SCraig Topper 4869f7d4150SCraig Topper return MadeChange; 4879f7d4150SCraig Topper } 488