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