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