1*9f7d4150SCraig Topper //===-- X86PartialReduction.cpp -------------------------------------------===// 2*9f7d4150SCraig Topper // 3*9f7d4150SCraig Topper // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*9f7d4150SCraig Topper // See https://llvm.org/LICENSE.txt for license information. 5*9f7d4150SCraig Topper // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*9f7d4150SCraig Topper // 7*9f7d4150SCraig Topper //===----------------------------------------------------------------------===// 8*9f7d4150SCraig Topper // 9*9f7d4150SCraig Topper // This pass looks for add instructions used by a horizontal reduction to see 10*9f7d4150SCraig Topper // if we might be able to use pmaddwd or psadbw. Some cases of this require 11*9f7d4150SCraig Topper // cross basic block knowledge and can't be done in SelectionDAG. 12*9f7d4150SCraig Topper // 13*9f7d4150SCraig Topper //===----------------------------------------------------------------------===// 14*9f7d4150SCraig Topper 15*9f7d4150SCraig Topper #include "X86.h" 16*9f7d4150SCraig Topper #include "llvm/Analysis/ValueTracking.h" 17*9f7d4150SCraig Topper #include "llvm/CodeGen/TargetPassConfig.h" 18*9f7d4150SCraig Topper #include "llvm/IR/Constants.h" 19*9f7d4150SCraig Topper #include "llvm/IR/Instructions.h" 20*9f7d4150SCraig Topper #include "llvm/IR/IntrinsicsX86.h" 21*9f7d4150SCraig Topper #include "llvm/IR/IRBuilder.h" 22*9f7d4150SCraig Topper #include "llvm/IR/Operator.h" 23*9f7d4150SCraig Topper #include "llvm/Pass.h" 24*9f7d4150SCraig Topper #include "X86TargetMachine.h" 25*9f7d4150SCraig Topper 26*9f7d4150SCraig Topper using namespace llvm; 27*9f7d4150SCraig Topper 28*9f7d4150SCraig Topper #define DEBUG_TYPE "x86-partial-reduction" 29*9f7d4150SCraig Topper 30*9f7d4150SCraig Topper namespace { 31*9f7d4150SCraig Topper 32*9f7d4150SCraig Topper class X86PartialReduction : public FunctionPass { 33*9f7d4150SCraig Topper const DataLayout *DL; 34*9f7d4150SCraig Topper const X86Subtarget *ST; 35*9f7d4150SCraig Topper 36*9f7d4150SCraig Topper public: 37*9f7d4150SCraig Topper static char ID; // Pass identification, replacement for typeid. 38*9f7d4150SCraig Topper 39*9f7d4150SCraig Topper X86PartialReduction() : FunctionPass(ID) { } 40*9f7d4150SCraig Topper 41*9f7d4150SCraig Topper bool runOnFunction(Function &Fn) override; 42*9f7d4150SCraig Topper 43*9f7d4150SCraig Topper void getAnalysisUsage(AnalysisUsage &AU) const override { 44*9f7d4150SCraig Topper AU.setPreservesCFG(); 45*9f7d4150SCraig Topper } 46*9f7d4150SCraig Topper 47*9f7d4150SCraig Topper StringRef getPassName() const override { 48*9f7d4150SCraig Topper return "X86 Partial Reduction"; 49*9f7d4150SCraig Topper } 50*9f7d4150SCraig Topper 51*9f7d4150SCraig Topper private: 52*9f7d4150SCraig Topper bool tryMAddPattern(BinaryOperator *BO); 53*9f7d4150SCraig Topper bool tryMAddReplacement(Value *Op, BinaryOperator *Add); 54*9f7d4150SCraig Topper 55*9f7d4150SCraig Topper bool trySADPattern(BinaryOperator *BO); 56*9f7d4150SCraig Topper bool trySADReplacement(Value *Op, BinaryOperator *Add); 57*9f7d4150SCraig Topper }; 58*9f7d4150SCraig Topper } 59*9f7d4150SCraig Topper 60*9f7d4150SCraig Topper FunctionPass *llvm::createX86PartialReductionPass() { 61*9f7d4150SCraig Topper return new X86PartialReduction(); 62*9f7d4150SCraig Topper } 63*9f7d4150SCraig Topper 64*9f7d4150SCraig Topper char X86PartialReduction::ID = 0; 65*9f7d4150SCraig Topper 66*9f7d4150SCraig Topper INITIALIZE_PASS(X86PartialReduction, DEBUG_TYPE, 67*9f7d4150SCraig Topper "X86 Partial Reduction", false, false) 68*9f7d4150SCraig Topper 69*9f7d4150SCraig Topper static bool isVectorReductionOp(const BinaryOperator &BO) { 70*9f7d4150SCraig Topper if (!BO.getType()->isVectorTy()) 71*9f7d4150SCraig Topper return false; 72*9f7d4150SCraig Topper 73*9f7d4150SCraig Topper unsigned Opcode = BO.getOpcode(); 74*9f7d4150SCraig Topper 75*9f7d4150SCraig Topper switch (Opcode) { 76*9f7d4150SCraig Topper case Instruction::Add: 77*9f7d4150SCraig Topper case Instruction::Mul: 78*9f7d4150SCraig Topper case Instruction::And: 79*9f7d4150SCraig Topper case Instruction::Or: 80*9f7d4150SCraig Topper case Instruction::Xor: 81*9f7d4150SCraig Topper break; 82*9f7d4150SCraig Topper case Instruction::FAdd: 83*9f7d4150SCraig Topper case Instruction::FMul: 84*9f7d4150SCraig Topper if (auto *FPOp = dyn_cast<FPMathOperator>(&BO)) 85*9f7d4150SCraig Topper if (FPOp->getFastMathFlags().isFast()) 86*9f7d4150SCraig Topper break; 87*9f7d4150SCraig Topper LLVM_FALLTHROUGH; 88*9f7d4150SCraig Topper default: 89*9f7d4150SCraig Topper return false; 90*9f7d4150SCraig Topper } 91*9f7d4150SCraig Topper 92*9f7d4150SCraig Topper unsigned ElemNum = BO.getType()->getVectorNumElements(); 93*9f7d4150SCraig Topper // Ensure the reduction size is a power of 2. 94*9f7d4150SCraig Topper if (!isPowerOf2_32(ElemNum)) 95*9f7d4150SCraig Topper return false; 96*9f7d4150SCraig Topper 97*9f7d4150SCraig Topper unsigned ElemNumToReduce = ElemNum; 98*9f7d4150SCraig Topper 99*9f7d4150SCraig Topper // Do DFS search on the def-use chain from the given instruction. We only 100*9f7d4150SCraig Topper // allow four kinds of operations during the search until we reach the 101*9f7d4150SCraig Topper // instruction that extracts the first element from the vector: 102*9f7d4150SCraig Topper // 103*9f7d4150SCraig Topper // 1. The reduction operation of the same opcode as the given instruction. 104*9f7d4150SCraig Topper // 105*9f7d4150SCraig Topper // 2. PHI node. 106*9f7d4150SCraig Topper // 107*9f7d4150SCraig Topper // 3. ShuffleVector instruction together with a reduction operation that 108*9f7d4150SCraig Topper // does a partial reduction. 109*9f7d4150SCraig Topper // 110*9f7d4150SCraig Topper // 4. ExtractElement that extracts the first element from the vector, and we 111*9f7d4150SCraig Topper // stop searching the def-use chain here. 112*9f7d4150SCraig Topper // 113*9f7d4150SCraig Topper // 3 & 4 above perform a reduction on all elements of the vector. We push defs 114*9f7d4150SCraig Topper // from 1-3 to the stack to continue the DFS. The given instruction is not 115*9f7d4150SCraig Topper // a reduction operation if we meet any other instructions other than those 116*9f7d4150SCraig Topper // listed above. 117*9f7d4150SCraig Topper 118*9f7d4150SCraig Topper SmallVector<const User *, 16> UsersToVisit{&BO}; 119*9f7d4150SCraig Topper SmallPtrSet<const User *, 16> Visited; 120*9f7d4150SCraig Topper bool ReduxExtracted = false; 121*9f7d4150SCraig Topper 122*9f7d4150SCraig Topper while (!UsersToVisit.empty()) { 123*9f7d4150SCraig Topper auto User = UsersToVisit.back(); 124*9f7d4150SCraig Topper UsersToVisit.pop_back(); 125*9f7d4150SCraig Topper if (!Visited.insert(User).second) 126*9f7d4150SCraig Topper continue; 127*9f7d4150SCraig Topper 128*9f7d4150SCraig Topper for (const auto *U : User->users()) { 129*9f7d4150SCraig Topper auto *Inst = dyn_cast<Instruction>(U); 130*9f7d4150SCraig Topper if (!Inst) 131*9f7d4150SCraig Topper return false; 132*9f7d4150SCraig Topper 133*9f7d4150SCraig Topper if (Inst->getOpcode() == Opcode || isa<PHINode>(U)) { 134*9f7d4150SCraig Topper if (auto *FPOp = dyn_cast<FPMathOperator>(Inst)) 135*9f7d4150SCraig Topper if (!isa<PHINode>(FPOp) && !FPOp->getFastMathFlags().isFast()) 136*9f7d4150SCraig Topper return false; 137*9f7d4150SCraig Topper UsersToVisit.push_back(U); 138*9f7d4150SCraig Topper } else if (auto *ShufInst = dyn_cast<ShuffleVectorInst>(U)) { 139*9f7d4150SCraig Topper // Detect the following pattern: A ShuffleVector instruction together 140*9f7d4150SCraig Topper // with a reduction that do partial reduction on the first and second 141*9f7d4150SCraig Topper // ElemNumToReduce / 2 elements, and store the result in 142*9f7d4150SCraig Topper // ElemNumToReduce / 2 elements in another vector. 143*9f7d4150SCraig Topper 144*9f7d4150SCraig Topper unsigned ResultElements = ShufInst->getType()->getVectorNumElements(); 145*9f7d4150SCraig Topper if (ResultElements < ElemNum) 146*9f7d4150SCraig Topper return false; 147*9f7d4150SCraig Topper 148*9f7d4150SCraig Topper if (ElemNumToReduce == 1) 149*9f7d4150SCraig Topper return false; 150*9f7d4150SCraig Topper if (!isa<UndefValue>(U->getOperand(1))) 151*9f7d4150SCraig Topper return false; 152*9f7d4150SCraig Topper for (unsigned i = 0; i < ElemNumToReduce / 2; ++i) 153*9f7d4150SCraig Topper if (ShufInst->getMaskValue(i) != int(i + ElemNumToReduce / 2)) 154*9f7d4150SCraig Topper return false; 155*9f7d4150SCraig Topper for (unsigned i = ElemNumToReduce / 2; i < ElemNum; ++i) 156*9f7d4150SCraig Topper if (ShufInst->getMaskValue(i) != -1) 157*9f7d4150SCraig Topper return false; 158*9f7d4150SCraig Topper 159*9f7d4150SCraig Topper // There is only one user of this ShuffleVector instruction, which 160*9f7d4150SCraig Topper // must be a reduction operation. 161*9f7d4150SCraig Topper if (!U->hasOneUse()) 162*9f7d4150SCraig Topper return false; 163*9f7d4150SCraig Topper 164*9f7d4150SCraig Topper auto *U2 = dyn_cast<BinaryOperator>(*U->user_begin()); 165*9f7d4150SCraig Topper if (!U2 || U2->getOpcode() != Opcode) 166*9f7d4150SCraig Topper return false; 167*9f7d4150SCraig Topper 168*9f7d4150SCraig Topper // Check operands of the reduction operation. 169*9f7d4150SCraig Topper if ((U2->getOperand(0) == U->getOperand(0) && U2->getOperand(1) == U) || 170*9f7d4150SCraig Topper (U2->getOperand(1) == U->getOperand(0) && U2->getOperand(0) == U)) { 171*9f7d4150SCraig Topper UsersToVisit.push_back(U2); 172*9f7d4150SCraig Topper ElemNumToReduce /= 2; 173*9f7d4150SCraig Topper } else 174*9f7d4150SCraig Topper return false; 175*9f7d4150SCraig Topper } else if (isa<ExtractElementInst>(U)) { 176*9f7d4150SCraig Topper // At this moment we should have reduced all elements in the vector. 177*9f7d4150SCraig Topper if (ElemNumToReduce != 1) 178*9f7d4150SCraig Topper return false; 179*9f7d4150SCraig Topper 180*9f7d4150SCraig Topper auto *Val = dyn_cast<ConstantInt>(U->getOperand(1)); 181*9f7d4150SCraig Topper if (!Val || !Val->isZero()) 182*9f7d4150SCraig Topper return false; 183*9f7d4150SCraig Topper 184*9f7d4150SCraig Topper ReduxExtracted = true; 185*9f7d4150SCraig Topper } else 186*9f7d4150SCraig Topper return false; 187*9f7d4150SCraig Topper } 188*9f7d4150SCraig Topper } 189*9f7d4150SCraig Topper return ReduxExtracted; 190*9f7d4150SCraig Topper } 191*9f7d4150SCraig Topper 192*9f7d4150SCraig Topper bool X86PartialReduction::tryMAddReplacement(Value *Op, BinaryOperator *Add) { 193*9f7d4150SCraig Topper BasicBlock *BB = Add->getParent(); 194*9f7d4150SCraig Topper 195*9f7d4150SCraig Topper auto *BO = dyn_cast<BinaryOperator>(Op); 196*9f7d4150SCraig Topper if (!BO || BO->getOpcode() != Instruction::Mul || !BO->hasOneUse() || 197*9f7d4150SCraig Topper BO->getParent() != BB) 198*9f7d4150SCraig Topper return false; 199*9f7d4150SCraig Topper 200*9f7d4150SCraig Topper Value *LHS = BO->getOperand(0); 201*9f7d4150SCraig Topper Value *RHS = BO->getOperand(1); 202*9f7d4150SCraig Topper 203*9f7d4150SCraig Topper // LHS and RHS should be only used once or if they are the same then only 204*9f7d4150SCraig Topper // used twice. Only check this when SSE4.1 is enabled and we have zext/sext 205*9f7d4150SCraig Topper // instructions, otherwise we use punpck to emulate zero extend in stages. The 206*9f7d4150SCraig Topper // trunc/ we need to do likely won't introduce new instructions in that case. 207*9f7d4150SCraig Topper if (ST->hasSSE41()) { 208*9f7d4150SCraig Topper if (LHS == RHS) { 209*9f7d4150SCraig Topper if (!isa<Constant>(LHS) && !LHS->hasNUses(2)) 210*9f7d4150SCraig Topper return false; 211*9f7d4150SCraig Topper } else { 212*9f7d4150SCraig Topper if (!isa<Constant>(LHS) && !LHS->hasOneUse()) 213*9f7d4150SCraig Topper return false; 214*9f7d4150SCraig Topper if (!isa<Constant>(RHS) && !RHS->hasOneUse()) 215*9f7d4150SCraig Topper return false; 216*9f7d4150SCraig Topper } 217*9f7d4150SCraig Topper } 218*9f7d4150SCraig Topper 219*9f7d4150SCraig Topper auto canShrinkOp = [&](Value *Op) { 220*9f7d4150SCraig Topper if (isa<Constant>(Op) && ComputeNumSignBits(Op, *DL, 0, nullptr, BO) > 16) 221*9f7d4150SCraig Topper return true; 222*9f7d4150SCraig Topper if (auto *Cast = dyn_cast<CastInst>(Op)) { 223*9f7d4150SCraig Topper if (Cast->getParent() == BB && 224*9f7d4150SCraig Topper (Cast->getOpcode() == Instruction::SExt || 225*9f7d4150SCraig Topper Cast->getOpcode() == Instruction::ZExt) && 226*9f7d4150SCraig Topper ComputeNumSignBits(Op, *DL, 0, nullptr, BO) > 16) 227*9f7d4150SCraig Topper return true; 228*9f7d4150SCraig Topper } 229*9f7d4150SCraig Topper 230*9f7d4150SCraig Topper return false; 231*9f7d4150SCraig Topper }; 232*9f7d4150SCraig Topper 233*9f7d4150SCraig Topper // Both Ops need to be shrinkable. 234*9f7d4150SCraig Topper if (!canShrinkOp(LHS) && !canShrinkOp(RHS)) 235*9f7d4150SCraig Topper return false; 236*9f7d4150SCraig Topper 237*9f7d4150SCraig Topper IRBuilder<> Builder(Add); 238*9f7d4150SCraig Topper 239*9f7d4150SCraig Topper Type *MulTy = Op->getType(); 240*9f7d4150SCraig Topper unsigned NumElts = MulTy->getVectorNumElements(); 241*9f7d4150SCraig Topper 242*9f7d4150SCraig Topper // Extract even elements and odd elements and add them together. This will 243*9f7d4150SCraig Topper // be pattern matched by SelectionDAG to pmaddwd. This instruction will be 244*9f7d4150SCraig Topper // half the original width. 245*9f7d4150SCraig Topper SmallVector<uint32_t, 16> EvenMask(NumElts / 2); 246*9f7d4150SCraig Topper SmallVector<uint32_t, 16> OddMask(NumElts / 2); 247*9f7d4150SCraig Topper for (int i = 0, e = NumElts / 2; i != e; ++i) { 248*9f7d4150SCraig Topper EvenMask[i] = i * 2; 249*9f7d4150SCraig Topper OddMask[i] = i * 2 + 1; 250*9f7d4150SCraig Topper } 251*9f7d4150SCraig Topper Value *EvenElts = Builder.CreateShuffleVector(BO, BO, EvenMask); 252*9f7d4150SCraig Topper Value *OddElts = Builder.CreateShuffleVector(BO, BO, OddMask); 253*9f7d4150SCraig Topper Value *MAdd = Builder.CreateAdd(EvenElts, OddElts); 254*9f7d4150SCraig Topper 255*9f7d4150SCraig Topper // Concatenate zeroes to extend back to the original type. 256*9f7d4150SCraig Topper SmallVector<uint32_t, 32> ConcatMask(NumElts); 257*9f7d4150SCraig Topper std::iota(ConcatMask.begin(), ConcatMask.end(), 0); 258*9f7d4150SCraig Topper Value *Zero = Constant::getNullValue(MAdd->getType()); 259*9f7d4150SCraig Topper Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask); 260*9f7d4150SCraig Topper 261*9f7d4150SCraig Topper // Replaces the use of mul in the original Add with the pmaddwd and zeroes. 262*9f7d4150SCraig Topper Add->replaceUsesOfWith(BO, Concat); 263*9f7d4150SCraig Topper Add->setHasNoSignedWrap(false); 264*9f7d4150SCraig Topper Add->setHasNoUnsignedWrap(false); 265*9f7d4150SCraig Topper 266*9f7d4150SCraig Topper return true; 267*9f7d4150SCraig Topper } 268*9f7d4150SCraig Topper 269*9f7d4150SCraig Topper // Try to replace operans of this add with pmaddwd patterns. 270*9f7d4150SCraig Topper bool X86PartialReduction::tryMAddPattern(BinaryOperator *BO) { 271*9f7d4150SCraig Topper if (!ST->hasSSE2()) 272*9f7d4150SCraig Topper return false; 273*9f7d4150SCraig Topper 274*9f7d4150SCraig Topper // Need at least 8 elements. 275*9f7d4150SCraig Topper if (BO->getType()->getVectorNumElements() < 8) 276*9f7d4150SCraig Topper return false; 277*9f7d4150SCraig Topper 278*9f7d4150SCraig Topper // Element type should be i32. 279*9f7d4150SCraig Topper if (!BO->getType()->getVectorElementType()->isIntegerTy(32)) 280*9f7d4150SCraig Topper return false; 281*9f7d4150SCraig Topper 282*9f7d4150SCraig Topper bool Changed = false; 283*9f7d4150SCraig Topper Changed |= tryMAddReplacement(BO->getOperand(0), BO); 284*9f7d4150SCraig Topper Changed |= tryMAddReplacement(BO->getOperand(1), BO); 285*9f7d4150SCraig Topper return Changed; 286*9f7d4150SCraig Topper } 287*9f7d4150SCraig Topper 288*9f7d4150SCraig Topper bool X86PartialReduction::trySADReplacement(Value *Op, BinaryOperator *Add) { 289*9f7d4150SCraig Topper // Operand should be a select. 290*9f7d4150SCraig Topper auto *SI = dyn_cast<SelectInst>(Op); 291*9f7d4150SCraig Topper if (!SI) 292*9f7d4150SCraig Topper return false; 293*9f7d4150SCraig Topper 294*9f7d4150SCraig Topper // Select needs to implement absolute value. 295*9f7d4150SCraig Topper Value *LHS, *RHS; 296*9f7d4150SCraig Topper auto SPR = matchSelectPattern(SI, LHS, RHS); 297*9f7d4150SCraig Topper if (SPR.Flavor != SPF_ABS) 298*9f7d4150SCraig Topper return false; 299*9f7d4150SCraig Topper 300*9f7d4150SCraig Topper // Need a subtract of two values. 301*9f7d4150SCraig Topper auto *Sub = dyn_cast<BinaryOperator>(LHS); 302*9f7d4150SCraig Topper if (!Sub || Sub->getOpcode() != Instruction::Sub) 303*9f7d4150SCraig Topper return false; 304*9f7d4150SCraig Topper 305*9f7d4150SCraig Topper // Look for zero extend from i8. 306*9f7d4150SCraig Topper auto getZeroExtendedVal = [](Value *Op) -> Value * { 307*9f7d4150SCraig Topper if (auto *ZExt = dyn_cast<ZExtInst>(Op)) 308*9f7d4150SCraig Topper if (ZExt->getOperand(0)->getType()->getVectorElementType()->isIntegerTy(8)) 309*9f7d4150SCraig Topper return ZExt->getOperand(0); 310*9f7d4150SCraig Topper 311*9f7d4150SCraig Topper return nullptr; 312*9f7d4150SCraig Topper }; 313*9f7d4150SCraig Topper 314*9f7d4150SCraig Topper // Both operands of the subtract should be extends from vXi8. 315*9f7d4150SCraig Topper Value *Op0 = getZeroExtendedVal(Sub->getOperand(0)); 316*9f7d4150SCraig Topper Value *Op1 = getZeroExtendedVal(Sub->getOperand(1)); 317*9f7d4150SCraig Topper if (!Op0 || !Op1) 318*9f7d4150SCraig Topper return false; 319*9f7d4150SCraig Topper 320*9f7d4150SCraig Topper IRBuilder<> Builder(Add); 321*9f7d4150SCraig Topper 322*9f7d4150SCraig Topper Type *OpTy = Op->getType(); 323*9f7d4150SCraig Topper unsigned NumElts = OpTy->getVectorNumElements(); 324*9f7d4150SCraig Topper 325*9f7d4150SCraig Topper unsigned IntrinsicNumElts; 326*9f7d4150SCraig Topper Intrinsic::ID IID; 327*9f7d4150SCraig Topper if (ST->hasBWI() && NumElts >= 64) { 328*9f7d4150SCraig Topper IID = Intrinsic::x86_avx512_psad_bw_512; 329*9f7d4150SCraig Topper IntrinsicNumElts = 64; 330*9f7d4150SCraig Topper } else if (ST->hasAVX2() && NumElts >= 32) { 331*9f7d4150SCraig Topper IID = Intrinsic::x86_avx2_psad_bw; 332*9f7d4150SCraig Topper IntrinsicNumElts = 32; 333*9f7d4150SCraig Topper } else { 334*9f7d4150SCraig Topper IID = Intrinsic::x86_sse2_psad_bw; 335*9f7d4150SCraig Topper IntrinsicNumElts = 16; 336*9f7d4150SCraig Topper } 337*9f7d4150SCraig Topper 338*9f7d4150SCraig Topper Function *PSADBWFn = Intrinsic::getDeclaration(Add->getModule(), IID); 339*9f7d4150SCraig Topper 340*9f7d4150SCraig Topper if (NumElts < 16) { 341*9f7d4150SCraig Topper // Pad input with zeroes. 342*9f7d4150SCraig Topper SmallVector<uint32_t, 32> ConcatMask(16); 343*9f7d4150SCraig Topper for (unsigned i = 0; i != NumElts; ++i) 344*9f7d4150SCraig Topper ConcatMask[i] = i; 345*9f7d4150SCraig Topper for (unsigned i = NumElts; i != 16; ++i) 346*9f7d4150SCraig Topper ConcatMask[i] = (i % NumElts) + NumElts; 347*9f7d4150SCraig Topper 348*9f7d4150SCraig Topper Value *Zero = Constant::getNullValue(Op0->getType()); 349*9f7d4150SCraig Topper Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask); 350*9f7d4150SCraig Topper Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask); 351*9f7d4150SCraig Topper NumElts = 16; 352*9f7d4150SCraig Topper } 353*9f7d4150SCraig Topper 354*9f7d4150SCraig Topper // Intrinsics produce vXi64 and need to be casted to vXi32. 355*9f7d4150SCraig Topper Type *I32Ty = VectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4); 356*9f7d4150SCraig Topper 357*9f7d4150SCraig Topper assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!"); 358*9f7d4150SCraig Topper unsigned NumSplits = NumElts / IntrinsicNumElts; 359*9f7d4150SCraig Topper 360*9f7d4150SCraig Topper // First collect the pieces we need. 361*9f7d4150SCraig Topper SmallVector<Value *, 4> Ops(NumSplits); 362*9f7d4150SCraig Topper for (unsigned i = 0; i != NumSplits; ++i) { 363*9f7d4150SCraig Topper SmallVector<uint32_t, 64> ExtractMask(IntrinsicNumElts); 364*9f7d4150SCraig Topper std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts); 365*9f7d4150SCraig Topper Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask); 366*9f7d4150SCraig Topper Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask); 367*9f7d4150SCraig Topper Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1}); 368*9f7d4150SCraig Topper Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty); 369*9f7d4150SCraig Topper } 370*9f7d4150SCraig Topper 371*9f7d4150SCraig Topper assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits"); 372*9f7d4150SCraig Topper unsigned Stages = Log2_32(NumSplits); 373*9f7d4150SCraig Topper for (unsigned s = Stages; s > 0; --s) { 374*9f7d4150SCraig Topper unsigned NumConcatElts = Ops[0]->getType()->getVectorNumElements() * 2; 375*9f7d4150SCraig Topper for (unsigned i = 0; i != 1 << (s - 1); ++i) { 376*9f7d4150SCraig Topper SmallVector<uint32_t, 64> ConcatMask(NumConcatElts); 377*9f7d4150SCraig Topper std::iota(ConcatMask.begin(), ConcatMask.end(), 0); 378*9f7d4150SCraig Topper Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask); 379*9f7d4150SCraig Topper } 380*9f7d4150SCraig Topper } 381*9f7d4150SCraig Topper 382*9f7d4150SCraig Topper // At this point the final value should be in Ops[0]. Now we need to adjust 383*9f7d4150SCraig Topper // it to the final original type. 384*9f7d4150SCraig Topper NumElts = OpTy->getVectorNumElements(); 385*9f7d4150SCraig Topper if (NumElts == 2) { 386*9f7d4150SCraig Topper // Extract down to 2 elements. 387*9f7d4150SCraig Topper Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], {0, 1}); 388*9f7d4150SCraig Topper } else if (NumElts >= 8) { 389*9f7d4150SCraig Topper SmallVector<uint32_t, 32> ConcatMask(NumElts); 390*9f7d4150SCraig Topper unsigned SubElts = Ops[0]->getType()->getVectorNumElements(); 391*9f7d4150SCraig Topper for (unsigned i = 0; i != SubElts; ++i) 392*9f7d4150SCraig Topper ConcatMask[i] = i; 393*9f7d4150SCraig Topper for (unsigned i = SubElts; i != NumElts; ++i) 394*9f7d4150SCraig Topper ConcatMask[i] = (i % SubElts) + SubElts; 395*9f7d4150SCraig Topper 396*9f7d4150SCraig Topper Value *Zero = Constant::getNullValue(Ops[0]->getType()); 397*9f7d4150SCraig Topper Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask); 398*9f7d4150SCraig Topper } 399*9f7d4150SCraig Topper 400*9f7d4150SCraig Topper // Replaces the uses of Op in Add with the new sequence. 401*9f7d4150SCraig Topper Add->replaceUsesOfWith(Op, Ops[0]); 402*9f7d4150SCraig Topper Add->setHasNoSignedWrap(false); 403*9f7d4150SCraig Topper Add->setHasNoUnsignedWrap(false); 404*9f7d4150SCraig Topper 405*9f7d4150SCraig Topper return false; 406*9f7d4150SCraig Topper } 407*9f7d4150SCraig Topper 408*9f7d4150SCraig Topper bool X86PartialReduction::trySADPattern(BinaryOperator *BO) { 409*9f7d4150SCraig Topper if (!ST->hasSSE2()) 410*9f7d4150SCraig Topper return false; 411*9f7d4150SCraig Topper 412*9f7d4150SCraig Topper // TODO: There's nothing special about i32, any integer type above i16 should 413*9f7d4150SCraig Topper // work just as well. 414*9f7d4150SCraig Topper if (!BO->getType()->getVectorElementType()->isIntegerTy(32)) 415*9f7d4150SCraig Topper return false; 416*9f7d4150SCraig Topper 417*9f7d4150SCraig Topper bool Changed = false; 418*9f7d4150SCraig Topper Changed |= trySADReplacement(BO->getOperand(0), BO); 419*9f7d4150SCraig Topper Changed |= trySADReplacement(BO->getOperand(1), BO); 420*9f7d4150SCraig Topper return Changed; 421*9f7d4150SCraig Topper } 422*9f7d4150SCraig Topper 423*9f7d4150SCraig Topper bool X86PartialReduction::runOnFunction(Function &F) { 424*9f7d4150SCraig Topper if (skipFunction(F)) 425*9f7d4150SCraig Topper return false; 426*9f7d4150SCraig Topper 427*9f7d4150SCraig Topper auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 428*9f7d4150SCraig Topper if (!TPC) 429*9f7d4150SCraig Topper return false; 430*9f7d4150SCraig Topper 431*9f7d4150SCraig Topper auto &TM = TPC->getTM<X86TargetMachine>(); 432*9f7d4150SCraig Topper ST = TM.getSubtargetImpl(F); 433*9f7d4150SCraig Topper 434*9f7d4150SCraig Topper DL = &F.getParent()->getDataLayout(); 435*9f7d4150SCraig Topper 436*9f7d4150SCraig Topper bool MadeChange = false; 437*9f7d4150SCraig Topper for (auto &BB : F) { 438*9f7d4150SCraig Topper for (auto &I : BB) { 439*9f7d4150SCraig Topper auto *BO = dyn_cast<BinaryOperator>(&I); 440*9f7d4150SCraig Topper if (!BO) 441*9f7d4150SCraig Topper continue; 442*9f7d4150SCraig Topper 443*9f7d4150SCraig Topper if (!isVectorReductionOp(*BO)) 444*9f7d4150SCraig Topper continue; 445*9f7d4150SCraig Topper 446*9f7d4150SCraig Topper if (BO->getOpcode() == Instruction::Add) { 447*9f7d4150SCraig Topper if (tryMAddPattern(BO)) { 448*9f7d4150SCraig Topper MadeChange = true; 449*9f7d4150SCraig Topper continue; 450*9f7d4150SCraig Topper } 451*9f7d4150SCraig Topper if (trySADPattern(BO)) { 452*9f7d4150SCraig Topper MadeChange = true; 453*9f7d4150SCraig Topper continue; 454*9f7d4150SCraig Topper } 455*9f7d4150SCraig Topper } 456*9f7d4150SCraig Topper } 457*9f7d4150SCraig Topper } 458*9f7d4150SCraig Topper 459*9f7d4150SCraig Topper return MadeChange; 460*9f7d4150SCraig Topper } 461