1eb11fae6SDimitry Andric //===- LoopVectorizationPlanner.h - Planner for LoopVectorization ---------===// 2eb11fae6SDimitry Andric // 3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6eb11fae6SDimitry Andric // 7eb11fae6SDimitry Andric //===----------------------------------------------------------------------===// 8eb11fae6SDimitry Andric /// 9eb11fae6SDimitry Andric /// \file 10eb11fae6SDimitry Andric /// This file provides a LoopVectorizationPlanner class. 11eb11fae6SDimitry Andric /// InnerLoopVectorizer vectorizes loops which contain only one basic 12eb11fae6SDimitry Andric /// LoopVectorizationPlanner - drives the vectorization process after having 13eb11fae6SDimitry Andric /// passed Legality checks. 14eb11fae6SDimitry Andric /// The planner builds and optimizes the Vectorization Plans which record the 15eb11fae6SDimitry Andric /// decisions how to vectorize the given loop. In particular, represent the 16eb11fae6SDimitry Andric /// control-flow of the vectorized version, the replication of instructions that 17eb11fae6SDimitry Andric /// are to be scalarized, and interleave access groups. 18eb11fae6SDimitry Andric /// 19eb11fae6SDimitry Andric /// Also provides a VPlan-based builder utility analogous to IRBuilder. 20eb11fae6SDimitry Andric /// It provides an instruction-level API for generating VPInstructions while 21eb11fae6SDimitry Andric /// abstracting away the Recipe manipulation details. 22eb11fae6SDimitry Andric //===----------------------------------------------------------------------===// 23eb11fae6SDimitry Andric 24eb11fae6SDimitry Andric #ifndef LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZATIONPLANNER_H 25eb11fae6SDimitry Andric #define LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZATIONPLANNER_H 26eb11fae6SDimitry Andric 27eb11fae6SDimitry Andric #include "VPlan.h" 287fa27ce4SDimitry Andric #include "llvm/ADT/SmallSet.h" 29145449b1SDimitry Andric #include "llvm/Support/InstructionCost.h" 30eb11fae6SDimitry Andric 31eb11fae6SDimitry Andric namespace llvm { 32eb11fae6SDimitry Andric 33344a3780SDimitry Andric class LoopInfo; 34b1c73532SDimitry Andric class DominatorTree; 35cfca06d7SDimitry Andric class LoopVectorizationLegality; 36cfca06d7SDimitry Andric class LoopVectorizationCostModel; 37cfca06d7SDimitry Andric class PredicatedScalarEvolution; 38344a3780SDimitry Andric class LoopVectorizeHints; 39344a3780SDimitry Andric class OptimizationRemarkEmitter; 40344a3780SDimitry Andric class TargetTransformInfo; 41344a3780SDimitry Andric class TargetLibraryInfo; 42b60736ecSDimitry Andric class VPRecipeBuilder; 43cfca06d7SDimitry Andric 44eb11fae6SDimitry Andric /// VPlan-based builder utility analogous to IRBuilder. 45eb11fae6SDimitry Andric class VPBuilder { 46eb11fae6SDimitry Andric VPBasicBlock *BB = nullptr; 47eb11fae6SDimitry Andric VPBasicBlock::iterator InsertPt = VPBasicBlock::iterator(); 48eb11fae6SDimitry Andric 49b1c73532SDimitry Andric /// Insert \p VPI in BB at InsertPt if BB is set. tryInsertInstruction(VPInstruction * VPI)50b1c73532SDimitry Andric VPInstruction *tryInsertInstruction(VPInstruction *VPI) { 51b1c73532SDimitry Andric if (BB) 52b1c73532SDimitry Andric BB->insert(VPI, InsertPt); 53b1c73532SDimitry Andric return VPI; 54b1c73532SDimitry Andric } 55b1c73532SDimitry Andric 56eb11fae6SDimitry Andric VPInstruction *createInstruction(unsigned Opcode, 571f917f69SDimitry Andric ArrayRef<VPValue *> Operands, DebugLoc DL, 581f917f69SDimitry Andric const Twine &Name = "") { 59b1c73532SDimitry Andric return tryInsertInstruction(new VPInstruction(Opcode, Operands, DL, Name)); 60eb11fae6SDimitry Andric } 61eb11fae6SDimitry Andric 62eb11fae6SDimitry Andric VPInstruction *createInstruction(unsigned Opcode, 6377fc4c14SDimitry Andric std::initializer_list<VPValue *> Operands, 641f917f69SDimitry Andric DebugLoc DL, const Twine &Name = "") { 651f917f69SDimitry Andric return createInstruction(Opcode, ArrayRef<VPValue *>(Operands), DL, Name); 66eb11fae6SDimitry Andric } 67eb11fae6SDimitry Andric 68eb11fae6SDimitry Andric public: 69145449b1SDimitry Andric VPBuilder() = default; VPBuilder(VPBasicBlock * InsertBB)70b1c73532SDimitry Andric VPBuilder(VPBasicBlock *InsertBB) { setInsertPoint(InsertBB); } VPBuilder(VPRecipeBase * InsertPt)71ac9a064cSDimitry Andric VPBuilder(VPRecipeBase *InsertPt) { setInsertPoint(InsertPt); } 72eb11fae6SDimitry Andric 73eb11fae6SDimitry Andric /// Clear the insertion point: created instructions will not be inserted into 74eb11fae6SDimitry Andric /// a block. clearInsertionPoint()75eb11fae6SDimitry Andric void clearInsertionPoint() { 76eb11fae6SDimitry Andric BB = nullptr; 77eb11fae6SDimitry Andric InsertPt = VPBasicBlock::iterator(); 78eb11fae6SDimitry Andric } 79eb11fae6SDimitry Andric getInsertBlock()80eb11fae6SDimitry Andric VPBasicBlock *getInsertBlock() const { return BB; } getInsertPoint()81eb11fae6SDimitry Andric VPBasicBlock::iterator getInsertPoint() const { return InsertPt; } 82eb11fae6SDimitry Andric 83ac9a064cSDimitry Andric /// Create a VPBuilder to insert after \p R. getToInsertAfter(VPRecipeBase * R)84ac9a064cSDimitry Andric static VPBuilder getToInsertAfter(VPRecipeBase *R) { 85ac9a064cSDimitry Andric VPBuilder B; 86ac9a064cSDimitry Andric B.setInsertPoint(R->getParent(), std::next(R->getIterator())); 87ac9a064cSDimitry Andric return B; 88ac9a064cSDimitry Andric } 89ac9a064cSDimitry Andric 90eb11fae6SDimitry Andric /// InsertPoint - A saved insertion point. 91eb11fae6SDimitry Andric class VPInsertPoint { 92eb11fae6SDimitry Andric VPBasicBlock *Block = nullptr; 93eb11fae6SDimitry Andric VPBasicBlock::iterator Point; 94eb11fae6SDimitry Andric 95eb11fae6SDimitry Andric public: 96eb11fae6SDimitry Andric /// Creates a new insertion point which doesn't point to anything. 97eb11fae6SDimitry Andric VPInsertPoint() = default; 98eb11fae6SDimitry Andric 99eb11fae6SDimitry Andric /// Creates a new insertion point at the given location. VPInsertPoint(VPBasicBlock * InsertBlock,VPBasicBlock::iterator InsertPoint)100eb11fae6SDimitry Andric VPInsertPoint(VPBasicBlock *InsertBlock, VPBasicBlock::iterator InsertPoint) 101eb11fae6SDimitry Andric : Block(InsertBlock), Point(InsertPoint) {} 102eb11fae6SDimitry Andric 103eb11fae6SDimitry Andric /// Returns true if this insert point is set. isSet()104eb11fae6SDimitry Andric bool isSet() const { return Block != nullptr; } 105eb11fae6SDimitry Andric getBlock()106eb11fae6SDimitry Andric VPBasicBlock *getBlock() const { return Block; } getPoint()107eb11fae6SDimitry Andric VPBasicBlock::iterator getPoint() const { return Point; } 108eb11fae6SDimitry Andric }; 109eb11fae6SDimitry Andric 110eb11fae6SDimitry Andric /// Sets the current insert point to a previously-saved location. restoreIP(VPInsertPoint IP)111eb11fae6SDimitry Andric void restoreIP(VPInsertPoint IP) { 112eb11fae6SDimitry Andric if (IP.isSet()) 113eb11fae6SDimitry Andric setInsertPoint(IP.getBlock(), IP.getPoint()); 114eb11fae6SDimitry Andric else 115eb11fae6SDimitry Andric clearInsertionPoint(); 116eb11fae6SDimitry Andric } 117eb11fae6SDimitry Andric 118eb11fae6SDimitry Andric /// This specifies that created VPInstructions should be appended to the end 119eb11fae6SDimitry Andric /// of the specified block. setInsertPoint(VPBasicBlock * TheBB)120eb11fae6SDimitry Andric void setInsertPoint(VPBasicBlock *TheBB) { 121eb11fae6SDimitry Andric assert(TheBB && "Attempting to set a null insert point"); 122eb11fae6SDimitry Andric BB = TheBB; 123eb11fae6SDimitry Andric InsertPt = BB->end(); 124eb11fae6SDimitry Andric } 125eb11fae6SDimitry Andric 126eb11fae6SDimitry Andric /// This specifies that created instructions should be inserted at the 127eb11fae6SDimitry Andric /// specified point. setInsertPoint(VPBasicBlock * TheBB,VPBasicBlock::iterator IP)128eb11fae6SDimitry Andric void setInsertPoint(VPBasicBlock *TheBB, VPBasicBlock::iterator IP) { 129eb11fae6SDimitry Andric BB = TheBB; 130eb11fae6SDimitry Andric InsertPt = IP; 131eb11fae6SDimitry Andric } 132eb11fae6SDimitry Andric 133b1c73532SDimitry Andric /// This specifies that created instructions should be inserted at the 134b1c73532SDimitry Andric /// specified point. setInsertPoint(VPRecipeBase * IP)135b1c73532SDimitry Andric void setInsertPoint(VPRecipeBase *IP) { 136b1c73532SDimitry Andric BB = IP->getParent(); 137b1c73532SDimitry Andric InsertPt = IP->getIterator(); 138eb11fae6SDimitry Andric } 139eb11fae6SDimitry Andric 140eb11fae6SDimitry Andric /// Create an N-ary operation with \p Opcode, \p Operands and set \p Inst as 141eb11fae6SDimitry Andric /// its underlying Instruction. 142ac9a064cSDimitry Andric VPInstruction *createNaryOp(unsigned Opcode, ArrayRef<VPValue *> Operands, 143ac9a064cSDimitry Andric Instruction *Inst = nullptr, 144ac9a064cSDimitry Andric const Twine &Name = "") { 14577fc4c14SDimitry Andric DebugLoc DL; 14677fc4c14SDimitry Andric if (Inst) 14777fc4c14SDimitry Andric DL = Inst->getDebugLoc(); 1481f917f69SDimitry Andric VPInstruction *NewVPInst = createInstruction(Opcode, Operands, DL, Name); 149eb11fae6SDimitry Andric NewVPInst->setUnderlyingValue(Inst); 150eb11fae6SDimitry Andric return NewVPInst; 151eb11fae6SDimitry Andric } 152ac9a064cSDimitry Andric VPInstruction *createNaryOp(unsigned Opcode, ArrayRef<VPValue *> Operands, 1531f917f69SDimitry Andric DebugLoc DL, const Twine &Name = "") { 1541f917f69SDimitry Andric return createInstruction(Opcode, Operands, DL, Name); 155eb11fae6SDimitry Andric } 156eb11fae6SDimitry Andric 157b1c73532SDimitry Andric VPInstruction *createOverflowingOp(unsigned Opcode, 158b1c73532SDimitry Andric std::initializer_list<VPValue *> Operands, 159b1c73532SDimitry Andric VPRecipeWithIRFlags::WrapFlagsTy WrapFlags, 1604df029ccSDimitry Andric DebugLoc DL = {}, const Twine &Name = "") { 161b1c73532SDimitry Andric return tryInsertInstruction( 162b1c73532SDimitry Andric new VPInstruction(Opcode, Operands, WrapFlags, DL, Name)); 163b1c73532SDimitry Andric } 1644df029ccSDimitry Andric VPValue *createNot(VPValue *Operand, DebugLoc DL = {}, 1654df029ccSDimitry Andric const Twine &Name = "") { 1661f917f69SDimitry Andric return createInstruction(VPInstruction::Not, {Operand}, DL, Name); 167eb11fae6SDimitry Andric } 168eb11fae6SDimitry Andric 1694df029ccSDimitry Andric VPValue *createAnd(VPValue *LHS, VPValue *RHS, DebugLoc DL = {}, 1701f917f69SDimitry Andric const Twine &Name = "") { 1711f917f69SDimitry Andric return createInstruction(Instruction::BinaryOps::And, {LHS, RHS}, DL, Name); 172eb11fae6SDimitry Andric } 173eb11fae6SDimitry Andric 1744df029ccSDimitry Andric VPValue *createOr(VPValue *LHS, VPValue *RHS, DebugLoc DL = {}, 1751f917f69SDimitry Andric const Twine &Name = "") { 176ac9a064cSDimitry Andric 177ac9a064cSDimitry Andric return tryInsertInstruction(new VPInstruction( 178ac9a064cSDimitry Andric Instruction::BinaryOps::Or, {LHS, RHS}, 179ac9a064cSDimitry Andric VPRecipeWithIRFlags::DisjointFlagsTy(false), DL, Name)); 180ac9a064cSDimitry Andric } 181ac9a064cSDimitry Andric 182ac9a064cSDimitry Andric VPValue *createLogicalAnd(VPValue *LHS, VPValue *RHS, DebugLoc DL = {}, 183ac9a064cSDimitry Andric const Twine &Name = "") { 184ac9a064cSDimitry Andric return tryInsertInstruction( 185ac9a064cSDimitry Andric new VPInstruction(VPInstruction::LogicalAnd, {LHS, RHS}, DL, Name)); 186eb11fae6SDimitry Andric } 187eb11fae6SDimitry Andric 18877fc4c14SDimitry Andric VPValue *createSelect(VPValue *Cond, VPValue *TrueVal, VPValue *FalseVal, 1894df029ccSDimitry Andric DebugLoc DL = {}, const Twine &Name = "", 190aca2e42cSDimitry Andric std::optional<FastMathFlags> FMFs = std::nullopt) { 191aca2e42cSDimitry Andric auto *Select = 192aca2e42cSDimitry Andric FMFs ? new VPInstruction(Instruction::Select, {Cond, TrueVal, FalseVal}, 193aca2e42cSDimitry Andric *FMFs, DL, Name) 194aca2e42cSDimitry Andric : new VPInstruction(Instruction::Select, {Cond, TrueVal, FalseVal}, 195aca2e42cSDimitry Andric DL, Name); 196aca2e42cSDimitry Andric return tryInsertInstruction(Select); 197344a3780SDimitry Andric } 198344a3780SDimitry Andric 199b1c73532SDimitry Andric /// Create a new ICmp VPInstruction with predicate \p Pred and operands \p A 200b1c73532SDimitry Andric /// and \p B. 201b1c73532SDimitry Andric /// TODO: add createFCmp when needed. 202b1c73532SDimitry Andric VPValue *createICmp(CmpInst::Predicate Pred, VPValue *A, VPValue *B, 203b1c73532SDimitry Andric DebugLoc DL = {}, const Twine &Name = ""); 204b1c73532SDimitry Andric 205eb11fae6SDimitry Andric //===--------------------------------------------------------------------===// 206eb11fae6SDimitry Andric // RAII helpers. 207eb11fae6SDimitry Andric //===--------------------------------------------------------------------===// 208eb11fae6SDimitry Andric 209eb11fae6SDimitry Andric /// RAII object that stores the current insertion point and restores it when 210eb11fae6SDimitry Andric /// the object is destroyed. 211eb11fae6SDimitry Andric class InsertPointGuard { 212eb11fae6SDimitry Andric VPBuilder &Builder; 213eb11fae6SDimitry Andric VPBasicBlock *Block; 214eb11fae6SDimitry Andric VPBasicBlock::iterator Point; 215eb11fae6SDimitry Andric 216eb11fae6SDimitry Andric public: InsertPointGuard(VPBuilder & B)217eb11fae6SDimitry Andric InsertPointGuard(VPBuilder &B) 218eb11fae6SDimitry Andric : Builder(B), Block(B.getInsertBlock()), Point(B.getInsertPoint()) {} 219eb11fae6SDimitry Andric 220eb11fae6SDimitry Andric InsertPointGuard(const InsertPointGuard &) = delete; 221eb11fae6SDimitry Andric InsertPointGuard &operator=(const InsertPointGuard &) = delete; 222eb11fae6SDimitry Andric ~InsertPointGuard()223eb11fae6SDimitry Andric ~InsertPointGuard() { Builder.restoreIP(VPInsertPoint(Block, Point)); } 224eb11fae6SDimitry Andric }; 225eb11fae6SDimitry Andric }; 226eb11fae6SDimitry Andric 227eb11fae6SDimitry Andric /// TODO: The following VectorizationFactor was pulled out of 228eb11fae6SDimitry Andric /// LoopVectorizationCostModel class. LV also deals with 229ac9a064cSDimitry Andric /// VectorizerParams::VectorizationFactor. 230eb11fae6SDimitry Andric /// We need to streamline them. 231eb11fae6SDimitry Andric 232344a3780SDimitry Andric /// Information about vectorization costs. 233eb11fae6SDimitry Andric struct VectorizationFactor { 234344a3780SDimitry Andric /// Vector width with best cost. 235b60736ecSDimitry Andric ElementCount Width; 236e3b55780SDimitry Andric 237344a3780SDimitry Andric /// Cost of the loop with that width. 238344a3780SDimitry Andric InstructionCost Cost; 239e6d15924SDimitry Andric 240145449b1SDimitry Andric /// Cost of the scalar loop. 241145449b1SDimitry Andric InstructionCost ScalarCost; 242145449b1SDimitry Andric 2431f917f69SDimitry Andric /// The minimum trip count required to make vectorization profitable, e.g. due 2441f917f69SDimitry Andric /// to runtime checks. 2451f917f69SDimitry Andric ElementCount MinProfitableTripCount; 2461f917f69SDimitry Andric VectorizationFactorVectorizationFactor247145449b1SDimitry Andric VectorizationFactor(ElementCount Width, InstructionCost Cost, 248145449b1SDimitry Andric InstructionCost ScalarCost) 249145449b1SDimitry Andric : Width(Width), Cost(Cost), ScalarCost(ScalarCost) {} 250344a3780SDimitry Andric 251344a3780SDimitry Andric /// Width 1 means no vectorization, cost 0 means uncomputed cost. DisabledVectorizationFactor252b60736ecSDimitry Andric static VectorizationFactor Disabled() { 253145449b1SDimitry Andric return {ElementCount::getFixed(1), 0, 0}; 254b60736ecSDimitry Andric } 255e6d15924SDimitry Andric 256e6d15924SDimitry Andric bool operator==(const VectorizationFactor &rhs) const { 257e6d15924SDimitry Andric return Width == rhs.Width && Cost == rhs.Cost; 258e6d15924SDimitry Andric } 259b60736ecSDimitry Andric 260b60736ecSDimitry Andric bool operator!=(const VectorizationFactor &rhs) const { 261b60736ecSDimitry Andric return !(*this == rhs); 262b60736ecSDimitry Andric } 263eb11fae6SDimitry Andric }; 264eb11fae6SDimitry Andric 265344a3780SDimitry Andric /// A class that represents two vectorization factors (initialized with 0 by 266344a3780SDimitry Andric /// default). One for fixed-width vectorization and one for scalable 267344a3780SDimitry Andric /// vectorization. This can be used by the vectorizer to choose from a range of 268344a3780SDimitry Andric /// fixed and/or scalable VFs in order to find the most cost-effective VF to 269344a3780SDimitry Andric /// vectorize with. 270344a3780SDimitry Andric struct FixedScalableVFPair { 271344a3780SDimitry Andric ElementCount FixedVF; 272344a3780SDimitry Andric ElementCount ScalableVF; 273344a3780SDimitry Andric FixedScalableVFPairFixedScalableVFPair274344a3780SDimitry Andric FixedScalableVFPair() 275344a3780SDimitry Andric : FixedVF(ElementCount::getFixed(0)), 276344a3780SDimitry Andric ScalableVF(ElementCount::getScalable(0)) {} FixedScalableVFPairFixedScalableVFPair277344a3780SDimitry Andric FixedScalableVFPair(const ElementCount &Max) : FixedScalableVFPair() { 278344a3780SDimitry Andric *(Max.isScalable() ? &ScalableVF : &FixedVF) = Max; 279344a3780SDimitry Andric } FixedScalableVFPairFixedScalableVFPair280344a3780SDimitry Andric FixedScalableVFPair(const ElementCount &FixedVF, 281344a3780SDimitry Andric const ElementCount &ScalableVF) 282344a3780SDimitry Andric : FixedVF(FixedVF), ScalableVF(ScalableVF) { 283344a3780SDimitry Andric assert(!FixedVF.isScalable() && ScalableVF.isScalable() && 284344a3780SDimitry Andric "Invalid scalable properties"); 285344a3780SDimitry Andric } 286344a3780SDimitry Andric getNoneFixedScalableVFPair287344a3780SDimitry Andric static FixedScalableVFPair getNone() { return FixedScalableVFPair(); } 288344a3780SDimitry Andric 289344a3780SDimitry Andric /// \return true if either fixed- or scalable VF is non-zero. 290344a3780SDimitry Andric explicit operator bool() const { return FixedVF || ScalableVF; } 291344a3780SDimitry Andric 292344a3780SDimitry Andric /// \return true if either fixed- or scalable VF is a valid vector VF. hasVectorFixedScalableVFPair293344a3780SDimitry Andric bool hasVector() const { return FixedVF.isVector() || ScalableVF.isVector(); } 294344a3780SDimitry Andric }; 295344a3780SDimitry Andric 296eb11fae6SDimitry Andric /// Planner drives the vectorization process after having passed 297eb11fae6SDimitry Andric /// Legality checks. 298eb11fae6SDimitry Andric class LoopVectorizationPlanner { 299eb11fae6SDimitry Andric /// The loop that we evaluate. 300eb11fae6SDimitry Andric Loop *OrigLoop; 301eb11fae6SDimitry Andric 302eb11fae6SDimitry Andric /// Loop Info analysis. 303eb11fae6SDimitry Andric LoopInfo *LI; 304eb11fae6SDimitry Andric 305b1c73532SDimitry Andric /// The dominator tree. 306b1c73532SDimitry Andric DominatorTree *DT; 307b1c73532SDimitry Andric 308eb11fae6SDimitry Andric /// Target Library Info. 309eb11fae6SDimitry Andric const TargetLibraryInfo *TLI; 310eb11fae6SDimitry Andric 311eb11fae6SDimitry Andric /// Target Transform Info. 3127fa27ce4SDimitry Andric const TargetTransformInfo &TTI; 313eb11fae6SDimitry Andric 314eb11fae6SDimitry Andric /// The legality analysis. 315eb11fae6SDimitry Andric LoopVectorizationLegality *Legal; 316eb11fae6SDimitry Andric 317e6d15924SDimitry Andric /// The profitability analysis. 318eb11fae6SDimitry Andric LoopVectorizationCostModel &CM; 319eb11fae6SDimitry Andric 320706b4fc4SDimitry Andric /// The interleaved access analysis. 321706b4fc4SDimitry Andric InterleavedAccessInfo &IAI; 322706b4fc4SDimitry Andric 323cfca06d7SDimitry Andric PredicatedScalarEvolution &PSE; 324cfca06d7SDimitry Andric 325344a3780SDimitry Andric const LoopVectorizeHints &Hints; 326344a3780SDimitry Andric 327344a3780SDimitry Andric OptimizationRemarkEmitter *ORE; 328344a3780SDimitry Andric 329eb11fae6SDimitry Andric SmallVector<VPlanPtr, 4> VPlans; 330eb11fae6SDimitry Andric 3317fa27ce4SDimitry Andric /// Profitable vector factors. 3327fa27ce4SDimitry Andric SmallVector<VectorizationFactor, 8> ProfitableVFs; 3337fa27ce4SDimitry Andric 334eb11fae6SDimitry Andric /// A builder used to construct the current plan. 335eb11fae6SDimitry Andric VPBuilder Builder; 336eb11fae6SDimitry Andric 337ac9a064cSDimitry Andric /// Computes the cost of \p Plan for vectorization factor \p VF. 338ac9a064cSDimitry Andric /// 339ac9a064cSDimitry Andric /// The current implementation requires access to the 340ac9a064cSDimitry Andric /// LoopVectorizationLegality to handle inductions and reductions, which is 341ac9a064cSDimitry Andric /// why it is kept separate from the VPlan-only cost infrastructure. 342ac9a064cSDimitry Andric /// 343ac9a064cSDimitry Andric /// TODO: Move to VPlan::cost once the use of LoopVectorizationLegality has 344ac9a064cSDimitry Andric /// been retired. 345ac9a064cSDimitry Andric InstructionCost cost(VPlan &Plan, ElementCount VF) const; 346ac9a064cSDimitry Andric 347eb11fae6SDimitry Andric public: LoopVectorizationPlanner(Loop * L,LoopInfo * LI,DominatorTree * DT,const TargetLibraryInfo * TLI,const TargetTransformInfo & TTI,LoopVectorizationLegality * Legal,LoopVectorizationCostModel & CM,InterleavedAccessInfo & IAI,PredicatedScalarEvolution & PSE,const LoopVectorizeHints & Hints,OptimizationRemarkEmitter * ORE)348b1c73532SDimitry Andric LoopVectorizationPlanner( 349b1c73532SDimitry Andric Loop *L, LoopInfo *LI, DominatorTree *DT, const TargetLibraryInfo *TLI, 350b1c73532SDimitry Andric const TargetTransformInfo &TTI, LoopVectorizationLegality *Legal, 351b1c73532SDimitry Andric LoopVectorizationCostModel &CM, InterleavedAccessInfo &IAI, 352b1c73532SDimitry Andric PredicatedScalarEvolution &PSE, const LoopVectorizeHints &Hints, 353344a3780SDimitry Andric OptimizationRemarkEmitter *ORE) 354b1c73532SDimitry Andric : OrigLoop(L), LI(LI), DT(DT), TLI(TLI), TTI(TTI), Legal(Legal), CM(CM), 355b1c73532SDimitry Andric IAI(IAI), PSE(PSE), Hints(Hints), ORE(ORE) {} 356eb11fae6SDimitry Andric 357e3b55780SDimitry Andric /// Plan how to best vectorize, return the best VF and its cost, or 358e3b55780SDimitry Andric /// std::nullopt if vectorization and interleaving should be avoided up front. 359e3b55780SDimitry Andric std::optional<VectorizationFactor> plan(ElementCount UserVF, unsigned UserIC); 360eb11fae6SDimitry Andric 361eb11fae6SDimitry Andric /// Use the VPlan-native path to plan how to best vectorize, return the best 362eb11fae6SDimitry Andric /// VF and its cost. 363b60736ecSDimitry Andric VectorizationFactor planInVPlanNativePath(ElementCount UserVF); 364eb11fae6SDimitry Andric 365c0981da4SDimitry Andric /// Return the best VPlan for \p VF. 366c0981da4SDimitry Andric VPlan &getBestPlanFor(ElementCount VF) const; 367eb11fae6SDimitry Andric 368ac9a064cSDimitry Andric /// Return the most profitable plan and fix its VF to the most profitable one. 369ac9a064cSDimitry Andric VPlan &getBestPlan() const; 370ac9a064cSDimitry Andric 371aca2e42cSDimitry Andric /// Generate the IR code for the vectorized loop captured in VPlan \p BestPlan 372aca2e42cSDimitry Andric /// according to the best selected \p VF and \p UF. 373aca2e42cSDimitry Andric /// 374145449b1SDimitry Andric /// TODO: \p IsEpilogueVectorization is needed to avoid issues due to epilogue 375145449b1SDimitry Andric /// vectorization re-using plans for both the main and epilogue vector loops. 376145449b1SDimitry Andric /// It should be removed once the re-use issue has been fixed. 3777fa27ce4SDimitry Andric /// \p ExpandedSCEVs is passed during execution of the plan for epilogue loop 378aca2e42cSDimitry Andric /// to re-use expansion results generated during main plan execution. 379aca2e42cSDimitry Andric /// 380aca2e42cSDimitry Andric /// Returns a mapping of SCEVs to their expanded IR values and a mapping for 381aca2e42cSDimitry Andric /// the reduction resume values. Note that this is a temporary workaround 382aca2e42cSDimitry Andric /// needed due to the current epilogue handling. 383aca2e42cSDimitry Andric std::pair<DenseMap<const SCEV *, Value *>, 384aca2e42cSDimitry Andric DenseMap<const RecurrenceDescriptor *, Value *>> 3857fa27ce4SDimitry Andric executePlan(ElementCount VF, unsigned UF, VPlan &BestPlan, 386145449b1SDimitry Andric InnerLoopVectorizer &LB, DominatorTree *DT, 3877fa27ce4SDimitry Andric bool IsEpilogueVectorization, 388b1c73532SDimitry Andric const DenseMap<const SCEV *, Value *> *ExpandedSCEVs = nullptr); 389eb11fae6SDimitry Andric 390344a3780SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 391344a3780SDimitry Andric void printPlans(raw_ostream &O); 392344a3780SDimitry Andric #endif 393eb11fae6SDimitry Andric 3947fa27ce4SDimitry Andric /// Look through the existing plans and return true if we have one with 3957fa27ce4SDimitry Andric /// vectorization factor \p VF. hasPlanWithVF(ElementCount VF)396c0981da4SDimitry Andric bool hasPlanWithVF(ElementCount VF) const { 397c0981da4SDimitry Andric return any_of(VPlans, 398c0981da4SDimitry Andric [&](const VPlanPtr &Plan) { return Plan->hasVF(VF); }); 399b60736ecSDimitry Andric } 400b60736ecSDimitry Andric 401eb11fae6SDimitry Andric /// Test a \p Predicate on a \p Range of VF's. Return the value of applying 402eb11fae6SDimitry Andric /// \p Predicate on Range.Start, possibly decreasing Range.End such that the 403eb11fae6SDimitry Andric /// returned value holds for the entire \p Range. 404eb11fae6SDimitry Andric static bool 405b60736ecSDimitry Andric getDecisionAndClampRange(const std::function<bool(ElementCount)> &Predicate, 406eb11fae6SDimitry Andric VFRange &Range); 407eb11fae6SDimitry Andric 4087fa27ce4SDimitry Andric /// \return The most profitable vectorization factor and the cost of that VF 4097fa27ce4SDimitry Andric /// for vectorizing the epilogue. Returns VectorizationFactor::Disabled if 4107fa27ce4SDimitry Andric /// epilogue vectorization is not supported for the loop. 4117fa27ce4SDimitry Andric VectorizationFactor 4127fa27ce4SDimitry Andric selectEpilogueVectorizationFactor(const ElementCount MaxVF, unsigned IC); 413145449b1SDimitry Andric 414eb11fae6SDimitry Andric protected: 415eb11fae6SDimitry Andric /// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive, 416eb11fae6SDimitry Andric /// according to the information gathered by Legal when it checked if it is 417eb11fae6SDimitry Andric /// legal to vectorize the loop. 418b60736ecSDimitry Andric void buildVPlans(ElementCount MinVF, ElementCount MaxVF); 419eb11fae6SDimitry Andric 420eb11fae6SDimitry Andric private: 421eb11fae6SDimitry Andric /// Build a VPlan according to the information gathered by Legal. \return a 422eb11fae6SDimitry Andric /// VPlan for vectorization factors \p Range.Start and up to \p Range.End 423eb11fae6SDimitry Andric /// exclusive, possibly decreasing \p Range.End. 424eb11fae6SDimitry Andric VPlanPtr buildVPlan(VFRange &Range); 425eb11fae6SDimitry Andric 426eb11fae6SDimitry Andric /// Build a VPlan using VPRecipes according to the information gather by 427eb11fae6SDimitry Andric /// Legal. This method is only used for the legacy inner loop vectorizer. 4287fa27ce4SDimitry Andric /// \p Range's largest included VF is restricted to the maximum VF the 4297fa27ce4SDimitry Andric /// returned VPlan is valid for. If no VPlan can be built for the input range, 4307fa27ce4SDimitry Andric /// set the largest included VF to the maximum VF for which no plan could be 4317fa27ce4SDimitry Andric /// built. 432b1c73532SDimitry Andric VPlanPtr tryToBuildVPlanWithVPRecipes(VFRange &Range); 433eb11fae6SDimitry Andric 434eb11fae6SDimitry Andric /// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive, 435eb11fae6SDimitry Andric /// according to the information gathered by Legal when it checked if it is 436eb11fae6SDimitry Andric /// legal to vectorize the loop. This method creates VPlans using VPRecipes. 437b60736ecSDimitry Andric void buildVPlansWithVPRecipes(ElementCount MinVF, ElementCount MaxVF); 438b60736ecSDimitry Andric 439c0981da4SDimitry Andric // Adjust the recipes for reductions. For in-loop reductions the chain of 440c0981da4SDimitry Andric // instructions leading from the loop exit instr to the phi need to be 441c0981da4SDimitry Andric // converted to reductions, with one operand being vector and the other being 442c0981da4SDimitry Andric // the scalar reduction chain. For other reductions, a select is introduced 443c0981da4SDimitry Andric // between the phi and live-out recipes when folding the tail. 444ac9a064cSDimitry Andric void adjustRecipesForReductions(VPlanPtr &Plan, 445344a3780SDimitry Andric VPRecipeBuilder &RecipeBuilder, 446344a3780SDimitry Andric ElementCount MinVF); 4477fa27ce4SDimitry Andric 448ac9a064cSDimitry Andric /// \return The most profitable vectorization factor for the available VPlans 449ac9a064cSDimitry Andric /// and the cost of that VF. 450ac9a064cSDimitry Andric /// This is now only used to verify the decisions by the new VPlan-based 451ac9a064cSDimitry Andric /// cost-model and will be retired once the VPlan-based cost-model is 452ac9a064cSDimitry Andric /// stabilized. 453ac9a064cSDimitry Andric VectorizationFactor selectVectorizationFactor(); 4547fa27ce4SDimitry Andric 4557fa27ce4SDimitry Andric /// Returns true if the per-lane cost of VectorizationFactor A is lower than 4567fa27ce4SDimitry Andric /// that of B. 4577fa27ce4SDimitry Andric bool isMoreProfitable(const VectorizationFactor &A, 4587fa27ce4SDimitry Andric const VectorizationFactor &B) const; 4597fa27ce4SDimitry Andric 4607fa27ce4SDimitry Andric /// Determines if we have the infrastructure to vectorize the loop and its 4617fa27ce4SDimitry Andric /// epilogue, assuming the main loop is vectorized by \p VF. 4627fa27ce4SDimitry Andric bool isCandidateForEpilogueVectorization(const ElementCount VF) const; 463eb11fae6SDimitry Andric }; 464eb11fae6SDimitry Andric 465eb11fae6SDimitry Andric } // namespace llvm 466eb11fae6SDimitry Andric 467eb11fae6SDimitry Andric #endif // LLVM_TRANSFORMS_VECTORIZE_LOOPVECTORIZATIONPLANNER_H 468