1*4ba319b5SDimitry Andric //===- LoopVectorizationPlanner.h - Planner for LoopVectorization ---------===// 2*4ba319b5SDimitry Andric // 3*4ba319b5SDimitry Andric // The LLVM Compiler Infrastructure 4*4ba319b5SDimitry Andric // 5*4ba319b5SDimitry Andric // This file is distributed under the University of Illinois Open Source 6*4ba319b5SDimitry Andric // License. See LICENSE.TXT for details. 7*4ba319b5SDimitry Andric // 8*4ba319b5SDimitry Andric //===----------------------------------------------------------------------===// 9*4ba319b5SDimitry Andric /// 10*4ba319b5SDimitry Andric /// \file 11*4ba319b5SDimitry Andric /// This file provides a LoopVectorizationPlanner class. 12*4ba319b5SDimitry Andric /// InnerLoopVectorizer vectorizes loops which contain only one basic 13*4ba319b5SDimitry Andric /// LoopVectorizationPlanner - drives the vectorization process after having 14*4ba319b5SDimitry Andric /// passed Legality checks. 15*4ba319b5SDimitry Andric /// The planner builds and optimizes the Vectorization Plans which record the 16*4ba319b5SDimitry Andric /// decisions how to vectorize the given loop. In particular, represent the 17*4ba319b5SDimitry Andric /// control-flow of the vectorized version, the replication of instructions that 18*4ba319b5SDimitry Andric /// are to be scalarized, and interleave access groups. 19*4ba319b5SDimitry Andric /// 20*4ba319b5SDimitry Andric /// Also provides a VPlan-based builder utility analogous to IRBuilder. 21*4ba319b5SDimitry Andric /// It provides an instruction-level API for generating VPInstructions while 22*4ba319b5SDimitry Andric /// abstracting away the Recipe manipulation details. 23*4ba319b5SDimitry Andric //===----------------------------------------------------------------------===// 24*4ba319b5SDimitry Andric 25*4ba319b5SDimitry Andric #ifndef LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZATIONPLANNER_H 26*4ba319b5SDimitry Andric #define LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZATIONPLANNER_H 27*4ba319b5SDimitry Andric 28*4ba319b5SDimitry Andric #include "VPlan.h" 29*4ba319b5SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 30*4ba319b5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 31*4ba319b5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 32*4ba319b5SDimitry Andric 33*4ba319b5SDimitry Andric namespace llvm { 34*4ba319b5SDimitry Andric 35*4ba319b5SDimitry Andric /// VPlan-based builder utility analogous to IRBuilder. 36*4ba319b5SDimitry Andric class VPBuilder { 37*4ba319b5SDimitry Andric private: 38*4ba319b5SDimitry Andric VPBasicBlock *BB = nullptr; 39*4ba319b5SDimitry Andric VPBasicBlock::iterator InsertPt = VPBasicBlock::iterator(); 40*4ba319b5SDimitry Andric createInstruction(unsigned Opcode,ArrayRef<VPValue * > Operands)41*4ba319b5SDimitry Andric VPInstruction *createInstruction(unsigned Opcode, 42*4ba319b5SDimitry Andric ArrayRef<VPValue *> Operands) { 43*4ba319b5SDimitry Andric VPInstruction *Instr = new VPInstruction(Opcode, Operands); 44*4ba319b5SDimitry Andric if (BB) 45*4ba319b5SDimitry Andric BB->insert(Instr, InsertPt); 46*4ba319b5SDimitry Andric return Instr; 47*4ba319b5SDimitry Andric } 48*4ba319b5SDimitry Andric createInstruction(unsigned Opcode,std::initializer_list<VPValue * > Operands)49*4ba319b5SDimitry Andric VPInstruction *createInstruction(unsigned Opcode, 50*4ba319b5SDimitry Andric std::initializer_list<VPValue *> Operands) { 51*4ba319b5SDimitry Andric return createInstruction(Opcode, ArrayRef<VPValue *>(Operands)); 52*4ba319b5SDimitry Andric } 53*4ba319b5SDimitry Andric 54*4ba319b5SDimitry Andric public: VPBuilder()55*4ba319b5SDimitry Andric VPBuilder() {} 56*4ba319b5SDimitry Andric 57*4ba319b5SDimitry Andric /// Clear the insertion point: created instructions will not be inserted into 58*4ba319b5SDimitry Andric /// a block. clearInsertionPoint()59*4ba319b5SDimitry Andric void clearInsertionPoint() { 60*4ba319b5SDimitry Andric BB = nullptr; 61*4ba319b5SDimitry Andric InsertPt = VPBasicBlock::iterator(); 62*4ba319b5SDimitry Andric } 63*4ba319b5SDimitry Andric getInsertBlock()64*4ba319b5SDimitry Andric VPBasicBlock *getInsertBlock() const { return BB; } getInsertPoint()65*4ba319b5SDimitry Andric VPBasicBlock::iterator getInsertPoint() const { return InsertPt; } 66*4ba319b5SDimitry Andric 67*4ba319b5SDimitry Andric /// InsertPoint - A saved insertion point. 68*4ba319b5SDimitry Andric class VPInsertPoint { 69*4ba319b5SDimitry Andric VPBasicBlock *Block = nullptr; 70*4ba319b5SDimitry Andric VPBasicBlock::iterator Point; 71*4ba319b5SDimitry Andric 72*4ba319b5SDimitry Andric public: 73*4ba319b5SDimitry Andric /// Creates a new insertion point which doesn't point to anything. 74*4ba319b5SDimitry Andric VPInsertPoint() = default; 75*4ba319b5SDimitry Andric 76*4ba319b5SDimitry Andric /// Creates a new insertion point at the given location. VPInsertPoint(VPBasicBlock * InsertBlock,VPBasicBlock::iterator InsertPoint)77*4ba319b5SDimitry Andric VPInsertPoint(VPBasicBlock *InsertBlock, VPBasicBlock::iterator InsertPoint) 78*4ba319b5SDimitry Andric : Block(InsertBlock), Point(InsertPoint) {} 79*4ba319b5SDimitry Andric 80*4ba319b5SDimitry Andric /// Returns true if this insert point is set. isSet()81*4ba319b5SDimitry Andric bool isSet() const { return Block != nullptr; } 82*4ba319b5SDimitry Andric getBlock()83*4ba319b5SDimitry Andric VPBasicBlock *getBlock() const { return Block; } getPoint()84*4ba319b5SDimitry Andric VPBasicBlock::iterator getPoint() const { return Point; } 85*4ba319b5SDimitry Andric }; 86*4ba319b5SDimitry Andric 87*4ba319b5SDimitry Andric /// Sets the current insert point to a previously-saved location. restoreIP(VPInsertPoint IP)88*4ba319b5SDimitry Andric void restoreIP(VPInsertPoint IP) { 89*4ba319b5SDimitry Andric if (IP.isSet()) 90*4ba319b5SDimitry Andric setInsertPoint(IP.getBlock(), IP.getPoint()); 91*4ba319b5SDimitry Andric else 92*4ba319b5SDimitry Andric clearInsertionPoint(); 93*4ba319b5SDimitry Andric } 94*4ba319b5SDimitry Andric 95*4ba319b5SDimitry Andric /// This specifies that created VPInstructions should be appended to the end 96*4ba319b5SDimitry Andric /// of the specified block. setInsertPoint(VPBasicBlock * TheBB)97*4ba319b5SDimitry Andric void setInsertPoint(VPBasicBlock *TheBB) { 98*4ba319b5SDimitry Andric assert(TheBB && "Attempting to set a null insert point"); 99*4ba319b5SDimitry Andric BB = TheBB; 100*4ba319b5SDimitry Andric InsertPt = BB->end(); 101*4ba319b5SDimitry Andric } 102*4ba319b5SDimitry Andric 103*4ba319b5SDimitry Andric /// This specifies that created instructions should be inserted at the 104*4ba319b5SDimitry Andric /// specified point. setInsertPoint(VPBasicBlock * TheBB,VPBasicBlock::iterator IP)105*4ba319b5SDimitry Andric void setInsertPoint(VPBasicBlock *TheBB, VPBasicBlock::iterator IP) { 106*4ba319b5SDimitry Andric BB = TheBB; 107*4ba319b5SDimitry Andric InsertPt = IP; 108*4ba319b5SDimitry Andric } 109*4ba319b5SDimitry Andric 110*4ba319b5SDimitry Andric /// Insert and return the specified instruction. insert(VPInstruction * I)111*4ba319b5SDimitry Andric VPInstruction *insert(VPInstruction *I) const { 112*4ba319b5SDimitry Andric BB->insert(I, InsertPt); 113*4ba319b5SDimitry Andric return I; 114*4ba319b5SDimitry Andric } 115*4ba319b5SDimitry Andric 116*4ba319b5SDimitry Andric /// Create an N-ary operation with \p Opcode, \p Operands and set \p Inst as 117*4ba319b5SDimitry Andric /// its underlying Instruction. 118*4ba319b5SDimitry Andric VPValue *createNaryOp(unsigned Opcode, ArrayRef<VPValue *> Operands, 119*4ba319b5SDimitry Andric Instruction *Inst = nullptr) { 120*4ba319b5SDimitry Andric VPInstruction *NewVPInst = createInstruction(Opcode, Operands); 121*4ba319b5SDimitry Andric NewVPInst->setUnderlyingValue(Inst); 122*4ba319b5SDimitry Andric return NewVPInst; 123*4ba319b5SDimitry Andric } 124*4ba319b5SDimitry Andric VPValue *createNaryOp(unsigned Opcode, 125*4ba319b5SDimitry Andric std::initializer_list<VPValue *> Operands, 126*4ba319b5SDimitry Andric Instruction *Inst = nullptr) { 127*4ba319b5SDimitry Andric return createNaryOp(Opcode, ArrayRef<VPValue *>(Operands), Inst); 128*4ba319b5SDimitry Andric } 129*4ba319b5SDimitry Andric createNot(VPValue * Operand)130*4ba319b5SDimitry Andric VPValue *createNot(VPValue *Operand) { 131*4ba319b5SDimitry Andric return createInstruction(VPInstruction::Not, {Operand}); 132*4ba319b5SDimitry Andric } 133*4ba319b5SDimitry Andric createAnd(VPValue * LHS,VPValue * RHS)134*4ba319b5SDimitry Andric VPValue *createAnd(VPValue *LHS, VPValue *RHS) { 135*4ba319b5SDimitry Andric return createInstruction(Instruction::BinaryOps::And, {LHS, RHS}); 136*4ba319b5SDimitry Andric } 137*4ba319b5SDimitry Andric createOr(VPValue * LHS,VPValue * RHS)138*4ba319b5SDimitry Andric VPValue *createOr(VPValue *LHS, VPValue *RHS) { 139*4ba319b5SDimitry Andric return createInstruction(Instruction::BinaryOps::Or, {LHS, RHS}); 140*4ba319b5SDimitry Andric } 141*4ba319b5SDimitry Andric 142*4ba319b5SDimitry Andric //===--------------------------------------------------------------------===// 143*4ba319b5SDimitry Andric // RAII helpers. 144*4ba319b5SDimitry Andric //===--------------------------------------------------------------------===// 145*4ba319b5SDimitry Andric 146*4ba319b5SDimitry Andric /// RAII object that stores the current insertion point and restores it when 147*4ba319b5SDimitry Andric /// the object is destroyed. 148*4ba319b5SDimitry Andric class InsertPointGuard { 149*4ba319b5SDimitry Andric VPBuilder &Builder; 150*4ba319b5SDimitry Andric VPBasicBlock *Block; 151*4ba319b5SDimitry Andric VPBasicBlock::iterator Point; 152*4ba319b5SDimitry Andric 153*4ba319b5SDimitry Andric public: InsertPointGuard(VPBuilder & B)154*4ba319b5SDimitry Andric InsertPointGuard(VPBuilder &B) 155*4ba319b5SDimitry Andric : Builder(B), Block(B.getInsertBlock()), Point(B.getInsertPoint()) {} 156*4ba319b5SDimitry Andric 157*4ba319b5SDimitry Andric InsertPointGuard(const InsertPointGuard &) = delete; 158*4ba319b5SDimitry Andric InsertPointGuard &operator=(const InsertPointGuard &) = delete; 159*4ba319b5SDimitry Andric ~InsertPointGuard()160*4ba319b5SDimitry Andric ~InsertPointGuard() { Builder.restoreIP(VPInsertPoint(Block, Point)); } 161*4ba319b5SDimitry Andric }; 162*4ba319b5SDimitry Andric }; 163*4ba319b5SDimitry Andric 164*4ba319b5SDimitry Andric /// TODO: The following VectorizationFactor was pulled out of 165*4ba319b5SDimitry Andric /// LoopVectorizationCostModel class. LV also deals with 166*4ba319b5SDimitry Andric /// VectorizerParams::VectorizationFactor and VectorizationCostTy. 167*4ba319b5SDimitry Andric /// We need to streamline them. 168*4ba319b5SDimitry Andric 169*4ba319b5SDimitry Andric /// Information about vectorization costs 170*4ba319b5SDimitry Andric struct VectorizationFactor { 171*4ba319b5SDimitry Andric // Vector width with best cost 172*4ba319b5SDimitry Andric unsigned Width; 173*4ba319b5SDimitry Andric // Cost of the loop with that width 174*4ba319b5SDimitry Andric unsigned Cost; 175*4ba319b5SDimitry Andric }; 176*4ba319b5SDimitry Andric 177*4ba319b5SDimitry Andric /// Planner drives the vectorization process after having passed 178*4ba319b5SDimitry Andric /// Legality checks. 179*4ba319b5SDimitry Andric class LoopVectorizationPlanner { 180*4ba319b5SDimitry Andric /// The loop that we evaluate. 181*4ba319b5SDimitry Andric Loop *OrigLoop; 182*4ba319b5SDimitry Andric 183*4ba319b5SDimitry Andric /// Loop Info analysis. 184*4ba319b5SDimitry Andric LoopInfo *LI; 185*4ba319b5SDimitry Andric 186*4ba319b5SDimitry Andric /// Target Library Info. 187*4ba319b5SDimitry Andric const TargetLibraryInfo *TLI; 188*4ba319b5SDimitry Andric 189*4ba319b5SDimitry Andric /// Target Transform Info. 190*4ba319b5SDimitry Andric const TargetTransformInfo *TTI; 191*4ba319b5SDimitry Andric 192*4ba319b5SDimitry Andric /// The legality analysis. 193*4ba319b5SDimitry Andric LoopVectorizationLegality *Legal; 194*4ba319b5SDimitry Andric 195*4ba319b5SDimitry Andric /// The profitablity analysis. 196*4ba319b5SDimitry Andric LoopVectorizationCostModel &CM; 197*4ba319b5SDimitry Andric 198*4ba319b5SDimitry Andric using VPlanPtr = std::unique_ptr<VPlan>; 199*4ba319b5SDimitry Andric 200*4ba319b5SDimitry Andric SmallVector<VPlanPtr, 4> VPlans; 201*4ba319b5SDimitry Andric 202*4ba319b5SDimitry Andric /// This class is used to enable the VPlan to invoke a method of ILV. This is 203*4ba319b5SDimitry Andric /// needed until the method is refactored out of ILV and becomes reusable. 204*4ba319b5SDimitry Andric struct VPCallbackILV : public VPCallback { 205*4ba319b5SDimitry Andric InnerLoopVectorizer &ILV; 206*4ba319b5SDimitry Andric VPCallbackILVVPCallbackILV207*4ba319b5SDimitry Andric VPCallbackILV(InnerLoopVectorizer &ILV) : ILV(ILV) {} 208*4ba319b5SDimitry Andric 209*4ba319b5SDimitry Andric Value *getOrCreateVectorValues(Value *V, unsigned Part) override; 210*4ba319b5SDimitry Andric }; 211*4ba319b5SDimitry Andric 212*4ba319b5SDimitry Andric /// A builder used to construct the current plan. 213*4ba319b5SDimitry Andric VPBuilder Builder; 214*4ba319b5SDimitry Andric 215*4ba319b5SDimitry Andric unsigned BestVF = 0; 216*4ba319b5SDimitry Andric unsigned BestUF = 0; 217*4ba319b5SDimitry Andric 218*4ba319b5SDimitry Andric public: LoopVectorizationPlanner(Loop * L,LoopInfo * LI,const TargetLibraryInfo * TLI,const TargetTransformInfo * TTI,LoopVectorizationLegality * Legal,LoopVectorizationCostModel & CM)219*4ba319b5SDimitry Andric LoopVectorizationPlanner(Loop *L, LoopInfo *LI, const TargetLibraryInfo *TLI, 220*4ba319b5SDimitry Andric const TargetTransformInfo *TTI, 221*4ba319b5SDimitry Andric LoopVectorizationLegality *Legal, 222*4ba319b5SDimitry Andric LoopVectorizationCostModel &CM) 223*4ba319b5SDimitry Andric : OrigLoop(L), LI(LI), TLI(TLI), TTI(TTI), Legal(Legal), CM(CM) {} 224*4ba319b5SDimitry Andric 225*4ba319b5SDimitry Andric /// Plan how to best vectorize, return the best VF and its cost. 226*4ba319b5SDimitry Andric VectorizationFactor plan(bool OptForSize, unsigned UserVF); 227*4ba319b5SDimitry Andric 228*4ba319b5SDimitry Andric /// Use the VPlan-native path to plan how to best vectorize, return the best 229*4ba319b5SDimitry Andric /// VF and its cost. 230*4ba319b5SDimitry Andric VectorizationFactor planInVPlanNativePath(bool OptForSize, unsigned UserVF); 231*4ba319b5SDimitry Andric 232*4ba319b5SDimitry Andric /// Finalize the best decision and dispose of all other VPlans. 233*4ba319b5SDimitry Andric void setBestPlan(unsigned VF, unsigned UF); 234*4ba319b5SDimitry Andric 235*4ba319b5SDimitry Andric /// Generate the IR code for the body of the vectorized loop according to the 236*4ba319b5SDimitry Andric /// best selected VPlan. 237*4ba319b5SDimitry Andric void executePlan(InnerLoopVectorizer &LB, DominatorTree *DT); 238*4ba319b5SDimitry Andric printPlans(raw_ostream & O)239*4ba319b5SDimitry Andric void printPlans(raw_ostream &O) { 240*4ba319b5SDimitry Andric for (const auto &Plan : VPlans) 241*4ba319b5SDimitry Andric O << *Plan; 242*4ba319b5SDimitry Andric } 243*4ba319b5SDimitry Andric 244*4ba319b5SDimitry Andric /// Test a \p Predicate on a \p Range of VF's. Return the value of applying 245*4ba319b5SDimitry Andric /// \p Predicate on Range.Start, possibly decreasing Range.End such that the 246*4ba319b5SDimitry Andric /// returned value holds for the entire \p Range. 247*4ba319b5SDimitry Andric static bool 248*4ba319b5SDimitry Andric getDecisionAndClampRange(const std::function<bool(unsigned)> &Predicate, 249*4ba319b5SDimitry Andric VFRange &Range); 250*4ba319b5SDimitry Andric 251*4ba319b5SDimitry Andric protected: 252*4ba319b5SDimitry Andric /// Collect the instructions from the original loop that would be trivially 253*4ba319b5SDimitry Andric /// dead in the vectorized loop if generated. 254*4ba319b5SDimitry Andric void collectTriviallyDeadInstructions( 255*4ba319b5SDimitry Andric SmallPtrSetImpl<Instruction *> &DeadInstructions); 256*4ba319b5SDimitry Andric 257*4ba319b5SDimitry Andric /// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive, 258*4ba319b5SDimitry Andric /// according to the information gathered by Legal when it checked if it is 259*4ba319b5SDimitry Andric /// legal to vectorize the loop. 260*4ba319b5SDimitry Andric void buildVPlans(unsigned MinVF, unsigned MaxVF); 261*4ba319b5SDimitry Andric 262*4ba319b5SDimitry Andric private: 263*4ba319b5SDimitry Andric /// Build a VPlan according to the information gathered by Legal. \return a 264*4ba319b5SDimitry Andric /// VPlan for vectorization factors \p Range.Start and up to \p Range.End 265*4ba319b5SDimitry Andric /// exclusive, possibly decreasing \p Range.End. 266*4ba319b5SDimitry Andric VPlanPtr buildVPlan(VFRange &Range); 267*4ba319b5SDimitry Andric 268*4ba319b5SDimitry Andric /// Build a VPlan using VPRecipes according to the information gather by 269*4ba319b5SDimitry Andric /// Legal. This method is only used for the legacy inner loop vectorizer. 270*4ba319b5SDimitry Andric VPlanPtr 271*4ba319b5SDimitry Andric buildVPlanWithVPRecipes(VFRange &Range, SmallPtrSetImpl<Value *> &NeedDef, 272*4ba319b5SDimitry Andric SmallPtrSetImpl<Instruction *> &DeadInstructions); 273*4ba319b5SDimitry Andric 274*4ba319b5SDimitry Andric /// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive, 275*4ba319b5SDimitry Andric /// according to the information gathered by Legal when it checked if it is 276*4ba319b5SDimitry Andric /// legal to vectorize the loop. This method creates VPlans using VPRecipes. 277*4ba319b5SDimitry Andric void buildVPlansWithVPRecipes(unsigned MinVF, unsigned MaxVF); 278*4ba319b5SDimitry Andric }; 279*4ba319b5SDimitry Andric 280*4ba319b5SDimitry Andric } // namespace llvm 281*4ba319b5SDimitry Andric 282*4ba319b5SDimitry Andric #endif // LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZATIONPLANNER_H 283