10b57cec5SDimitry Andric //===- VPlan.h - Represent A Vectorizer Plan --------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file contains the declarations of the Vectorization Plan base classes: 110b57cec5SDimitry Andric /// 1. VPBasicBlock and VPRegionBlock that inherit from a common pure virtual 120b57cec5SDimitry Andric /// VPBlockBase, together implementing a Hierarchical CFG; 13bdd1243dSDimitry Andric /// 2. Pure virtual VPRecipeBase serving as the base class for recipes contained 140b57cec5SDimitry Andric /// within VPBasicBlocks; 157a6dacacSDimitry Andric /// 3. Pure virtual VPSingleDefRecipe serving as a base class for recipes that 167a6dacacSDimitry Andric /// also inherit from VPValue. 177a6dacacSDimitry Andric /// 4. VPInstruction, a concrete Recipe and VPUser modeling a single planned 180b57cec5SDimitry Andric /// instruction; 197a6dacacSDimitry Andric /// 5. The VPlan class holding a candidate for vectorization; 207a6dacacSDimitry Andric /// 6. The VPlanPrinter class providing a way to print a plan in dot format; 210b57cec5SDimitry Andric /// These are documented in docs/VectorizationPlan.rst. 220b57cec5SDimitry Andric // 230b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #ifndef LLVM_TRANSFORMS_VECTORIZE_VPLAN_H 260b57cec5SDimitry Andric #define LLVM_TRANSFORMS_VECTORIZE_VPLAN_H 270b57cec5SDimitry Andric 285f757f3fSDimitry Andric #include "VPlanAnalysis.h" 290b57cec5SDimitry Andric #include "VPlanValue.h" 300b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 3181ad6265SDimitry Andric #include "llvm/ADT/MapVector.h" 32480093f4SDimitry Andric #include "llvm/ADT/SmallBitVector.h" 330b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 340b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 350b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 360b57cec5SDimitry Andric #include "llvm/ADT/ilist.h" 370b57cec5SDimitry Andric #include "llvm/ADT/ilist_node.h" 38*0fca6ea1SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h" 3906c3fb27SDimitry Andric #include "llvm/Analysis/IVDescriptors.h" 4081ad6265SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 410b57cec5SDimitry Andric #include "llvm/Analysis/VectorUtils.h" 420eae32dcSDimitry Andric #include "llvm/IR/DebugLoc.h" 4381ad6265SDimitry Andric #include "llvm/IR/FMF.h" 4406c3fb27SDimitry Andric #include "llvm/IR/Operator.h" 45*0fca6ea1SDimitry Andric #include "llvm/Support/InstructionCost.h" 460b57cec5SDimitry Andric #include <algorithm> 470b57cec5SDimitry Andric #include <cassert> 480b57cec5SDimitry Andric #include <cstddef> 490b57cec5SDimitry Andric #include <string> 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric namespace llvm { 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric class BasicBlock; 540b57cec5SDimitry Andric class DominatorTree; 550b57cec5SDimitry Andric class InnerLoopVectorizer; 5681ad6265SDimitry Andric class IRBuilderBase; 570b57cec5SDimitry Andric class LoopInfo; 580b57cec5SDimitry Andric class raw_ostream; 59e8d8bef9SDimitry Andric class RecurrenceDescriptor; 60bdd1243dSDimitry Andric class SCEV; 61bdd1243dSDimitry Andric class Type; 620b57cec5SDimitry Andric class VPBasicBlock; 630b57cec5SDimitry Andric class VPRegionBlock; 640b57cec5SDimitry Andric class VPlan; 654824e7fdSDimitry Andric class VPReplicateRecipe; 660b57cec5SDimitry Andric class VPlanSlp; 67bdd1243dSDimitry Andric class Value; 68*0fca6ea1SDimitry Andric class LoopVectorizationCostModel; 6906c3fb27SDimitry Andric class LoopVersioning; 70bdd1243dSDimitry Andric 71*0fca6ea1SDimitry Andric struct VPCostContext; 72*0fca6ea1SDimitry Andric 73bdd1243dSDimitry Andric namespace Intrinsic { 74bdd1243dSDimitry Andric typedef unsigned ID; 75bdd1243dSDimitry Andric } 760b57cec5SDimitry Andric 77fe6060f1SDimitry Andric /// Returns a calculation for the total number of elements for a given \p VF. 78fe6060f1SDimitry Andric /// For fixed width vectors this value is a constant, whereas for scalable 79fe6060f1SDimitry Andric /// vectors it is an expression determined at runtime. 8081ad6265SDimitry Andric Value *getRuntimeVF(IRBuilderBase &B, Type *Ty, ElementCount VF); 81fe6060f1SDimitry Andric 8204eeddc0SDimitry Andric /// Return a value for Step multiplied by VF. 8381ad6265SDimitry Andric Value *createStepForVF(IRBuilderBase &B, Type *Ty, ElementCount VF, 8481ad6265SDimitry Andric int64_t Step); 8504eeddc0SDimitry Andric 8606c3fb27SDimitry Andric const SCEV *createTripCountSCEV(Type *IdxTy, PredicatedScalarEvolution &PSE, 8706c3fb27SDimitry Andric Loop *CurLoop = nullptr); 88bdd1243dSDimitry Andric 89*0fca6ea1SDimitry Andric /// A helper function that returns the reciprocal of the block probability of 90*0fca6ea1SDimitry Andric /// predicated blocks. If we return X, we are assuming the predicated block 91*0fca6ea1SDimitry Andric /// will execute once for every X iterations of the loop header. 92*0fca6ea1SDimitry Andric /// 93*0fca6ea1SDimitry Andric /// TODO: We should use actual block probability here, if available. Currently, 94*0fca6ea1SDimitry Andric /// we always assume predicated blocks have a 50% chance of executing. 95*0fca6ea1SDimitry Andric inline unsigned getReciprocalPredBlockProb() { return 2; } 96*0fca6ea1SDimitry Andric 970b57cec5SDimitry Andric /// A range of powers-of-2 vectorization factors with fixed start and 980b57cec5SDimitry Andric /// adjustable end. The range includes start and excludes end, e.g.,: 9906c3fb27SDimitry Andric /// [1, 16) = {1, 2, 4, 8} 1000b57cec5SDimitry Andric struct VFRange { 1010b57cec5SDimitry Andric // A power of 2. 102e8d8bef9SDimitry Andric const ElementCount Start; 1030b57cec5SDimitry Andric 10406c3fb27SDimitry Andric // A power of 2. If End <= Start range is empty. 105e8d8bef9SDimitry Andric ElementCount End; 106e8d8bef9SDimitry Andric 107e8d8bef9SDimitry Andric bool isEmpty() const { 108e8d8bef9SDimitry Andric return End.getKnownMinValue() <= Start.getKnownMinValue(); 109e8d8bef9SDimitry Andric } 110e8d8bef9SDimitry Andric 111e8d8bef9SDimitry Andric VFRange(const ElementCount &Start, const ElementCount &End) 112e8d8bef9SDimitry Andric : Start(Start), End(End) { 113e8d8bef9SDimitry Andric assert(Start.isScalable() == End.isScalable() && 114e8d8bef9SDimitry Andric "Both Start and End should have the same scalable flag"); 115e8d8bef9SDimitry Andric assert(isPowerOf2_32(Start.getKnownMinValue()) && 116e8d8bef9SDimitry Andric "Expected Start to be a power of 2"); 11706c3fb27SDimitry Andric assert(isPowerOf2_32(End.getKnownMinValue()) && 11806c3fb27SDimitry Andric "Expected End to be a power of 2"); 11906c3fb27SDimitry Andric } 12006c3fb27SDimitry Andric 12106c3fb27SDimitry Andric /// Iterator to iterate over vectorization factors in a VFRange. 12206c3fb27SDimitry Andric class iterator 12306c3fb27SDimitry Andric : public iterator_facade_base<iterator, std::forward_iterator_tag, 12406c3fb27SDimitry Andric ElementCount> { 12506c3fb27SDimitry Andric ElementCount VF; 12606c3fb27SDimitry Andric 12706c3fb27SDimitry Andric public: 12806c3fb27SDimitry Andric iterator(ElementCount VF) : VF(VF) {} 12906c3fb27SDimitry Andric 13006c3fb27SDimitry Andric bool operator==(const iterator &Other) const { return VF == Other.VF; } 13106c3fb27SDimitry Andric 13206c3fb27SDimitry Andric ElementCount operator*() const { return VF; } 13306c3fb27SDimitry Andric 13406c3fb27SDimitry Andric iterator &operator++() { 13506c3fb27SDimitry Andric VF *= 2; 13606c3fb27SDimitry Andric return *this; 13706c3fb27SDimitry Andric } 13806c3fb27SDimitry Andric }; 13906c3fb27SDimitry Andric 14006c3fb27SDimitry Andric iterator begin() { return iterator(Start); } 14106c3fb27SDimitry Andric iterator end() { 14206c3fb27SDimitry Andric assert(isPowerOf2_32(End.getKnownMinValue())); 14306c3fb27SDimitry Andric return iterator(End); 144e8d8bef9SDimitry Andric } 1450b57cec5SDimitry Andric }; 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric using VPlanPtr = std::unique_ptr<VPlan>; 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric /// In what follows, the term "input IR" refers to code that is fed into the 1500b57cec5SDimitry Andric /// vectorizer whereas the term "output IR" refers to code that is generated by 1510b57cec5SDimitry Andric /// the vectorizer. 1520b57cec5SDimitry Andric 153fe6060f1SDimitry Andric /// VPLane provides a way to access lanes in both fixed width and scalable 154fe6060f1SDimitry Andric /// vectors, where for the latter the lane index sometimes needs calculating 155fe6060f1SDimitry Andric /// as a runtime expression. 156fe6060f1SDimitry Andric class VPLane { 157fe6060f1SDimitry Andric public: 158fe6060f1SDimitry Andric /// Kind describes how to interpret Lane. 159fe6060f1SDimitry Andric enum class Kind : uint8_t { 160fe6060f1SDimitry Andric /// For First, Lane is the index into the first N elements of a 161fe6060f1SDimitry Andric /// fixed-vector <N x <ElTy>> or a scalable vector <vscale x N x <ElTy>>. 162fe6060f1SDimitry Andric First, 163fe6060f1SDimitry Andric /// For ScalableLast, Lane is the offset from the start of the last 164fe6060f1SDimitry Andric /// N-element subvector in a scalable vector <vscale x N x <ElTy>>. For 165fe6060f1SDimitry Andric /// example, a Lane of 0 corresponds to lane `(vscale - 1) * N`, a Lane of 166fe6060f1SDimitry Andric /// 1 corresponds to `((vscale - 1) * N) + 1`, etc. 167fe6060f1SDimitry Andric ScalableLast 168fe6060f1SDimitry Andric }; 169fe6060f1SDimitry Andric 170fe6060f1SDimitry Andric private: 171fe6060f1SDimitry Andric /// in [0..VF) 172fe6060f1SDimitry Andric unsigned Lane; 173fe6060f1SDimitry Andric 174fe6060f1SDimitry Andric /// Indicates how the Lane should be interpreted, as described above. 175fe6060f1SDimitry Andric Kind LaneKind; 176fe6060f1SDimitry Andric 177fe6060f1SDimitry Andric public: 178fe6060f1SDimitry Andric VPLane(unsigned Lane, Kind LaneKind) : Lane(Lane), LaneKind(LaneKind) {} 179fe6060f1SDimitry Andric 180fe6060f1SDimitry Andric static VPLane getFirstLane() { return VPLane(0, VPLane::Kind::First); } 181fe6060f1SDimitry Andric 182*0fca6ea1SDimitry Andric static VPLane getLaneFromEnd(const ElementCount &VF, unsigned Offset) { 183*0fca6ea1SDimitry Andric assert(Offset > 0 && Offset <= VF.getKnownMinValue() && 184*0fca6ea1SDimitry Andric "trying to extract with invalid offset"); 185*0fca6ea1SDimitry Andric unsigned LaneOffset = VF.getKnownMinValue() - Offset; 186fe6060f1SDimitry Andric Kind LaneKind; 187fe6060f1SDimitry Andric if (VF.isScalable()) 188fe6060f1SDimitry Andric // In this case 'LaneOffset' refers to the offset from the start of the 189fe6060f1SDimitry Andric // last subvector with VF.getKnownMinValue() elements. 190fe6060f1SDimitry Andric LaneKind = VPLane::Kind::ScalableLast; 191fe6060f1SDimitry Andric else 192fe6060f1SDimitry Andric LaneKind = VPLane::Kind::First; 193fe6060f1SDimitry Andric return VPLane(LaneOffset, LaneKind); 194fe6060f1SDimitry Andric } 195fe6060f1SDimitry Andric 196*0fca6ea1SDimitry Andric static VPLane getLastLaneForVF(const ElementCount &VF) { 197*0fca6ea1SDimitry Andric return getLaneFromEnd(VF, 1); 198*0fca6ea1SDimitry Andric } 199*0fca6ea1SDimitry Andric 200fe6060f1SDimitry Andric /// Returns a compile-time known value for the lane index and asserts if the 201fe6060f1SDimitry Andric /// lane can only be calculated at runtime. 202fe6060f1SDimitry Andric unsigned getKnownLane() const { 203fe6060f1SDimitry Andric assert(LaneKind == Kind::First); 204fe6060f1SDimitry Andric return Lane; 205fe6060f1SDimitry Andric } 206fe6060f1SDimitry Andric 207fe6060f1SDimitry Andric /// Returns an expression describing the lane index that can be used at 208fe6060f1SDimitry Andric /// runtime. 20981ad6265SDimitry Andric Value *getAsRuntimeExpr(IRBuilderBase &Builder, const ElementCount &VF) const; 210fe6060f1SDimitry Andric 211fe6060f1SDimitry Andric /// Returns the Kind of lane offset. 212fe6060f1SDimitry Andric Kind getKind() const { return LaneKind; } 213fe6060f1SDimitry Andric 214fe6060f1SDimitry Andric /// Returns true if this is the first lane of the whole vector. 215fe6060f1SDimitry Andric bool isFirstLane() const { return Lane == 0 && LaneKind == Kind::First; } 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric /// Maps the lane to a cache index based on \p VF. 218fe6060f1SDimitry Andric unsigned mapToCacheIndex(const ElementCount &VF) const { 219fe6060f1SDimitry Andric switch (LaneKind) { 220fe6060f1SDimitry Andric case VPLane::Kind::ScalableLast: 221fe6060f1SDimitry Andric assert(VF.isScalable() && Lane < VF.getKnownMinValue()); 222fe6060f1SDimitry Andric return VF.getKnownMinValue() + Lane; 223fe6060f1SDimitry Andric default: 224fe6060f1SDimitry Andric assert(Lane < VF.getKnownMinValue()); 225fe6060f1SDimitry Andric return Lane; 226fe6060f1SDimitry Andric } 227fe6060f1SDimitry Andric } 228fe6060f1SDimitry Andric 229fe6060f1SDimitry Andric /// Returns the maxmimum number of lanes that we are able to consider 230fe6060f1SDimitry Andric /// caching for \p VF. 231fe6060f1SDimitry Andric static unsigned getNumCachedLanes(const ElementCount &VF) { 232fe6060f1SDimitry Andric return VF.getKnownMinValue() * (VF.isScalable() ? 2 : 1); 233fe6060f1SDimitry Andric } 234fe6060f1SDimitry Andric }; 235fe6060f1SDimitry Andric 2360b57cec5SDimitry Andric /// VPIteration represents a single point in the iteration space of the output 2370b57cec5SDimitry Andric /// (vectorized and/or unrolled) IR loop. 2380b57cec5SDimitry Andric struct VPIteration { 2390b57cec5SDimitry Andric /// in [0..UF) 2400b57cec5SDimitry Andric unsigned Part; 2410b57cec5SDimitry Andric 242fe6060f1SDimitry Andric VPLane Lane; 2430b57cec5SDimitry Andric 244fe6060f1SDimitry Andric VPIteration(unsigned Part, unsigned Lane, 245fe6060f1SDimitry Andric VPLane::Kind Kind = VPLane::Kind::First) 246fe6060f1SDimitry Andric : Part(Part), Lane(Lane, Kind) {} 2470b57cec5SDimitry Andric 248fe6060f1SDimitry Andric VPIteration(unsigned Part, const VPLane &Lane) : Part(Part), Lane(Lane) {} 2490b57cec5SDimitry Andric 250fe6060f1SDimitry Andric bool isFirstIteration() const { return Part == 0 && Lane.isFirstLane(); } 2510b57cec5SDimitry Andric }; 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric /// VPTransformState holds information passed down when "executing" a VPlan, 2540b57cec5SDimitry Andric /// needed for generating the output IR. 2550b57cec5SDimitry Andric struct VPTransformState { 256fe6060f1SDimitry Andric VPTransformState(ElementCount VF, unsigned UF, LoopInfo *LI, 25781ad6265SDimitry Andric DominatorTree *DT, IRBuilderBase &Builder, 258*0fca6ea1SDimitry Andric InnerLoopVectorizer *ILV, VPlan *Plan, LLVMContext &Ctx); 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric /// The chosen Vectorization and Unroll Factors of the loop being vectorized. 261e8d8bef9SDimitry Andric ElementCount VF; 2620b57cec5SDimitry Andric unsigned UF; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric /// Hold the indices to generate specific scalar instructions. Null indicates 2650b57cec5SDimitry Andric /// that all instances are to be generated, using either scalar or vector 2660b57cec5SDimitry Andric /// instructions. 267bdd1243dSDimitry Andric std::optional<VPIteration> Instance; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric struct DataState { 2700b57cec5SDimitry Andric /// A type for vectorized values in the new loop. Each value from the 2710b57cec5SDimitry Andric /// original loop, when vectorized, is represented by UF vector values in 2720b57cec5SDimitry Andric /// the new unrolled loop, where UF is the unroll factor. 2730b57cec5SDimitry Andric typedef SmallVector<Value *, 2> PerPartValuesTy; 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric DenseMap<VPValue *, PerPartValuesTy> PerPartOutput; 276e8d8bef9SDimitry Andric 277e8d8bef9SDimitry Andric using ScalarsPerPartValuesTy = SmallVector<SmallVector<Value *, 4>, 2>; 278e8d8bef9SDimitry Andric DenseMap<VPValue *, ScalarsPerPartValuesTy> PerPartScalars; 2790b57cec5SDimitry Andric } Data; 2800b57cec5SDimitry Andric 281*0fca6ea1SDimitry Andric /// Get the generated vector Value for a given VPValue \p Def and a given \p 282*0fca6ea1SDimitry Andric /// Part if \p IsScalar is false, otherwise return the generated scalar 283*0fca6ea1SDimitry Andric /// for \p Part. \See set. 284*0fca6ea1SDimitry Andric Value *get(VPValue *Def, unsigned Part, bool IsScalar = false); 2850b57cec5SDimitry Andric 2865ffd83dbSDimitry Andric /// Get the generated Value for a given VPValue and given Part and Lane. 287e8d8bef9SDimitry Andric Value *get(VPValue *Def, const VPIteration &Instance); 288e8d8bef9SDimitry Andric 289e8d8bef9SDimitry Andric bool hasVectorValue(VPValue *Def, unsigned Part) { 290e8d8bef9SDimitry Andric auto I = Data.PerPartOutput.find(Def); 291e8d8bef9SDimitry Andric return I != Data.PerPartOutput.end() && Part < I->second.size() && 292e8d8bef9SDimitry Andric I->second[Part]; 2935ffd83dbSDimitry Andric } 2945ffd83dbSDimitry Andric 295e8d8bef9SDimitry Andric bool hasScalarValue(VPValue *Def, VPIteration Instance) { 296e8d8bef9SDimitry Andric auto I = Data.PerPartScalars.find(Def); 297e8d8bef9SDimitry Andric if (I == Data.PerPartScalars.end()) 298e8d8bef9SDimitry Andric return false; 299fe6060f1SDimitry Andric unsigned CacheIdx = Instance.Lane.mapToCacheIndex(VF); 300e8d8bef9SDimitry Andric return Instance.Part < I->second.size() && 301fe6060f1SDimitry Andric CacheIdx < I->second[Instance.Part].size() && 302fe6060f1SDimitry Andric I->second[Instance.Part][CacheIdx]; 303480093f4SDimitry Andric } 304480093f4SDimitry Andric 305*0fca6ea1SDimitry Andric /// Set the generated vector Value for a given VPValue and a given Part, if \p 306*0fca6ea1SDimitry Andric /// IsScalar is false. If \p IsScalar is true, set the scalar in (Part, 0). 307*0fca6ea1SDimitry Andric void set(VPValue *Def, Value *V, unsigned Part, bool IsScalar = false) { 308*0fca6ea1SDimitry Andric if (IsScalar) { 309*0fca6ea1SDimitry Andric set(Def, V, VPIteration(Part, 0)); 310*0fca6ea1SDimitry Andric return; 311*0fca6ea1SDimitry Andric } 312*0fca6ea1SDimitry Andric assert((VF.isScalar() || V->getType()->isVectorTy()) && 313*0fca6ea1SDimitry Andric "scalar values must be stored as (Part, 0)"); 3140b57cec5SDimitry Andric if (!Data.PerPartOutput.count(Def)) { 3150b57cec5SDimitry Andric DataState::PerPartValuesTy Entry(UF); 3160b57cec5SDimitry Andric Data.PerPartOutput[Def] = Entry; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric Data.PerPartOutput[Def][Part] = V; 3190b57cec5SDimitry Andric } 320*0fca6ea1SDimitry Andric 321fe6060f1SDimitry Andric /// Reset an existing vector value for \p Def and a given \p Part. 322fe6060f1SDimitry Andric void reset(VPValue *Def, Value *V, unsigned Part) { 323fe6060f1SDimitry Andric auto Iter = Data.PerPartOutput.find(Def); 324fe6060f1SDimitry Andric assert(Iter != Data.PerPartOutput.end() && 325fe6060f1SDimitry Andric "need to overwrite existing value"); 326fe6060f1SDimitry Andric Iter->second[Part] = V; 327fe6060f1SDimitry Andric } 328e8d8bef9SDimitry Andric 329fe6060f1SDimitry Andric /// Set the generated scalar \p V for \p Def and the given \p Instance. 330e8d8bef9SDimitry Andric void set(VPValue *Def, Value *V, const VPIteration &Instance) { 331e8d8bef9SDimitry Andric auto Iter = Data.PerPartScalars.insert({Def, {}}); 332e8d8bef9SDimitry Andric auto &PerPartVec = Iter.first->second; 333*0fca6ea1SDimitry Andric if (PerPartVec.size() <= Instance.Part) 334*0fca6ea1SDimitry Andric PerPartVec.resize(Instance.Part + 1); 335e8d8bef9SDimitry Andric auto &Scalars = PerPartVec[Instance.Part]; 336fe6060f1SDimitry Andric unsigned CacheIdx = Instance.Lane.mapToCacheIndex(VF); 337*0fca6ea1SDimitry Andric if (Scalars.size() <= CacheIdx) 338*0fca6ea1SDimitry Andric Scalars.resize(CacheIdx + 1); 339fe6060f1SDimitry Andric assert(!Scalars[CacheIdx] && "should overwrite existing value"); 340fe6060f1SDimitry Andric Scalars[CacheIdx] = V; 341fe6060f1SDimitry Andric } 342fe6060f1SDimitry Andric 343fe6060f1SDimitry Andric /// Reset an existing scalar value for \p Def and a given \p Instance. 344fe6060f1SDimitry Andric void reset(VPValue *Def, Value *V, const VPIteration &Instance) { 345fe6060f1SDimitry Andric auto Iter = Data.PerPartScalars.find(Def); 346fe6060f1SDimitry Andric assert(Iter != Data.PerPartScalars.end() && 347fe6060f1SDimitry Andric "need to overwrite existing value"); 348fe6060f1SDimitry Andric assert(Instance.Part < Iter->second.size() && 349fe6060f1SDimitry Andric "need to overwrite existing value"); 350fe6060f1SDimitry Andric unsigned CacheIdx = Instance.Lane.mapToCacheIndex(VF); 351fe6060f1SDimitry Andric assert(CacheIdx < Iter->second[Instance.Part].size() && 352fe6060f1SDimitry Andric "need to overwrite existing value"); 353fe6060f1SDimitry Andric Iter->second[Instance.Part][CacheIdx] = V; 354e8d8bef9SDimitry Andric } 3550b57cec5SDimitry Andric 35681ad6265SDimitry Andric /// Add additional metadata to \p To that was not present on \p Orig. 35781ad6265SDimitry Andric /// 35881ad6265SDimitry Andric /// Currently this is used to add the noalias annotations based on the 35981ad6265SDimitry Andric /// inserted memchecks. Use this for instructions that are *cloned* into the 36081ad6265SDimitry Andric /// vector loop. 36181ad6265SDimitry Andric void addNewMetadata(Instruction *To, const Instruction *Orig); 36281ad6265SDimitry Andric 36381ad6265SDimitry Andric /// Add metadata from one instruction to another. 36481ad6265SDimitry Andric /// 36581ad6265SDimitry Andric /// This includes both the original MDs from \p From and additional ones (\see 36681ad6265SDimitry Andric /// addNewMetadata). Use this for *newly created* instructions in the vector 36781ad6265SDimitry Andric /// loop. 368*0fca6ea1SDimitry Andric void addMetadata(Value *To, Instruction *From); 36981ad6265SDimitry Andric 3705f757f3fSDimitry Andric /// Set the debug location in the builder using the debug location \p DL. 3715f757f3fSDimitry Andric void setDebugLocFrom(DebugLoc DL); 3725f757f3fSDimitry Andric 3735f757f3fSDimitry Andric /// Construct the vector value of a scalarized value \p V one lane at a time. 3745f757f3fSDimitry Andric void packScalarIntoVectorValue(VPValue *Def, const VPIteration &Instance); 37581ad6265SDimitry Andric 3760b57cec5SDimitry Andric /// Hold state information used when constructing the CFG of the output IR, 3770b57cec5SDimitry Andric /// traversing the VPBasicBlocks and generating corresponding IR BasicBlocks. 3780b57cec5SDimitry Andric struct CFGState { 3790b57cec5SDimitry Andric /// The previous VPBasicBlock visited. Initially set to null. 3800b57cec5SDimitry Andric VPBasicBlock *PrevVPBB = nullptr; 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric /// The previous IR BasicBlock created or used. Initially set to the new 3830b57cec5SDimitry Andric /// header BasicBlock. 3840b57cec5SDimitry Andric BasicBlock *PrevBB = nullptr; 3850b57cec5SDimitry Andric 38681ad6265SDimitry Andric /// The last IR BasicBlock in the output IR. Set to the exit block of the 38781ad6265SDimitry Andric /// vector loop. 38881ad6265SDimitry Andric BasicBlock *ExitBB = nullptr; 389fe6060f1SDimitry Andric 3900b57cec5SDimitry Andric /// A mapping of each VPBasicBlock to the corresponding BasicBlock. In case 3910b57cec5SDimitry Andric /// of replication, maps the BasicBlock of the last replica created. 3920b57cec5SDimitry Andric SmallDenseMap<VPBasicBlock *, BasicBlock *> VPBB2IRBB; 3930b57cec5SDimitry Andric 394*0fca6ea1SDimitry Andric /// Updater for the DominatorTree. 395*0fca6ea1SDimitry Andric DomTreeUpdater DTU; 396*0fca6ea1SDimitry Andric 397*0fca6ea1SDimitry Andric CFGState(DominatorTree *DT) 398*0fca6ea1SDimitry Andric : DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy) {} 39981ad6265SDimitry Andric 40081ad6265SDimitry Andric /// Returns the BasicBlock* mapped to the pre-header of the loop region 40181ad6265SDimitry Andric /// containing \p R. 40281ad6265SDimitry Andric BasicBlock *getPreheaderBBFor(VPRecipeBase *R); 4030b57cec5SDimitry Andric } CFG; 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric /// Hold a pointer to LoopInfo to register new basic blocks in the loop. 4060b57cec5SDimitry Andric LoopInfo *LI; 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric /// Hold a reference to the IRBuilder used to generate output IR code. 40981ad6265SDimitry Andric IRBuilderBase &Builder; 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric /// Hold a pointer to InnerLoopVectorizer to reuse its IR generation methods. 4120b57cec5SDimitry Andric InnerLoopVectorizer *ILV; 4130b57cec5SDimitry Andric 414fe6060f1SDimitry Andric /// Pointer to the VPlan code is generated for. 415fe6060f1SDimitry Andric VPlan *Plan; 4164824e7fdSDimitry Andric 41781ad6265SDimitry Andric /// The loop object for the current parent region, or nullptr. 41881ad6265SDimitry Andric Loop *CurrentVectorLoop = nullptr; 419fe6060f1SDimitry Andric 42081ad6265SDimitry Andric /// LoopVersioning. It's only set up (non-null) if memchecks were 42181ad6265SDimitry Andric /// used. 42281ad6265SDimitry Andric /// 42381ad6265SDimitry Andric /// This is currently only used to add no-alias metadata based on the 42481ad6265SDimitry Andric /// memchecks. The actually versioning is performed manually. 42506c3fb27SDimitry Andric LoopVersioning *LVer = nullptr; 42606c3fb27SDimitry Andric 42706c3fb27SDimitry Andric /// Map SCEVs to their expanded values. Populated when executing 42806c3fb27SDimitry Andric /// VPExpandSCEVRecipes. 42906c3fb27SDimitry Andric DenseMap<const SCEV *, Value *> ExpandedSCEVs; 4305f757f3fSDimitry Andric 4315f757f3fSDimitry Andric /// VPlan-based type analysis. 4325f757f3fSDimitry Andric VPTypeAnalysis TypeAnalysis; 4330b57cec5SDimitry Andric }; 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric /// VPBlockBase is the building block of the Hierarchical Control-Flow Graph. 4360b57cec5SDimitry Andric /// A VPBlockBase can be either a VPBasicBlock or a VPRegionBlock. 4370b57cec5SDimitry Andric class VPBlockBase { 4380b57cec5SDimitry Andric friend class VPBlockUtils; 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric /// An optional name for the block. 4430b57cec5SDimitry Andric std::string Name; 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric /// The immediate VPRegionBlock which this VPBlockBase belongs to, or null if 4460b57cec5SDimitry Andric /// it is a topmost VPBlockBase. 4470b57cec5SDimitry Andric VPRegionBlock *Parent = nullptr; 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric /// List of predecessor blocks. 4500b57cec5SDimitry Andric SmallVector<VPBlockBase *, 1> Predecessors; 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric /// List of successor blocks. 4530b57cec5SDimitry Andric SmallVector<VPBlockBase *, 1> Successors; 4540b57cec5SDimitry Andric 4555ffd83dbSDimitry Andric /// VPlan containing the block. Can only be set on the entry block of the 4565ffd83dbSDimitry Andric /// plan. 4575ffd83dbSDimitry Andric VPlan *Plan = nullptr; 4585ffd83dbSDimitry Andric 4590b57cec5SDimitry Andric /// Add \p Successor as the last successor to this block. 4600b57cec5SDimitry Andric void appendSuccessor(VPBlockBase *Successor) { 4610b57cec5SDimitry Andric assert(Successor && "Cannot add nullptr successor!"); 4620b57cec5SDimitry Andric Successors.push_back(Successor); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric /// Add \p Predecessor as the last predecessor to this block. 4660b57cec5SDimitry Andric void appendPredecessor(VPBlockBase *Predecessor) { 4670b57cec5SDimitry Andric assert(Predecessor && "Cannot add nullptr predecessor!"); 4680b57cec5SDimitry Andric Predecessors.push_back(Predecessor); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric /// Remove \p Predecessor from the predecessors of this block. 4720b57cec5SDimitry Andric void removePredecessor(VPBlockBase *Predecessor) { 473e8d8bef9SDimitry Andric auto Pos = find(Predecessors, Predecessor); 4740b57cec5SDimitry Andric assert(Pos && "Predecessor does not exist"); 4750b57cec5SDimitry Andric Predecessors.erase(Pos); 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric /// Remove \p Successor from the successors of this block. 4790b57cec5SDimitry Andric void removeSuccessor(VPBlockBase *Successor) { 480e8d8bef9SDimitry Andric auto Pos = find(Successors, Successor); 4810b57cec5SDimitry Andric assert(Pos && "Successor does not exist"); 4820b57cec5SDimitry Andric Successors.erase(Pos); 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric protected: 4860b57cec5SDimitry Andric VPBlockBase(const unsigned char SC, const std::string &N) 4870b57cec5SDimitry Andric : SubclassID(SC), Name(N) {} 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric public: 4900b57cec5SDimitry Andric /// An enumeration for keeping track of the concrete subclass of VPBlockBase 4910b57cec5SDimitry Andric /// that are actually instantiated. Values of this enumeration are kept in the 4920b57cec5SDimitry Andric /// SubclassID field of the VPBlockBase objects. They are used for concrete 4930b57cec5SDimitry Andric /// type identification. 494*0fca6ea1SDimitry Andric using VPBlockTy = enum { VPRegionBlockSC, VPBasicBlockSC, VPIRBasicBlockSC }; 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric using VPBlocksTy = SmallVectorImpl<VPBlockBase *>; 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric virtual ~VPBlockBase() = default; 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric const std::string &getName() const { return Name; } 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric void setName(const Twine &newName) { Name = newName.str(); } 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric /// \return an ID for the concrete type of this object. 5050b57cec5SDimitry Andric /// This is used to implement the classof checks. This should not be used 5060b57cec5SDimitry Andric /// for any other purpose, as the values may change as LLVM evolves. 5070b57cec5SDimitry Andric unsigned getVPBlockID() const { return SubclassID; } 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric VPRegionBlock *getParent() { return Parent; } 5100b57cec5SDimitry Andric const VPRegionBlock *getParent() const { return Parent; } 5110b57cec5SDimitry Andric 5125ffd83dbSDimitry Andric /// \return A pointer to the plan containing the current block. 5135ffd83dbSDimitry Andric VPlan *getPlan(); 5145ffd83dbSDimitry Andric const VPlan *getPlan() const; 5155ffd83dbSDimitry Andric 5165ffd83dbSDimitry Andric /// Sets the pointer of the plan containing the block. The block must be the 5175ffd83dbSDimitry Andric /// entry block into the VPlan. 5185ffd83dbSDimitry Andric void setPlan(VPlan *ParentPlan); 5195ffd83dbSDimitry Andric 5200b57cec5SDimitry Andric void setParent(VPRegionBlock *P) { Parent = P; } 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric /// \return the VPBasicBlock that is the entry of this VPBlockBase, 5230b57cec5SDimitry Andric /// recursively, if the latter is a VPRegionBlock. Otherwise, if this 5240b57cec5SDimitry Andric /// VPBlockBase is a VPBasicBlock, it is returned. 5250b57cec5SDimitry Andric const VPBasicBlock *getEntryBasicBlock() const; 5260b57cec5SDimitry Andric VPBasicBlock *getEntryBasicBlock(); 5270b57cec5SDimitry Andric 52881ad6265SDimitry Andric /// \return the VPBasicBlock that is the exiting this VPBlockBase, 5290b57cec5SDimitry Andric /// recursively, if the latter is a VPRegionBlock. Otherwise, if this 5300b57cec5SDimitry Andric /// VPBlockBase is a VPBasicBlock, it is returned. 53181ad6265SDimitry Andric const VPBasicBlock *getExitingBasicBlock() const; 53281ad6265SDimitry Andric VPBasicBlock *getExitingBasicBlock(); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric const VPBlocksTy &getSuccessors() const { return Successors; } 5350b57cec5SDimitry Andric VPBlocksTy &getSuccessors() { return Successors; } 5360b57cec5SDimitry Andric 5370eae32dcSDimitry Andric iterator_range<VPBlockBase **> successors() { return Successors; } 5380eae32dcSDimitry Andric 5390b57cec5SDimitry Andric const VPBlocksTy &getPredecessors() const { return Predecessors; } 5400b57cec5SDimitry Andric VPBlocksTy &getPredecessors() { return Predecessors; } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric /// \return the successor of this VPBlockBase if it has a single successor. 5430b57cec5SDimitry Andric /// Otherwise return a null pointer. 5440b57cec5SDimitry Andric VPBlockBase *getSingleSuccessor() const { 5450b57cec5SDimitry Andric return (Successors.size() == 1 ? *Successors.begin() : nullptr); 5460b57cec5SDimitry Andric } 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric /// \return the predecessor of this VPBlockBase if it has a single 5490b57cec5SDimitry Andric /// predecessor. Otherwise return a null pointer. 5500b57cec5SDimitry Andric VPBlockBase *getSinglePredecessor() const { 5510b57cec5SDimitry Andric return (Predecessors.size() == 1 ? *Predecessors.begin() : nullptr); 5520b57cec5SDimitry Andric } 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric size_t getNumSuccessors() const { return Successors.size(); } 5550b57cec5SDimitry Andric size_t getNumPredecessors() const { return Predecessors.size(); } 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric /// An Enclosing Block of a block B is any block containing B, including B 5580b57cec5SDimitry Andric /// itself. \return the closest enclosing block starting from "this", which 5590b57cec5SDimitry Andric /// has successors. \return the root enclosing block if all enclosing blocks 5600b57cec5SDimitry Andric /// have no successors. 5610b57cec5SDimitry Andric VPBlockBase *getEnclosingBlockWithSuccessors(); 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric /// \return the closest enclosing block starting from "this", which has 5640b57cec5SDimitry Andric /// predecessors. \return the root enclosing block if all enclosing blocks 5650b57cec5SDimitry Andric /// have no predecessors. 5660b57cec5SDimitry Andric VPBlockBase *getEnclosingBlockWithPredecessors(); 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric /// \return the successors either attached directly to this VPBlockBase or, if 5690b57cec5SDimitry Andric /// this VPBlockBase is the exit block of a VPRegionBlock and has no 5700b57cec5SDimitry Andric /// successors of its own, search recursively for the first enclosing 5710b57cec5SDimitry Andric /// VPRegionBlock that has successors and return them. If no such 5720b57cec5SDimitry Andric /// VPRegionBlock exists, return the (empty) successors of the topmost 5730b57cec5SDimitry Andric /// VPBlockBase reached. 5740b57cec5SDimitry Andric const VPBlocksTy &getHierarchicalSuccessors() { 5750b57cec5SDimitry Andric return getEnclosingBlockWithSuccessors()->getSuccessors(); 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric /// \return the hierarchical successor of this VPBlockBase if it has a single 5790b57cec5SDimitry Andric /// hierarchical successor. Otherwise return a null pointer. 5800b57cec5SDimitry Andric VPBlockBase *getSingleHierarchicalSuccessor() { 5810b57cec5SDimitry Andric return getEnclosingBlockWithSuccessors()->getSingleSuccessor(); 5820b57cec5SDimitry Andric } 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric /// \return the predecessors either attached directly to this VPBlockBase or, 5850b57cec5SDimitry Andric /// if this VPBlockBase is the entry block of a VPRegionBlock and has no 5860b57cec5SDimitry Andric /// predecessors of its own, search recursively for the first enclosing 5870b57cec5SDimitry Andric /// VPRegionBlock that has predecessors and return them. If no such 5880b57cec5SDimitry Andric /// VPRegionBlock exists, return the (empty) predecessors of the topmost 5890b57cec5SDimitry Andric /// VPBlockBase reached. 5900b57cec5SDimitry Andric const VPBlocksTy &getHierarchicalPredecessors() { 5910b57cec5SDimitry Andric return getEnclosingBlockWithPredecessors()->getPredecessors(); 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric /// \return the hierarchical predecessor of this VPBlockBase if it has a 5950b57cec5SDimitry Andric /// single hierarchical predecessor. Otherwise return a null pointer. 5960b57cec5SDimitry Andric VPBlockBase *getSingleHierarchicalPredecessor() { 5970b57cec5SDimitry Andric return getEnclosingBlockWithPredecessors()->getSinglePredecessor(); 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric /// Set a given VPBlockBase \p Successor as the single successor of this 6010b57cec5SDimitry Andric /// VPBlockBase. This VPBlockBase is not added as predecessor of \p Successor. 6020b57cec5SDimitry Andric /// This VPBlockBase must have no successors. 6030b57cec5SDimitry Andric void setOneSuccessor(VPBlockBase *Successor) { 6040b57cec5SDimitry Andric assert(Successors.empty() && "Setting one successor when others exist."); 6055f757f3fSDimitry Andric assert(Successor->getParent() == getParent() && 6065f757f3fSDimitry Andric "connected blocks must have the same parent"); 6070b57cec5SDimitry Andric appendSuccessor(Successor); 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric /// Set two given VPBlockBases \p IfTrue and \p IfFalse to be the two 61181ad6265SDimitry Andric /// successors of this VPBlockBase. This VPBlockBase is not added as 61281ad6265SDimitry Andric /// predecessor of \p IfTrue or \p IfFalse. This VPBlockBase must have no 61381ad6265SDimitry Andric /// successors. 61481ad6265SDimitry Andric void setTwoSuccessors(VPBlockBase *IfTrue, VPBlockBase *IfFalse) { 6150b57cec5SDimitry Andric assert(Successors.empty() && "Setting two successors when others exist."); 6160b57cec5SDimitry Andric appendSuccessor(IfTrue); 6170b57cec5SDimitry Andric appendSuccessor(IfFalse); 6180b57cec5SDimitry Andric } 6190b57cec5SDimitry Andric 6200b57cec5SDimitry Andric /// Set each VPBasicBlock in \p NewPreds as predecessor of this VPBlockBase. 6210b57cec5SDimitry Andric /// This VPBlockBase must have no predecessors. This VPBlockBase is not added 6220b57cec5SDimitry Andric /// as successor of any VPBasicBlock in \p NewPreds. 6230b57cec5SDimitry Andric void setPredecessors(ArrayRef<VPBlockBase *> NewPreds) { 6240b57cec5SDimitry Andric assert(Predecessors.empty() && "Block predecessors already set."); 6250b57cec5SDimitry Andric for (auto *Pred : NewPreds) 6260b57cec5SDimitry Andric appendPredecessor(Pred); 6270b57cec5SDimitry Andric } 6280b57cec5SDimitry Andric 629*0fca6ea1SDimitry Andric /// Set each VPBasicBlock in \p NewSuccss as successor of this VPBlockBase. 630*0fca6ea1SDimitry Andric /// This VPBlockBase must have no successors. This VPBlockBase is not added 631*0fca6ea1SDimitry Andric /// as predecessor of any VPBasicBlock in \p NewSuccs. 632*0fca6ea1SDimitry Andric void setSuccessors(ArrayRef<VPBlockBase *> NewSuccs) { 633*0fca6ea1SDimitry Andric assert(Successors.empty() && "Block successors already set."); 634*0fca6ea1SDimitry Andric for (auto *Succ : NewSuccs) 635*0fca6ea1SDimitry Andric appendSuccessor(Succ); 636*0fca6ea1SDimitry Andric } 637*0fca6ea1SDimitry Andric 6380b57cec5SDimitry Andric /// Remove all the predecessor of this block. 6390b57cec5SDimitry Andric void clearPredecessors() { Predecessors.clear(); } 6400b57cec5SDimitry Andric 64181ad6265SDimitry Andric /// Remove all the successors of this block. 64281ad6265SDimitry Andric void clearSuccessors() { Successors.clear(); } 6430b57cec5SDimitry Andric 6440b57cec5SDimitry Andric /// The method which generates the output IR that correspond to this 6450b57cec5SDimitry Andric /// VPBlockBase, thereby "executing" the VPlan. 646bdd1243dSDimitry Andric virtual void execute(VPTransformState *State) = 0; 6470b57cec5SDimitry Andric 648*0fca6ea1SDimitry Andric /// Return the cost of the block. 649*0fca6ea1SDimitry Andric virtual InstructionCost cost(ElementCount VF, VPCostContext &Ctx) = 0; 650*0fca6ea1SDimitry Andric 6510b57cec5SDimitry Andric /// Delete all blocks reachable from a given VPBlockBase, inclusive. 6520b57cec5SDimitry Andric static void deleteCFG(VPBlockBase *Entry); 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric /// Return true if it is legal to hoist instructions into this block. 6550b57cec5SDimitry Andric bool isLegalToHoistInto() { 6560b57cec5SDimitry Andric // There are currently no constraints that prevent an instruction to be 6570b57cec5SDimitry Andric // hoisted into a VPBlockBase. 6580b57cec5SDimitry Andric return true; 6590b57cec5SDimitry Andric } 660e8d8bef9SDimitry Andric 661e8d8bef9SDimitry Andric /// Replace all operands of VPUsers in the block with \p NewValue and also 662e8d8bef9SDimitry Andric /// replaces all uses of VPValues defined in the block with NewValue. 663e8d8bef9SDimitry Andric virtual void dropAllReferences(VPValue *NewValue) = 0; 664fe6060f1SDimitry Andric 665fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 666fe6060f1SDimitry Andric void printAsOperand(raw_ostream &OS, bool PrintType) const { 667fe6060f1SDimitry Andric OS << getName(); 668fe6060f1SDimitry Andric } 669fe6060f1SDimitry Andric 670fe6060f1SDimitry Andric /// Print plain-text dump of this VPBlockBase to \p O, prefixing all lines 671fe6060f1SDimitry Andric /// with \p Indent. \p SlotTracker is used to print unnamed VPValue's using 672fe6060f1SDimitry Andric /// consequtive numbers. 673fe6060f1SDimitry Andric /// 674fe6060f1SDimitry Andric /// Note that the numbering is applied to the whole VPlan, so printing 675fe6060f1SDimitry Andric /// individual blocks is consistent with the whole VPlan printing. 676fe6060f1SDimitry Andric virtual void print(raw_ostream &O, const Twine &Indent, 677fe6060f1SDimitry Andric VPSlotTracker &SlotTracker) const = 0; 678fe6060f1SDimitry Andric 679fe6060f1SDimitry Andric /// Print plain-text dump of this VPlan to \p O. 680fe6060f1SDimitry Andric void print(raw_ostream &O) const { 681fe6060f1SDimitry Andric VPSlotTracker SlotTracker(getPlan()); 682fe6060f1SDimitry Andric print(O, "", SlotTracker); 683fe6060f1SDimitry Andric } 684fe6060f1SDimitry Andric 685fe6060f1SDimitry Andric /// Print the successors of this block to \p O, prefixing all lines with \p 686fe6060f1SDimitry Andric /// Indent. 687fe6060f1SDimitry Andric void printSuccessors(raw_ostream &O, const Twine &Indent) const; 688fe6060f1SDimitry Andric 689fe6060f1SDimitry Andric /// Dump this VPBlockBase to dbgs(). 690fe6060f1SDimitry Andric LLVM_DUMP_METHOD void dump() const { print(dbgs()); } 691fe6060f1SDimitry Andric #endif 692*0fca6ea1SDimitry Andric 693*0fca6ea1SDimitry Andric /// Clone the current block and it's recipes without updating the operands of 694*0fca6ea1SDimitry Andric /// the cloned recipes, including all blocks in the single-entry single-exit 695*0fca6ea1SDimitry Andric /// region for VPRegionBlocks. 696*0fca6ea1SDimitry Andric virtual VPBlockBase *clone() = 0; 6970b57cec5SDimitry Andric }; 6980b57cec5SDimitry Andric 69981ad6265SDimitry Andric /// A value that is used outside the VPlan. The operand of the user needs to be 700*0fca6ea1SDimitry Andric /// added to the associated phi node. The incoming block from VPlan is 701*0fca6ea1SDimitry Andric /// determined by where the VPValue is defined: if it is defined by a recipe 702*0fca6ea1SDimitry Andric /// outside a region, its parent block is used, otherwise the middle block is 703*0fca6ea1SDimitry Andric /// used. 70481ad6265SDimitry Andric class VPLiveOut : public VPUser { 70581ad6265SDimitry Andric PHINode *Phi; 70681ad6265SDimitry Andric 70781ad6265SDimitry Andric public: 70881ad6265SDimitry Andric VPLiveOut(PHINode *Phi, VPValue *Op) 70981ad6265SDimitry Andric : VPUser({Op}, VPUser::VPUserID::LiveOut), Phi(Phi) {} 71081ad6265SDimitry Andric 71106c3fb27SDimitry Andric static inline bool classof(const VPUser *U) { 71206c3fb27SDimitry Andric return U->getVPUserID() == VPUser::VPUserID::LiveOut; 71306c3fb27SDimitry Andric } 71406c3fb27SDimitry Andric 715*0fca6ea1SDimitry Andric /// Fix the wrapped phi node. This means adding an incoming value to exit 716*0fca6ea1SDimitry Andric /// block phi's from the vector loop via middle block (values from scalar loop 717*0fca6ea1SDimitry Andric /// already reach these phi's), and updating the value to scalar header phi's 718*0fca6ea1SDimitry Andric /// from the scalar preheader. 71981ad6265SDimitry Andric void fixPhi(VPlan &Plan, VPTransformState &State); 72081ad6265SDimitry Andric 72181ad6265SDimitry Andric /// Returns true if the VPLiveOut uses scalars of operand \p Op. 72281ad6265SDimitry Andric bool usesScalars(const VPValue *Op) const override { 72381ad6265SDimitry Andric assert(is_contained(operands(), Op) && 72481ad6265SDimitry Andric "Op must be an operand of the recipe"); 72581ad6265SDimitry Andric return true; 72681ad6265SDimitry Andric } 72781ad6265SDimitry Andric 72881ad6265SDimitry Andric PHINode *getPhi() const { return Phi; } 72906c3fb27SDimitry Andric 73006c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 73106c3fb27SDimitry Andric /// Print the VPLiveOut to \p O. 73206c3fb27SDimitry Andric void print(raw_ostream &O, VPSlotTracker &SlotTracker) const; 73306c3fb27SDimitry Andric #endif 73481ad6265SDimitry Andric }; 73581ad6265SDimitry Andric 736*0fca6ea1SDimitry Andric /// Struct to hold various analysis needed for cost computations. 737*0fca6ea1SDimitry Andric struct VPCostContext { 738*0fca6ea1SDimitry Andric const TargetTransformInfo &TTI; 739*0fca6ea1SDimitry Andric VPTypeAnalysis Types; 740*0fca6ea1SDimitry Andric LLVMContext &LLVMCtx; 741*0fca6ea1SDimitry Andric LoopVectorizationCostModel &CM; 742*0fca6ea1SDimitry Andric SmallPtrSet<Instruction *, 8> SkipCostComputation; 743*0fca6ea1SDimitry Andric 744*0fca6ea1SDimitry Andric VPCostContext(const TargetTransformInfo &TTI, Type *CanIVTy, 745*0fca6ea1SDimitry Andric LLVMContext &LLVMCtx, LoopVectorizationCostModel &CM) 746*0fca6ea1SDimitry Andric : TTI(TTI), Types(CanIVTy, LLVMCtx), LLVMCtx(LLVMCtx), CM(CM) {} 747*0fca6ea1SDimitry Andric 748*0fca6ea1SDimitry Andric /// Return the cost for \p UI with \p VF using the legacy cost model as 749*0fca6ea1SDimitry Andric /// fallback until computing the cost of all recipes migrates to VPlan. 750*0fca6ea1SDimitry Andric InstructionCost getLegacyCost(Instruction *UI, ElementCount VF) const; 751*0fca6ea1SDimitry Andric 752*0fca6ea1SDimitry Andric /// Return true if the cost for \p UI shouldn't be computed, e.g. because it 753*0fca6ea1SDimitry Andric /// has already been pre-computed. 754*0fca6ea1SDimitry Andric bool skipCostComputation(Instruction *UI, bool IsVector) const; 755*0fca6ea1SDimitry Andric }; 756*0fca6ea1SDimitry Andric 7570b57cec5SDimitry Andric /// VPRecipeBase is a base class modeling a sequence of one or more output IR 7585f757f3fSDimitry Andric /// instructions. VPRecipeBase owns the VPValues it defines through VPDef 759e8d8bef9SDimitry Andric /// and is responsible for deleting its defined values. Single-value 7607a6dacacSDimitry Andric /// recipes must inherit from VPSingleDef instead of inheriting from both 7617a6dacacSDimitry Andric /// VPRecipeBase and VPValue separately. 762e8d8bef9SDimitry Andric class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>, 763fe6060f1SDimitry Andric public VPDef, 764fe6060f1SDimitry Andric public VPUser { 7650b57cec5SDimitry Andric friend VPBasicBlock; 766480093f4SDimitry Andric friend class VPBlockUtils; 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric /// Each VPRecipe belongs to a single VPBasicBlock. 7690b57cec5SDimitry Andric VPBasicBlock *Parent = nullptr; 7700b57cec5SDimitry Andric 7715f757f3fSDimitry Andric /// The debug location for the recipe. 7725f757f3fSDimitry Andric DebugLoc DL; 7735f757f3fSDimitry Andric 7740b57cec5SDimitry Andric public: 7755f757f3fSDimitry Andric VPRecipeBase(const unsigned char SC, ArrayRef<VPValue *> Operands, 7765f757f3fSDimitry Andric DebugLoc DL = {}) 7775f757f3fSDimitry Andric : VPDef(SC), VPUser(Operands, VPUser::VPUserID::Recipe), DL(DL) {} 778fe6060f1SDimitry Andric 779fe6060f1SDimitry Andric template <typename IterT> 7805f757f3fSDimitry Andric VPRecipeBase(const unsigned char SC, iterator_range<IterT> Operands, 7815f757f3fSDimitry Andric DebugLoc DL = {}) 7825f757f3fSDimitry Andric : VPDef(SC), VPUser(Operands, VPUser::VPUserID::Recipe), DL(DL) {} 7830b57cec5SDimitry Andric virtual ~VPRecipeBase() = default; 7840b57cec5SDimitry Andric 785*0fca6ea1SDimitry Andric /// Clone the current recipe. 786*0fca6ea1SDimitry Andric virtual VPRecipeBase *clone() = 0; 787*0fca6ea1SDimitry Andric 7880b57cec5SDimitry Andric /// \return the VPBasicBlock which this VPRecipe belongs to. 7890b57cec5SDimitry Andric VPBasicBlock *getParent() { return Parent; } 7900b57cec5SDimitry Andric const VPBasicBlock *getParent() const { return Parent; } 7910b57cec5SDimitry Andric 7920b57cec5SDimitry Andric /// The method which generates the output IR instructions that correspond to 7930b57cec5SDimitry Andric /// this VPRecipe, thereby "executing" the VPlan. 794bdd1243dSDimitry Andric virtual void execute(VPTransformState &State) = 0; 7950b57cec5SDimitry Andric 796*0fca6ea1SDimitry Andric /// Return the cost of this recipe, taking into account if the cost 797*0fca6ea1SDimitry Andric /// computation should be skipped and the ForceTargetInstructionCost flag. 798*0fca6ea1SDimitry Andric /// Also takes care of printing the cost for debugging. 799*0fca6ea1SDimitry Andric virtual InstructionCost cost(ElementCount VF, VPCostContext &Ctx); 800*0fca6ea1SDimitry Andric 8010b57cec5SDimitry Andric /// Insert an unlinked recipe into a basic block immediately before 8020b57cec5SDimitry Andric /// the specified recipe. 8030b57cec5SDimitry Andric void insertBefore(VPRecipeBase *InsertPos); 80481ad6265SDimitry Andric /// Insert an unlinked recipe into \p BB immediately before the insertion 80581ad6265SDimitry Andric /// point \p IP; 80681ad6265SDimitry Andric void insertBefore(VPBasicBlock &BB, iplist<VPRecipeBase>::iterator IP); 8070b57cec5SDimitry Andric 808480093f4SDimitry Andric /// Insert an unlinked Recipe into a basic block immediately after 809480093f4SDimitry Andric /// the specified Recipe. 810480093f4SDimitry Andric void insertAfter(VPRecipeBase *InsertPos); 811480093f4SDimitry Andric 8128bcb0991SDimitry Andric /// Unlink this recipe from its current VPBasicBlock and insert it into 8138bcb0991SDimitry Andric /// the VPBasicBlock that MovePos lives in, right after MovePos. 8148bcb0991SDimitry Andric void moveAfter(VPRecipeBase *MovePos); 8158bcb0991SDimitry Andric 816e8d8bef9SDimitry Andric /// Unlink this recipe and insert into BB before I. 817e8d8bef9SDimitry Andric /// 818e8d8bef9SDimitry Andric /// \pre I is a valid iterator into BB. 819e8d8bef9SDimitry Andric void moveBefore(VPBasicBlock &BB, iplist<VPRecipeBase>::iterator I); 820e8d8bef9SDimitry Andric 821480093f4SDimitry Andric /// This method unlinks 'this' from the containing basic block, but does not 822480093f4SDimitry Andric /// delete it. 823480093f4SDimitry Andric void removeFromParent(); 824480093f4SDimitry Andric 8250b57cec5SDimitry Andric /// This method unlinks 'this' from the containing basic block and deletes it. 8260b57cec5SDimitry Andric /// 8270b57cec5SDimitry Andric /// \returns an iterator pointing to the element after the erased one 8280b57cec5SDimitry Andric iplist<VPRecipeBase>::iterator eraseFromParent(); 829e8d8bef9SDimitry Andric 830e8d8bef9SDimitry Andric /// Method to support type inquiry through isa, cast, and dyn_cast. 831e8d8bef9SDimitry Andric static inline bool classof(const VPDef *D) { 832e8d8bef9SDimitry Andric // All VPDefs are also VPRecipeBases. 833e8d8bef9SDimitry Andric return true; 834e8d8bef9SDimitry Andric } 835fe6060f1SDimitry Andric 836fe6060f1SDimitry Andric static inline bool classof(const VPUser *U) { 837fe6060f1SDimitry Andric return U->getVPUserID() == VPUser::VPUserID::Recipe; 838fe6060f1SDimitry Andric } 839fe6060f1SDimitry Andric 840fe6060f1SDimitry Andric /// Returns true if the recipe may have side-effects. 841fe6060f1SDimitry Andric bool mayHaveSideEffects() const; 842fe6060f1SDimitry Andric 843fe6060f1SDimitry Andric /// Returns true for PHI-like recipes. 844fe6060f1SDimitry Andric bool isPhi() const { 845fe6060f1SDimitry Andric return getVPDefID() >= VPFirstPHISC && getVPDefID() <= VPLastPHISC; 846fe6060f1SDimitry Andric } 847fe6060f1SDimitry Andric 848fe6060f1SDimitry Andric /// Returns true if the recipe may read from memory. 849fe6060f1SDimitry Andric bool mayReadFromMemory() const; 850fe6060f1SDimitry Andric 851fe6060f1SDimitry Andric /// Returns true if the recipe may write to memory. 852fe6060f1SDimitry Andric bool mayWriteToMemory() const; 853fe6060f1SDimitry Andric 854fe6060f1SDimitry Andric /// Returns true if the recipe may read from or write to memory. 855fe6060f1SDimitry Andric bool mayReadOrWriteMemory() const { 856fe6060f1SDimitry Andric return mayReadFromMemory() || mayWriteToMemory(); 857fe6060f1SDimitry Andric } 8585f757f3fSDimitry Andric 8595f757f3fSDimitry Andric /// Returns the debug location of the recipe. 8605f757f3fSDimitry Andric DebugLoc getDebugLoc() const { return DL; } 861*0fca6ea1SDimitry Andric 862*0fca6ea1SDimitry Andric protected: 863*0fca6ea1SDimitry Andric /// Compute the cost of this recipe using the legacy cost model and the 864*0fca6ea1SDimitry Andric /// underlying instructions. 865*0fca6ea1SDimitry Andric InstructionCost computeCost(ElementCount VF, VPCostContext &Ctx) const; 8660b57cec5SDimitry Andric }; 8670b57cec5SDimitry Andric 868bdd1243dSDimitry Andric // Helper macro to define common classof implementations for recipes. 869bdd1243dSDimitry Andric #define VP_CLASSOF_IMPL(VPDefID) \ 870bdd1243dSDimitry Andric static inline bool classof(const VPDef *D) { \ 871bdd1243dSDimitry Andric return D->getVPDefID() == VPDefID; \ 872bdd1243dSDimitry Andric } \ 873bdd1243dSDimitry Andric static inline bool classof(const VPValue *V) { \ 874bdd1243dSDimitry Andric auto *R = V->getDefiningRecipe(); \ 875bdd1243dSDimitry Andric return R && R->getVPDefID() == VPDefID; \ 876bdd1243dSDimitry Andric } \ 877bdd1243dSDimitry Andric static inline bool classof(const VPUser *U) { \ 878bdd1243dSDimitry Andric auto *R = dyn_cast<VPRecipeBase>(U); \ 879bdd1243dSDimitry Andric return R && R->getVPDefID() == VPDefID; \ 880bdd1243dSDimitry Andric } \ 881bdd1243dSDimitry Andric static inline bool classof(const VPRecipeBase *R) { \ 882bdd1243dSDimitry Andric return R->getVPDefID() == VPDefID; \ 8837a6dacacSDimitry Andric } \ 8847a6dacacSDimitry Andric static inline bool classof(const VPSingleDefRecipe *R) { \ 8857a6dacacSDimitry Andric return R->getVPDefID() == VPDefID; \ 886e8d8bef9SDimitry Andric } 887e8d8bef9SDimitry Andric 8887a6dacacSDimitry Andric /// VPSingleDef is a base class for recipes for modeling a sequence of one or 8897a6dacacSDimitry Andric /// more output IR that define a single result VPValue. 8907a6dacacSDimitry Andric /// Note that VPRecipeBase must be inherited from before VPValue. 8917a6dacacSDimitry Andric class VPSingleDefRecipe : public VPRecipeBase, public VPValue { 8927a6dacacSDimitry Andric public: 8937a6dacacSDimitry Andric template <typename IterT> 8947a6dacacSDimitry Andric VPSingleDefRecipe(const unsigned char SC, IterT Operands, DebugLoc DL = {}) 8957a6dacacSDimitry Andric : VPRecipeBase(SC, Operands, DL), VPValue(this) {} 8967a6dacacSDimitry Andric 8977a6dacacSDimitry Andric VPSingleDefRecipe(const unsigned char SC, ArrayRef<VPValue *> Operands, 8987a6dacacSDimitry Andric DebugLoc DL = {}) 8997a6dacacSDimitry Andric : VPRecipeBase(SC, Operands, DL), VPValue(this) {} 9007a6dacacSDimitry Andric 9017a6dacacSDimitry Andric template <typename IterT> 9027a6dacacSDimitry Andric VPSingleDefRecipe(const unsigned char SC, IterT Operands, Value *UV, 9037a6dacacSDimitry Andric DebugLoc DL = {}) 9047a6dacacSDimitry Andric : VPRecipeBase(SC, Operands, DL), VPValue(this, UV) {} 9057a6dacacSDimitry Andric 9067a6dacacSDimitry Andric static inline bool classof(const VPRecipeBase *R) { 9077a6dacacSDimitry Andric switch (R->getVPDefID()) { 9087a6dacacSDimitry Andric case VPRecipeBase::VPDerivedIVSC: 909*0fca6ea1SDimitry Andric case VPRecipeBase::VPEVLBasedIVPHISC: 9107a6dacacSDimitry Andric case VPRecipeBase::VPExpandSCEVSC: 9117a6dacacSDimitry Andric case VPRecipeBase::VPInstructionSC: 912*0fca6ea1SDimitry Andric case VPRecipeBase::VPReductionEVLSC: 9137a6dacacSDimitry Andric case VPRecipeBase::VPReductionSC: 9147a6dacacSDimitry Andric case VPRecipeBase::VPReplicateSC: 9157a6dacacSDimitry Andric case VPRecipeBase::VPScalarIVStepsSC: 9167a6dacacSDimitry Andric case VPRecipeBase::VPVectorPointerSC: 9177a6dacacSDimitry Andric case VPRecipeBase::VPWidenCallSC: 9187a6dacacSDimitry Andric case VPRecipeBase::VPWidenCanonicalIVSC: 9197a6dacacSDimitry Andric case VPRecipeBase::VPWidenCastSC: 9207a6dacacSDimitry Andric case VPRecipeBase::VPWidenGEPSC: 9217a6dacacSDimitry Andric case VPRecipeBase::VPWidenSC: 9227a6dacacSDimitry Andric case VPRecipeBase::VPWidenSelectSC: 9237a6dacacSDimitry Andric case VPRecipeBase::VPBlendSC: 9247a6dacacSDimitry Andric case VPRecipeBase::VPPredInstPHISC: 9257a6dacacSDimitry Andric case VPRecipeBase::VPCanonicalIVPHISC: 9267a6dacacSDimitry Andric case VPRecipeBase::VPActiveLaneMaskPHISC: 9277a6dacacSDimitry Andric case VPRecipeBase::VPFirstOrderRecurrencePHISC: 9287a6dacacSDimitry Andric case VPRecipeBase::VPWidenPHISC: 9297a6dacacSDimitry Andric case VPRecipeBase::VPWidenIntOrFpInductionSC: 9307a6dacacSDimitry Andric case VPRecipeBase::VPWidenPointerInductionSC: 9317a6dacacSDimitry Andric case VPRecipeBase::VPReductionPHISC: 932*0fca6ea1SDimitry Andric case VPRecipeBase::VPScalarCastSC: 9337a6dacacSDimitry Andric return true; 9347a6dacacSDimitry Andric case VPRecipeBase::VPInterleaveSC: 9357a6dacacSDimitry Andric case VPRecipeBase::VPBranchOnMaskSC: 936*0fca6ea1SDimitry Andric case VPRecipeBase::VPWidenLoadEVLSC: 937*0fca6ea1SDimitry Andric case VPRecipeBase::VPWidenLoadSC: 938*0fca6ea1SDimitry Andric case VPRecipeBase::VPWidenStoreEVLSC: 939*0fca6ea1SDimitry Andric case VPRecipeBase::VPWidenStoreSC: 9407a6dacacSDimitry Andric // TODO: Widened stores don't define a value, but widened loads do. Split 9417a6dacacSDimitry Andric // the recipes to be able to make widened loads VPSingleDefRecipes. 9427a6dacacSDimitry Andric return false; 9437a6dacacSDimitry Andric } 9447a6dacacSDimitry Andric llvm_unreachable("Unhandled VPDefID"); 9457a6dacacSDimitry Andric } 9467a6dacacSDimitry Andric 9477a6dacacSDimitry Andric static inline bool classof(const VPUser *U) { 9487a6dacacSDimitry Andric auto *R = dyn_cast<VPRecipeBase>(U); 9497a6dacacSDimitry Andric return R && classof(R); 9507a6dacacSDimitry Andric } 9517a6dacacSDimitry Andric 952*0fca6ea1SDimitry Andric virtual VPSingleDefRecipe *clone() override = 0; 953*0fca6ea1SDimitry Andric 9547a6dacacSDimitry Andric /// Returns the underlying instruction. 9557a6dacacSDimitry Andric Instruction *getUnderlyingInstr() { 9567a6dacacSDimitry Andric return cast<Instruction>(getUnderlyingValue()); 9577a6dacacSDimitry Andric } 9587a6dacacSDimitry Andric const Instruction *getUnderlyingInstr() const { 9597a6dacacSDimitry Andric return cast<Instruction>(getUnderlyingValue()); 9607a6dacacSDimitry Andric } 9617a6dacacSDimitry Andric }; 9627a6dacacSDimitry Andric 9635f757f3fSDimitry Andric /// Class to record LLVM IR flag for a recipe along with it. 9647a6dacacSDimitry Andric class VPRecipeWithIRFlags : public VPSingleDefRecipe { 9655f757f3fSDimitry Andric enum class OperationType : unsigned char { 9665f757f3fSDimitry Andric Cmp, 9675f757f3fSDimitry Andric OverflowingBinOp, 9685f757f3fSDimitry Andric DisjointOp, 9695f757f3fSDimitry Andric PossiblyExactOp, 9705f757f3fSDimitry Andric GEPOp, 9715f757f3fSDimitry Andric FPMathOp, 9725f757f3fSDimitry Andric NonNegOp, 9735f757f3fSDimitry Andric Other 9745f757f3fSDimitry Andric }; 9755f757f3fSDimitry Andric 9765f757f3fSDimitry Andric public: 9775f757f3fSDimitry Andric struct WrapFlagsTy { 9785f757f3fSDimitry Andric char HasNUW : 1; 9795f757f3fSDimitry Andric char HasNSW : 1; 9805f757f3fSDimitry Andric 9815f757f3fSDimitry Andric WrapFlagsTy(bool HasNUW, bool HasNSW) : HasNUW(HasNUW), HasNSW(HasNSW) {} 9825f757f3fSDimitry Andric }; 9835f757f3fSDimitry Andric 984*0fca6ea1SDimitry Andric struct DisjointFlagsTy { 985*0fca6ea1SDimitry Andric char IsDisjoint : 1; 986*0fca6ea1SDimitry Andric DisjointFlagsTy(bool IsDisjoint) : IsDisjoint(IsDisjoint) {} 987*0fca6ea1SDimitry Andric }; 988*0fca6ea1SDimitry Andric 9891db9f3b2SDimitry Andric protected: 9901db9f3b2SDimitry Andric struct GEPFlagsTy { 9911db9f3b2SDimitry Andric char IsInBounds : 1; 9921db9f3b2SDimitry Andric GEPFlagsTy(bool IsInBounds) : IsInBounds(IsInBounds) {} 9931db9f3b2SDimitry Andric }; 9941db9f3b2SDimitry Andric 9955f757f3fSDimitry Andric private: 9965f757f3fSDimitry Andric struct ExactFlagsTy { 9975f757f3fSDimitry Andric char IsExact : 1; 9985f757f3fSDimitry Andric }; 9995f757f3fSDimitry Andric struct NonNegFlagsTy { 10005f757f3fSDimitry Andric char NonNeg : 1; 10015f757f3fSDimitry Andric }; 10025f757f3fSDimitry Andric struct FastMathFlagsTy { 10035f757f3fSDimitry Andric char AllowReassoc : 1; 10045f757f3fSDimitry Andric char NoNaNs : 1; 10055f757f3fSDimitry Andric char NoInfs : 1; 10065f757f3fSDimitry Andric char NoSignedZeros : 1; 10075f757f3fSDimitry Andric char AllowReciprocal : 1; 10085f757f3fSDimitry Andric char AllowContract : 1; 10095f757f3fSDimitry Andric char ApproxFunc : 1; 10105f757f3fSDimitry Andric 10115f757f3fSDimitry Andric FastMathFlagsTy(const FastMathFlags &FMF); 10125f757f3fSDimitry Andric }; 10135f757f3fSDimitry Andric 10145f757f3fSDimitry Andric OperationType OpType; 10155f757f3fSDimitry Andric 10165f757f3fSDimitry Andric union { 10175f757f3fSDimitry Andric CmpInst::Predicate CmpPredicate; 10185f757f3fSDimitry Andric WrapFlagsTy WrapFlags; 10195f757f3fSDimitry Andric DisjointFlagsTy DisjointFlags; 10205f757f3fSDimitry Andric ExactFlagsTy ExactFlags; 10215f757f3fSDimitry Andric GEPFlagsTy GEPFlags; 10225f757f3fSDimitry Andric NonNegFlagsTy NonNegFlags; 10235f757f3fSDimitry Andric FastMathFlagsTy FMFs; 10245f757f3fSDimitry Andric unsigned AllFlags; 10255f757f3fSDimitry Andric }; 10265f757f3fSDimitry Andric 1027*0fca6ea1SDimitry Andric protected: 1028*0fca6ea1SDimitry Andric void transferFlags(VPRecipeWithIRFlags &Other) { 1029*0fca6ea1SDimitry Andric OpType = Other.OpType; 1030*0fca6ea1SDimitry Andric AllFlags = Other.AllFlags; 1031*0fca6ea1SDimitry Andric } 1032*0fca6ea1SDimitry Andric 10335f757f3fSDimitry Andric public: 10345f757f3fSDimitry Andric template <typename IterT> 10355f757f3fSDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, DebugLoc DL = {}) 10367a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, DL) { 10375f757f3fSDimitry Andric OpType = OperationType::Other; 10385f757f3fSDimitry Andric AllFlags = 0; 10395f757f3fSDimitry Andric } 10405f757f3fSDimitry Andric 10415f757f3fSDimitry Andric template <typename IterT> 10425f757f3fSDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, Instruction &I) 10437a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, &I, I.getDebugLoc()) { 10445f757f3fSDimitry Andric if (auto *Op = dyn_cast<CmpInst>(&I)) { 10455f757f3fSDimitry Andric OpType = OperationType::Cmp; 10465f757f3fSDimitry Andric CmpPredicate = Op->getPredicate(); 10475f757f3fSDimitry Andric } else if (auto *Op = dyn_cast<PossiblyDisjointInst>(&I)) { 10485f757f3fSDimitry Andric OpType = OperationType::DisjointOp; 10495f757f3fSDimitry Andric DisjointFlags.IsDisjoint = Op->isDisjoint(); 10505f757f3fSDimitry Andric } else if (auto *Op = dyn_cast<OverflowingBinaryOperator>(&I)) { 10515f757f3fSDimitry Andric OpType = OperationType::OverflowingBinOp; 10525f757f3fSDimitry Andric WrapFlags = {Op->hasNoUnsignedWrap(), Op->hasNoSignedWrap()}; 10535f757f3fSDimitry Andric } else if (auto *Op = dyn_cast<PossiblyExactOperator>(&I)) { 10545f757f3fSDimitry Andric OpType = OperationType::PossiblyExactOp; 10555f757f3fSDimitry Andric ExactFlags.IsExact = Op->isExact(); 10565f757f3fSDimitry Andric } else if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) { 10575f757f3fSDimitry Andric OpType = OperationType::GEPOp; 10585f757f3fSDimitry Andric GEPFlags.IsInBounds = GEP->isInBounds(); 10595f757f3fSDimitry Andric } else if (auto *PNNI = dyn_cast<PossiblyNonNegInst>(&I)) { 10605f757f3fSDimitry Andric OpType = OperationType::NonNegOp; 10615f757f3fSDimitry Andric NonNegFlags.NonNeg = PNNI->hasNonNeg(); 10625f757f3fSDimitry Andric } else if (auto *Op = dyn_cast<FPMathOperator>(&I)) { 10635f757f3fSDimitry Andric OpType = OperationType::FPMathOp; 10645f757f3fSDimitry Andric FMFs = Op->getFastMathFlags(); 10657a6dacacSDimitry Andric } else { 10667a6dacacSDimitry Andric OpType = OperationType::Other; 10677a6dacacSDimitry Andric AllFlags = 0; 10685f757f3fSDimitry Andric } 10695f757f3fSDimitry Andric } 10705f757f3fSDimitry Andric 10715f757f3fSDimitry Andric template <typename IterT> 10725f757f3fSDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, 10735f757f3fSDimitry Andric CmpInst::Predicate Pred, DebugLoc DL = {}) 10747a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, DL), OpType(OperationType::Cmp), 10755f757f3fSDimitry Andric CmpPredicate(Pred) {} 10765f757f3fSDimitry Andric 10775f757f3fSDimitry Andric template <typename IterT> 10785f757f3fSDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, 10795f757f3fSDimitry Andric WrapFlagsTy WrapFlags, DebugLoc DL = {}) 10807a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, DL), 10817a6dacacSDimitry Andric OpType(OperationType::OverflowingBinOp), WrapFlags(WrapFlags) {} 10825f757f3fSDimitry Andric 10835f757f3fSDimitry Andric template <typename IterT> 10845f757f3fSDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, 10855f757f3fSDimitry Andric FastMathFlags FMFs, DebugLoc DL = {}) 10867a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, DL), OpType(OperationType::FPMathOp), 10875f757f3fSDimitry Andric FMFs(FMFs) {} 10885f757f3fSDimitry Andric 1089*0fca6ea1SDimitry Andric template <typename IterT> 1090*0fca6ea1SDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, 1091*0fca6ea1SDimitry Andric DisjointFlagsTy DisjointFlags, DebugLoc DL = {}) 1092*0fca6ea1SDimitry Andric : VPSingleDefRecipe(SC, Operands, DL), OpType(OperationType::DisjointOp), 1093*0fca6ea1SDimitry Andric DisjointFlags(DisjointFlags) {} 1094*0fca6ea1SDimitry Andric 10951db9f3b2SDimitry Andric protected: 10961db9f3b2SDimitry Andric template <typename IterT> 10971db9f3b2SDimitry Andric VPRecipeWithIRFlags(const unsigned char SC, IterT Operands, 10981db9f3b2SDimitry Andric GEPFlagsTy GEPFlags, DebugLoc DL = {}) 10997a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, DL), OpType(OperationType::GEPOp), 11001db9f3b2SDimitry Andric GEPFlags(GEPFlags) {} 11011db9f3b2SDimitry Andric 11021db9f3b2SDimitry Andric public: 11035f757f3fSDimitry Andric static inline bool classof(const VPRecipeBase *R) { 11045f757f3fSDimitry Andric return R->getVPDefID() == VPRecipeBase::VPInstructionSC || 11055f757f3fSDimitry Andric R->getVPDefID() == VPRecipeBase::VPWidenSC || 11065f757f3fSDimitry Andric R->getVPDefID() == VPRecipeBase::VPWidenGEPSC || 11075f757f3fSDimitry Andric R->getVPDefID() == VPRecipeBase::VPWidenCastSC || 11081db9f3b2SDimitry Andric R->getVPDefID() == VPRecipeBase::VPReplicateSC || 11091db9f3b2SDimitry Andric R->getVPDefID() == VPRecipeBase::VPVectorPointerSC; 11105f757f3fSDimitry Andric } 11115f757f3fSDimitry Andric 1112*0fca6ea1SDimitry Andric static inline bool classof(const VPUser *U) { 1113*0fca6ea1SDimitry Andric auto *R = dyn_cast<VPRecipeBase>(U); 1114*0fca6ea1SDimitry Andric return R && classof(R); 1115*0fca6ea1SDimitry Andric } 1116*0fca6ea1SDimitry Andric 11175f757f3fSDimitry Andric /// Drop all poison-generating flags. 11185f757f3fSDimitry Andric void dropPoisonGeneratingFlags() { 11195f757f3fSDimitry Andric // NOTE: This needs to be kept in-sync with 11205f757f3fSDimitry Andric // Instruction::dropPoisonGeneratingFlags. 11215f757f3fSDimitry Andric switch (OpType) { 11225f757f3fSDimitry Andric case OperationType::OverflowingBinOp: 11235f757f3fSDimitry Andric WrapFlags.HasNUW = false; 11245f757f3fSDimitry Andric WrapFlags.HasNSW = false; 11255f757f3fSDimitry Andric break; 11265f757f3fSDimitry Andric case OperationType::DisjointOp: 11275f757f3fSDimitry Andric DisjointFlags.IsDisjoint = false; 11285f757f3fSDimitry Andric break; 11295f757f3fSDimitry Andric case OperationType::PossiblyExactOp: 11305f757f3fSDimitry Andric ExactFlags.IsExact = false; 11315f757f3fSDimitry Andric break; 11325f757f3fSDimitry Andric case OperationType::GEPOp: 11335f757f3fSDimitry Andric GEPFlags.IsInBounds = false; 11345f757f3fSDimitry Andric break; 11355f757f3fSDimitry Andric case OperationType::FPMathOp: 11365f757f3fSDimitry Andric FMFs.NoNaNs = false; 11375f757f3fSDimitry Andric FMFs.NoInfs = false; 11385f757f3fSDimitry Andric break; 11395f757f3fSDimitry Andric case OperationType::NonNegOp: 11405f757f3fSDimitry Andric NonNegFlags.NonNeg = false; 11415f757f3fSDimitry Andric break; 11425f757f3fSDimitry Andric case OperationType::Cmp: 11435f757f3fSDimitry Andric case OperationType::Other: 11445f757f3fSDimitry Andric break; 11455f757f3fSDimitry Andric } 11465f757f3fSDimitry Andric } 11475f757f3fSDimitry Andric 11485f757f3fSDimitry Andric /// Set the IR flags for \p I. 11495f757f3fSDimitry Andric void setFlags(Instruction *I) const { 11505f757f3fSDimitry Andric switch (OpType) { 11515f757f3fSDimitry Andric case OperationType::OverflowingBinOp: 11525f757f3fSDimitry Andric I->setHasNoUnsignedWrap(WrapFlags.HasNUW); 11535f757f3fSDimitry Andric I->setHasNoSignedWrap(WrapFlags.HasNSW); 11545f757f3fSDimitry Andric break; 11555f757f3fSDimitry Andric case OperationType::DisjointOp: 11565f757f3fSDimitry Andric cast<PossiblyDisjointInst>(I)->setIsDisjoint(DisjointFlags.IsDisjoint); 11575f757f3fSDimitry Andric break; 11585f757f3fSDimitry Andric case OperationType::PossiblyExactOp: 11595f757f3fSDimitry Andric I->setIsExact(ExactFlags.IsExact); 11605f757f3fSDimitry Andric break; 11615f757f3fSDimitry Andric case OperationType::GEPOp: 1162*0fca6ea1SDimitry Andric // TODO(gep_nowrap): Track the full GEPNoWrapFlags in VPlan. 1163*0fca6ea1SDimitry Andric cast<GetElementPtrInst>(I)->setNoWrapFlags( 1164*0fca6ea1SDimitry Andric GEPFlags.IsInBounds ? GEPNoWrapFlags::inBounds() 1165*0fca6ea1SDimitry Andric : GEPNoWrapFlags::none()); 11665f757f3fSDimitry Andric break; 11675f757f3fSDimitry Andric case OperationType::FPMathOp: 11685f757f3fSDimitry Andric I->setHasAllowReassoc(FMFs.AllowReassoc); 11695f757f3fSDimitry Andric I->setHasNoNaNs(FMFs.NoNaNs); 11705f757f3fSDimitry Andric I->setHasNoInfs(FMFs.NoInfs); 11715f757f3fSDimitry Andric I->setHasNoSignedZeros(FMFs.NoSignedZeros); 11725f757f3fSDimitry Andric I->setHasAllowReciprocal(FMFs.AllowReciprocal); 11735f757f3fSDimitry Andric I->setHasAllowContract(FMFs.AllowContract); 11745f757f3fSDimitry Andric I->setHasApproxFunc(FMFs.ApproxFunc); 11755f757f3fSDimitry Andric break; 11765f757f3fSDimitry Andric case OperationType::NonNegOp: 11775f757f3fSDimitry Andric I->setNonNeg(NonNegFlags.NonNeg); 11785f757f3fSDimitry Andric break; 11795f757f3fSDimitry Andric case OperationType::Cmp: 11805f757f3fSDimitry Andric case OperationType::Other: 11815f757f3fSDimitry Andric break; 11825f757f3fSDimitry Andric } 11835f757f3fSDimitry Andric } 11845f757f3fSDimitry Andric 11855f757f3fSDimitry Andric CmpInst::Predicate getPredicate() const { 11865f757f3fSDimitry Andric assert(OpType == OperationType::Cmp && 11875f757f3fSDimitry Andric "recipe doesn't have a compare predicate"); 11885f757f3fSDimitry Andric return CmpPredicate; 11895f757f3fSDimitry Andric } 11905f757f3fSDimitry Andric 11915f757f3fSDimitry Andric bool isInBounds() const { 11925f757f3fSDimitry Andric assert(OpType == OperationType::GEPOp && 11935f757f3fSDimitry Andric "recipe doesn't have inbounds flag"); 11945f757f3fSDimitry Andric return GEPFlags.IsInBounds; 11955f757f3fSDimitry Andric } 11965f757f3fSDimitry Andric 11975f757f3fSDimitry Andric /// Returns true if the recipe has fast-math flags. 11985f757f3fSDimitry Andric bool hasFastMathFlags() const { return OpType == OperationType::FPMathOp; } 11995f757f3fSDimitry Andric 12005f757f3fSDimitry Andric FastMathFlags getFastMathFlags() const; 12015f757f3fSDimitry Andric 12025f757f3fSDimitry Andric bool hasNoUnsignedWrap() const { 12035f757f3fSDimitry Andric assert(OpType == OperationType::OverflowingBinOp && 12045f757f3fSDimitry Andric "recipe doesn't have a NUW flag"); 12055f757f3fSDimitry Andric return WrapFlags.HasNUW; 12065f757f3fSDimitry Andric } 12075f757f3fSDimitry Andric 12085f757f3fSDimitry Andric bool hasNoSignedWrap() const { 12095f757f3fSDimitry Andric assert(OpType == OperationType::OverflowingBinOp && 12105f757f3fSDimitry Andric "recipe doesn't have a NSW flag"); 12115f757f3fSDimitry Andric return WrapFlags.HasNSW; 12125f757f3fSDimitry Andric } 12135f757f3fSDimitry Andric 1214*0fca6ea1SDimitry Andric bool isDisjoint() const { 1215*0fca6ea1SDimitry Andric assert(OpType == OperationType::DisjointOp && 1216*0fca6ea1SDimitry Andric "recipe cannot have a disjoing flag"); 1217*0fca6ea1SDimitry Andric return DisjointFlags.IsDisjoint; 1218*0fca6ea1SDimitry Andric } 1219*0fca6ea1SDimitry Andric 12205f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 12215f757f3fSDimitry Andric void printFlags(raw_ostream &O) const; 12225f757f3fSDimitry Andric #endif 12235f757f3fSDimitry Andric }; 12245f757f3fSDimitry Andric 12250b57cec5SDimitry Andric /// This is a concrete Recipe that models a single VPlan-level instruction. 12260b57cec5SDimitry Andric /// While as any Recipe it may generate a sequence of IR instructions when 12270b57cec5SDimitry Andric /// executed, these instructions would always form a single-def expression as 12280b57cec5SDimitry Andric /// the VPInstruction is also a single def-use vertex. 12297a6dacacSDimitry Andric class VPInstruction : public VPRecipeWithIRFlags { 12300b57cec5SDimitry Andric friend class VPlanSlp; 12310b57cec5SDimitry Andric 12320b57cec5SDimitry Andric public: 12330b57cec5SDimitry Andric /// VPlan opcodes, extending LLVM IR with idiomatics instructions. 12340b57cec5SDimitry Andric enum { 1235fe6060f1SDimitry Andric FirstOrderRecurrenceSplice = 1236fe6060f1SDimitry Andric Instruction::OtherOpsEnd + 1, // Combines the incoming and previous 1237fe6060f1SDimitry Andric // values of a first-order recurrence. 1238fe6060f1SDimitry Andric Not, 12390b57cec5SDimitry Andric SLPLoad, 12400b57cec5SDimitry Andric SLPStore, 12415ffd83dbSDimitry Andric ActiveLaneMask, 1242*0fca6ea1SDimitry Andric ExplicitVectorLength, 1243*0fca6ea1SDimitry Andric /// Creates a scalar phi in a leaf VPBB with a single predecessor in VPlan. 1244*0fca6ea1SDimitry Andric /// The first operand is the incoming value from the predecessor in VPlan, 1245*0fca6ea1SDimitry Andric /// the second operand is the incoming value for all other predecessors 1246*0fca6ea1SDimitry Andric /// (which are currently not modeled in VPlan). 1247*0fca6ea1SDimitry Andric ResumePhi, 124806c3fb27SDimitry Andric CalculateTripCountMinusVF, 12495f757f3fSDimitry Andric // Increment the canonical IV separately for each unrolled part. 1250753f127fSDimitry Andric CanonicalIVIncrementForPart, 125104eeddc0SDimitry Andric BranchOnCount, 12521db9f3b2SDimitry Andric BranchOnCond, 12531db9f3b2SDimitry Andric ComputeReductionResult, 1254*0fca6ea1SDimitry Andric // Takes the VPValue to extract from as first operand and the lane or part 1255*0fca6ea1SDimitry Andric // to extract as second operand, counting from the end starting with 1 for 1256*0fca6ea1SDimitry Andric // last. The second operand must be a positive constant and <= VF when 1257*0fca6ea1SDimitry Andric // extracting from a vector or <= UF when extracting from an unrolled 1258*0fca6ea1SDimitry Andric // scalar. 1259*0fca6ea1SDimitry Andric ExtractFromEnd, 1260*0fca6ea1SDimitry Andric LogicalAnd, // Non-poison propagating logical And. 1261*0fca6ea1SDimitry Andric // Add an offset in bytes (second operand) to a base pointer (first 1262*0fca6ea1SDimitry Andric // operand). Only generates scalar values (either for the first lane only or 1263*0fca6ea1SDimitry Andric // for all lanes, depending on its uses). 1264*0fca6ea1SDimitry Andric PtrAdd, 12650b57cec5SDimitry Andric }; 12660b57cec5SDimitry Andric 12670b57cec5SDimitry Andric private: 12680b57cec5SDimitry Andric typedef unsigned char OpcodeTy; 12690b57cec5SDimitry Andric OpcodeTy Opcode; 12700b57cec5SDimitry Andric 1271753f127fSDimitry Andric /// An optional name that can be used for the generated IR instruction. 1272753f127fSDimitry Andric const std::string Name; 1273753f127fSDimitry Andric 1274*0fca6ea1SDimitry Andric /// Returns true if this VPInstruction generates scalar values for all lanes. 1275*0fca6ea1SDimitry Andric /// Most VPInstructions generate a single value per part, either vector or 1276*0fca6ea1SDimitry Andric /// scalar. VPReplicateRecipe takes care of generating multiple (scalar) 1277*0fca6ea1SDimitry Andric /// values per all lanes, stemming from an original ingredient. This method 1278*0fca6ea1SDimitry Andric /// identifies the (rare) cases of VPInstructions that do so as well, w/o an 1279*0fca6ea1SDimitry Andric /// underlying ingredient. 1280*0fca6ea1SDimitry Andric bool doesGeneratePerAllLanes() const; 1281*0fca6ea1SDimitry Andric 1282*0fca6ea1SDimitry Andric /// Returns true if we can generate a scalar for the first lane only if 1283*0fca6ea1SDimitry Andric /// needed. 1284*0fca6ea1SDimitry Andric bool canGenerateScalarForFirstLane() const; 1285*0fca6ea1SDimitry Andric 1286*0fca6ea1SDimitry Andric /// Utility methods serving execute(): generates a single instance of the 1287*0fca6ea1SDimitry Andric /// modeled instruction for a given part. \returns the generated value for \p 1288*0fca6ea1SDimitry Andric /// Part. In some cases an existing value is returned rather than a generated 128906c3fb27SDimitry Andric /// one. 1290*0fca6ea1SDimitry Andric Value *generatePerPart(VPTransformState &State, unsigned Part); 1291*0fca6ea1SDimitry Andric 1292*0fca6ea1SDimitry Andric /// Utility methods serving execute(): generates a scalar single instance of 1293*0fca6ea1SDimitry Andric /// the modeled instruction for a given lane. \returns the scalar generated 1294*0fca6ea1SDimitry Andric /// value for lane \p Lane. 1295*0fca6ea1SDimitry Andric Value *generatePerLane(VPTransformState &State, const VPIteration &Lane); 12960b57cec5SDimitry Andric 12975f757f3fSDimitry Andric #if !defined(NDEBUG) 12985f757f3fSDimitry Andric /// Return true if the VPInstruction is a floating point math operation, i.e. 12995f757f3fSDimitry Andric /// has fast-math flags. 13005f757f3fSDimitry Andric bool isFPMathOp() const; 13015f757f3fSDimitry Andric #endif 13025f757f3fSDimitry Andric 13030b57cec5SDimitry Andric public: 1304753f127fSDimitry Andric VPInstruction(unsigned Opcode, ArrayRef<VPValue *> Operands, DebugLoc DL, 1305753f127fSDimitry Andric const Twine &Name = "") 13065f757f3fSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPInstructionSC, Operands, DL), 13077a6dacacSDimitry Andric Opcode(Opcode), Name(Name.str()) {} 1308e8d8bef9SDimitry Andric 13090eae32dcSDimitry Andric VPInstruction(unsigned Opcode, std::initializer_list<VPValue *> Operands, 1310753f127fSDimitry Andric DebugLoc DL = {}, const Twine &Name = "") 1311753f127fSDimitry Andric : VPInstruction(Opcode, ArrayRef<VPValue *>(Operands), DL, Name) {} 13120b57cec5SDimitry Andric 13135f757f3fSDimitry Andric VPInstruction(unsigned Opcode, CmpInst::Predicate Pred, VPValue *A, 13145f757f3fSDimitry Andric VPValue *B, DebugLoc DL = {}, const Twine &Name = ""); 13150b57cec5SDimitry Andric 13165f757f3fSDimitry Andric VPInstruction(unsigned Opcode, std::initializer_list<VPValue *> Operands, 13175f757f3fSDimitry Andric WrapFlagsTy WrapFlags, DebugLoc DL = {}, const Twine &Name = "") 13185f757f3fSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPInstructionSC, Operands, WrapFlags, DL), 13197a6dacacSDimitry Andric Opcode(Opcode), Name(Name.str()) {} 13205f757f3fSDimitry Andric 13215f757f3fSDimitry Andric VPInstruction(unsigned Opcode, std::initializer_list<VPValue *> Operands, 1322*0fca6ea1SDimitry Andric DisjointFlagsTy DisjointFlag, DebugLoc DL = {}, 1323*0fca6ea1SDimitry Andric const Twine &Name = "") 1324*0fca6ea1SDimitry Andric : VPRecipeWithIRFlags(VPDef::VPInstructionSC, Operands, DisjointFlag, DL), 1325*0fca6ea1SDimitry Andric Opcode(Opcode), Name(Name.str()) { 1326*0fca6ea1SDimitry Andric assert(Opcode == Instruction::Or && "only OR opcodes can be disjoint"); 1327*0fca6ea1SDimitry Andric } 1328*0fca6ea1SDimitry Andric 1329*0fca6ea1SDimitry Andric VPInstruction(unsigned Opcode, std::initializer_list<VPValue *> Operands, 13305f757f3fSDimitry Andric FastMathFlags FMFs, DebugLoc DL = {}, const Twine &Name = ""); 13315f757f3fSDimitry Andric 13325f757f3fSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPInstructionSC) 13330b57cec5SDimitry Andric 1334*0fca6ea1SDimitry Andric VPInstruction *clone() override { 1335*0fca6ea1SDimitry Andric SmallVector<VPValue *, 2> Operands(operands()); 1336*0fca6ea1SDimitry Andric auto *New = new VPInstruction(Opcode, Operands, getDebugLoc(), Name); 1337*0fca6ea1SDimitry Andric New->transferFlags(*this); 1338*0fca6ea1SDimitry Andric return New; 1339*0fca6ea1SDimitry Andric } 1340*0fca6ea1SDimitry Andric 13410b57cec5SDimitry Andric unsigned getOpcode() const { return Opcode; } 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric /// Generate the instruction. 13440b57cec5SDimitry Andric /// TODO: We currently execute only per-part unless a specific instance is 13450b57cec5SDimitry Andric /// provided. 13460b57cec5SDimitry Andric void execute(VPTransformState &State) override; 13470b57cec5SDimitry Andric 1348fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1349e8d8bef9SDimitry Andric /// Print the VPInstruction to \p O. 13505ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 13515ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 13520b57cec5SDimitry Andric 1353e8d8bef9SDimitry Andric /// Print the VPInstruction to dbgs() (for debugging). 1354fe6060f1SDimitry Andric LLVM_DUMP_METHOD void dump() const; 1355fe6060f1SDimitry Andric #endif 13560b57cec5SDimitry Andric 13570b57cec5SDimitry Andric /// Return true if this instruction may modify memory. 13580b57cec5SDimitry Andric bool mayWriteToMemory() const { 13590b57cec5SDimitry Andric // TODO: we can use attributes of the called function to rule out memory 13600b57cec5SDimitry Andric // modifications. 13610b57cec5SDimitry Andric return Opcode == Instruction::Store || Opcode == Instruction::Call || 13620b57cec5SDimitry Andric Opcode == Instruction::Invoke || Opcode == SLPStore; 13630b57cec5SDimitry Andric } 13645ffd83dbSDimitry Andric 13655ffd83dbSDimitry Andric bool hasResult() const { 13665ffd83dbSDimitry Andric // CallInst may or may not have a result, depending on the called function. 13675ffd83dbSDimitry Andric // Conservatively return calls have results for now. 13685ffd83dbSDimitry Andric switch (getOpcode()) { 13695ffd83dbSDimitry Andric case Instruction::Ret: 13705ffd83dbSDimitry Andric case Instruction::Br: 13715ffd83dbSDimitry Andric case Instruction::Store: 13725ffd83dbSDimitry Andric case Instruction::Switch: 13735ffd83dbSDimitry Andric case Instruction::IndirectBr: 13745ffd83dbSDimitry Andric case Instruction::Resume: 13755ffd83dbSDimitry Andric case Instruction::CatchRet: 13765ffd83dbSDimitry Andric case Instruction::Unreachable: 13775ffd83dbSDimitry Andric case Instruction::Fence: 13785ffd83dbSDimitry Andric case Instruction::AtomicRMW: 137981ad6265SDimitry Andric case VPInstruction::BranchOnCond: 138004eeddc0SDimitry Andric case VPInstruction::BranchOnCount: 13815ffd83dbSDimitry Andric return false; 13825ffd83dbSDimitry Andric default: 13835ffd83dbSDimitry Andric return true; 13845ffd83dbSDimitry Andric } 13855ffd83dbSDimitry Andric } 13864824e7fdSDimitry Andric 13871fd87a68SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 1388*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override; 13895f757f3fSDimitry Andric 13905f757f3fSDimitry Andric /// Returns true if the recipe only uses the first part of operand \p Op. 1391*0fca6ea1SDimitry Andric bool onlyFirstPartUsed(const VPValue *Op) const override; 1392*0fca6ea1SDimitry Andric 1393*0fca6ea1SDimitry Andric /// Returns true if this VPInstruction produces a scalar value from a vector, 1394*0fca6ea1SDimitry Andric /// e.g. by performing a reduction or extracting a lane. 1395*0fca6ea1SDimitry Andric bool isVectorToScalar() const; 1396*0fca6ea1SDimitry Andric 1397*0fca6ea1SDimitry Andric /// Returns true if this VPInstruction's operands are single scalars and the 1398*0fca6ea1SDimitry Andric /// result is also a single scalar. 1399*0fca6ea1SDimitry Andric bool isSingleScalar() const; 14000b57cec5SDimitry Andric }; 14010b57cec5SDimitry Andric 1402*0fca6ea1SDimitry Andric /// VPWidenRecipe is a recipe for producing a widened instruction using the 1403*0fca6ea1SDimitry Andric /// opcode and operands of the recipe. This recipe covers most of the 1404*0fca6ea1SDimitry Andric /// traditional vectorization cases where each recipe transforms into a 1405*0fca6ea1SDimitry Andric /// vectorized version of itself. 14067a6dacacSDimitry Andric class VPWidenRecipe : public VPRecipeWithIRFlags { 14075f757f3fSDimitry Andric unsigned Opcode; 140806c3fb27SDimitry Andric 14090b57cec5SDimitry Andric public: 14105ffd83dbSDimitry Andric template <typename IterT> 14115ffd83dbSDimitry Andric VPWidenRecipe(Instruction &I, iterator_range<IterT> Operands) 14127a6dacacSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPWidenSC, Operands, I), 14135f757f3fSDimitry Andric Opcode(I.getOpcode()) {} 14140b57cec5SDimitry Andric 14150b57cec5SDimitry Andric ~VPWidenRecipe() override = default; 14160b57cec5SDimitry Andric 1417*0fca6ea1SDimitry Andric VPWidenRecipe *clone() override { 1418*0fca6ea1SDimitry Andric auto *R = new VPWidenRecipe(*getUnderlyingInstr(), operands()); 1419*0fca6ea1SDimitry Andric R->transferFlags(*this); 1420*0fca6ea1SDimitry Andric return R; 1421*0fca6ea1SDimitry Andric } 1422*0fca6ea1SDimitry Andric 1423bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenSC) 14240b57cec5SDimitry Andric 1425*0fca6ea1SDimitry Andric /// Produce a widened instruction using the opcode and operands of the recipe, 1426*0fca6ea1SDimitry Andric /// processing State.VF elements. 14270b57cec5SDimitry Andric void execute(VPTransformState &State) override; 14280b57cec5SDimitry Andric 14295f757f3fSDimitry Andric unsigned getOpcode() const { return Opcode; } 14305f757f3fSDimitry Andric 1431fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 14325ffd83dbSDimitry Andric /// Print the recipe. 14335ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 14345ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 1435fe6060f1SDimitry Andric #endif 14365ffd83dbSDimitry Andric }; 14375ffd83dbSDimitry Andric 143806c3fb27SDimitry Andric /// VPWidenCastRecipe is a recipe to create vector cast instructions. 14397a6dacacSDimitry Andric class VPWidenCastRecipe : public VPRecipeWithIRFlags { 144006c3fb27SDimitry Andric /// Cast instruction opcode. 144106c3fb27SDimitry Andric Instruction::CastOps Opcode; 144206c3fb27SDimitry Andric 144306c3fb27SDimitry Andric /// Result type for the cast. 144406c3fb27SDimitry Andric Type *ResultTy; 144506c3fb27SDimitry Andric 144606c3fb27SDimitry Andric public: 144706c3fb27SDimitry Andric VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy, 14485f757f3fSDimitry Andric CastInst &UI) 14497a6dacacSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op, UI), Opcode(Opcode), 14507a6dacacSDimitry Andric ResultTy(ResultTy) { 14515f757f3fSDimitry Andric assert(UI.getOpcode() == Opcode && 145206c3fb27SDimitry Andric "opcode of underlying cast doesn't match"); 145306c3fb27SDimitry Andric } 145406c3fb27SDimitry Andric 14555f757f3fSDimitry Andric VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy) 14567a6dacacSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), Opcode(Opcode), 14577a6dacacSDimitry Andric ResultTy(ResultTy) {} 14585f757f3fSDimitry Andric 145906c3fb27SDimitry Andric ~VPWidenCastRecipe() override = default; 146006c3fb27SDimitry Andric 1461*0fca6ea1SDimitry Andric VPWidenCastRecipe *clone() override { 1462*0fca6ea1SDimitry Andric if (auto *UV = getUnderlyingValue()) 1463*0fca6ea1SDimitry Andric return new VPWidenCastRecipe(Opcode, getOperand(0), ResultTy, 1464*0fca6ea1SDimitry Andric *cast<CastInst>(UV)); 1465*0fca6ea1SDimitry Andric 1466*0fca6ea1SDimitry Andric return new VPWidenCastRecipe(Opcode, getOperand(0), ResultTy); 1467*0fca6ea1SDimitry Andric } 1468*0fca6ea1SDimitry Andric 146906c3fb27SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenCastSC) 147006c3fb27SDimitry Andric 147106c3fb27SDimitry Andric /// Produce widened copies of the cast. 147206c3fb27SDimitry Andric void execute(VPTransformState &State) override; 147306c3fb27SDimitry Andric 147406c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 147506c3fb27SDimitry Andric /// Print the recipe. 147606c3fb27SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 147706c3fb27SDimitry Andric VPSlotTracker &SlotTracker) const override; 147806c3fb27SDimitry Andric #endif 147906c3fb27SDimitry Andric 148006c3fb27SDimitry Andric Instruction::CastOps getOpcode() const { return Opcode; } 148106c3fb27SDimitry Andric 148206c3fb27SDimitry Andric /// Returns the result type of the cast. 148306c3fb27SDimitry Andric Type *getResultType() const { return ResultTy; } 148406c3fb27SDimitry Andric }; 148506c3fb27SDimitry Andric 1486*0fca6ea1SDimitry Andric /// VPScalarCastRecipe is a recipe to create scalar cast instructions. 1487*0fca6ea1SDimitry Andric class VPScalarCastRecipe : public VPSingleDefRecipe { 1488*0fca6ea1SDimitry Andric Instruction::CastOps Opcode; 1489*0fca6ea1SDimitry Andric 1490*0fca6ea1SDimitry Andric Type *ResultTy; 1491*0fca6ea1SDimitry Andric 1492*0fca6ea1SDimitry Andric Value *generate(VPTransformState &State, unsigned Part); 1493*0fca6ea1SDimitry Andric 1494*0fca6ea1SDimitry Andric public: 1495*0fca6ea1SDimitry Andric VPScalarCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy) 1496*0fca6ea1SDimitry Andric : VPSingleDefRecipe(VPDef::VPScalarCastSC, {Op}), Opcode(Opcode), 1497*0fca6ea1SDimitry Andric ResultTy(ResultTy) {} 1498*0fca6ea1SDimitry Andric 1499*0fca6ea1SDimitry Andric ~VPScalarCastRecipe() override = default; 1500*0fca6ea1SDimitry Andric 1501*0fca6ea1SDimitry Andric VPScalarCastRecipe *clone() override { 1502*0fca6ea1SDimitry Andric return new VPScalarCastRecipe(Opcode, getOperand(0), ResultTy); 1503*0fca6ea1SDimitry Andric } 1504*0fca6ea1SDimitry Andric 1505*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPScalarCastSC) 1506*0fca6ea1SDimitry Andric 1507*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override; 1508*0fca6ea1SDimitry Andric 1509*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1510*0fca6ea1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 1511*0fca6ea1SDimitry Andric VPSlotTracker &SlotTracker) const override; 1512*0fca6ea1SDimitry Andric #endif 1513*0fca6ea1SDimitry Andric 1514*0fca6ea1SDimitry Andric /// Returns the result type of the cast. 1515*0fca6ea1SDimitry Andric Type *getResultType() const { return ResultTy; } 1516*0fca6ea1SDimitry Andric 1517*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 1518*0fca6ea1SDimitry Andric // At the moment, only uniform codegen is implemented. 1519*0fca6ea1SDimitry Andric assert(is_contained(operands(), Op) && 1520*0fca6ea1SDimitry Andric "Op must be an operand of the recipe"); 1521*0fca6ea1SDimitry Andric return true; 1522*0fca6ea1SDimitry Andric } 1523*0fca6ea1SDimitry Andric }; 1524*0fca6ea1SDimitry Andric 15255ffd83dbSDimitry Andric /// A recipe for widening Call instructions. 15267a6dacacSDimitry Andric class VPWidenCallRecipe : public VPSingleDefRecipe { 1527bdd1243dSDimitry Andric /// ID of the vector intrinsic to call when widening the call. If set the 1528bdd1243dSDimitry Andric /// Intrinsic::not_intrinsic, a library call will be used instead. 1529bdd1243dSDimitry Andric Intrinsic::ID VectorIntrinsicID; 153006c3fb27SDimitry Andric /// If this recipe represents a library call, Variant stores a pointer to 153106c3fb27SDimitry Andric /// the chosen function. There is a 1:1 mapping between a given VF and the 153206c3fb27SDimitry Andric /// chosen vectorized variant, so there will be a different vplan for each 153306c3fb27SDimitry Andric /// VF with a valid variant. 153406c3fb27SDimitry Andric Function *Variant; 15355ffd83dbSDimitry Andric 15365ffd83dbSDimitry Andric public: 15375ffd83dbSDimitry Andric template <typename IterT> 1538*0fca6ea1SDimitry Andric VPWidenCallRecipe(Value *UV, iterator_range<IterT> CallArguments, 15397a6dacacSDimitry Andric Intrinsic::ID VectorIntrinsicID, DebugLoc DL = {}, 154006c3fb27SDimitry Andric Function *Variant = nullptr) 1541*0fca6ea1SDimitry Andric : VPSingleDefRecipe(VPDef::VPWidenCallSC, CallArguments, UV, DL), 1542*0fca6ea1SDimitry Andric VectorIntrinsicID(VectorIntrinsicID), Variant(Variant) { 1543*0fca6ea1SDimitry Andric assert( 1544*0fca6ea1SDimitry Andric isa<Function>(getOperand(getNumOperands() - 1)->getLiveInIRValue()) && 1545*0fca6ea1SDimitry Andric "last operand must be the called function"); 1546*0fca6ea1SDimitry Andric } 15475ffd83dbSDimitry Andric 15485ffd83dbSDimitry Andric ~VPWidenCallRecipe() override = default; 15495ffd83dbSDimitry Andric 1550*0fca6ea1SDimitry Andric VPWidenCallRecipe *clone() override { 1551*0fca6ea1SDimitry Andric return new VPWidenCallRecipe(getUnderlyingValue(), operands(), 1552*0fca6ea1SDimitry Andric VectorIntrinsicID, getDebugLoc(), Variant); 1553*0fca6ea1SDimitry Andric } 1554*0fca6ea1SDimitry Andric 1555bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenCallSC) 15560b57cec5SDimitry Andric 15575ffd83dbSDimitry Andric /// Produce a widened version of the call instruction. 15585ffd83dbSDimitry Andric void execute(VPTransformState &State) override; 15595ffd83dbSDimitry Andric 1560*0fca6ea1SDimitry Andric Function *getCalledScalarFunction() const { 1561*0fca6ea1SDimitry Andric return cast<Function>(getOperand(getNumOperands() - 1)->getLiveInIRValue()); 1562*0fca6ea1SDimitry Andric } 1563*0fca6ea1SDimitry Andric 1564*0fca6ea1SDimitry Andric operand_range arg_operands() { 1565*0fca6ea1SDimitry Andric return make_range(op_begin(), op_begin() + getNumOperands() - 1); 1566*0fca6ea1SDimitry Andric } 1567*0fca6ea1SDimitry Andric const_operand_range arg_operands() const { 1568*0fca6ea1SDimitry Andric return make_range(op_begin(), op_begin() + getNumOperands() - 1); 1569*0fca6ea1SDimitry Andric } 1570*0fca6ea1SDimitry Andric 1571fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 15720b57cec5SDimitry Andric /// Print the recipe. 15735ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 15745ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 1575fe6060f1SDimitry Andric #endif 15765ffd83dbSDimitry Andric }; 15775ffd83dbSDimitry Andric 15785ffd83dbSDimitry Andric /// A recipe for widening select instructions. 15797a6dacacSDimitry Andric struct VPWidenSelectRecipe : public VPSingleDefRecipe { 15805ffd83dbSDimitry Andric template <typename IterT> 158106c3fb27SDimitry Andric VPWidenSelectRecipe(SelectInst &I, iterator_range<IterT> Operands) 15827a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPWidenSelectSC, Operands, &I, 15837a6dacacSDimitry Andric I.getDebugLoc()) {} 15845ffd83dbSDimitry Andric 15855ffd83dbSDimitry Andric ~VPWidenSelectRecipe() override = default; 15865ffd83dbSDimitry Andric 1587*0fca6ea1SDimitry Andric VPWidenSelectRecipe *clone() override { 1588*0fca6ea1SDimitry Andric return new VPWidenSelectRecipe(*cast<SelectInst>(getUnderlyingInstr()), 1589*0fca6ea1SDimitry Andric operands()); 1590*0fca6ea1SDimitry Andric } 1591*0fca6ea1SDimitry Andric 1592bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenSelectSC) 15935ffd83dbSDimitry Andric 15945ffd83dbSDimitry Andric /// Produce a widened version of the select instruction. 15955ffd83dbSDimitry Andric void execute(VPTransformState &State) override; 15965ffd83dbSDimitry Andric 1597fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 15985ffd83dbSDimitry Andric /// Print the recipe. 15995ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 16005ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 1601fe6060f1SDimitry Andric #endif 160206c3fb27SDimitry Andric 160306c3fb27SDimitry Andric VPValue *getCond() const { 160406c3fb27SDimitry Andric return getOperand(0); 160506c3fb27SDimitry Andric } 160606c3fb27SDimitry Andric 160706c3fb27SDimitry Andric bool isInvariantCond() const { 160806c3fb27SDimitry Andric return getCond()->isDefinedOutsideVectorRegions(); 160906c3fb27SDimitry Andric } 16100b57cec5SDimitry Andric }; 16110b57cec5SDimitry Andric 1612480093f4SDimitry Andric /// A recipe for handling GEP instructions. 16137a6dacacSDimitry Andric class VPWidenGEPRecipe : public VPRecipeWithIRFlags { 161406c3fb27SDimitry Andric bool isPointerLoopInvariant() const { 161506c3fb27SDimitry Andric return getOperand(0)->isDefinedOutsideVectorRegions(); 161606c3fb27SDimitry Andric } 161706c3fb27SDimitry Andric 161806c3fb27SDimitry Andric bool isIndexLoopInvariant(unsigned I) const { 161906c3fb27SDimitry Andric return getOperand(I + 1)->isDefinedOutsideVectorRegions(); 162006c3fb27SDimitry Andric } 162106c3fb27SDimitry Andric 162206c3fb27SDimitry Andric bool areAllOperandsInvariant() const { 162306c3fb27SDimitry Andric return all_of(operands(), [](VPValue *Op) { 162406c3fb27SDimitry Andric return Op->isDefinedOutsideVectorRegions(); 162506c3fb27SDimitry Andric }); 162606c3fb27SDimitry Andric } 1627480093f4SDimitry Andric 1628480093f4SDimitry Andric public: 16295ffd83dbSDimitry Andric template <typename IterT> 1630e8d8bef9SDimitry Andric VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range<IterT> Operands) 16317a6dacacSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPWidenGEPSC, Operands, *GEP) {} 1632e8d8bef9SDimitry Andric 1633480093f4SDimitry Andric ~VPWidenGEPRecipe() override = default; 1634480093f4SDimitry Andric 1635*0fca6ea1SDimitry Andric VPWidenGEPRecipe *clone() override { 1636*0fca6ea1SDimitry Andric return new VPWidenGEPRecipe(cast<GetElementPtrInst>(getUnderlyingInstr()), 1637*0fca6ea1SDimitry Andric operands()); 1638*0fca6ea1SDimitry Andric } 1639*0fca6ea1SDimitry Andric 1640bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenGEPSC) 1641480093f4SDimitry Andric 1642480093f4SDimitry Andric /// Generate the gep nodes. 1643480093f4SDimitry Andric void execute(VPTransformState &State) override; 1644480093f4SDimitry Andric 1645fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1646480093f4SDimitry Andric /// Print the recipe. 16475ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 16485ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 1649fe6060f1SDimitry Andric #endif 1650480093f4SDimitry Andric }; 1651480093f4SDimitry Andric 1652647cbc5dSDimitry Andric /// A recipe to compute the pointers for widened memory accesses of IndexTy for 1653647cbc5dSDimitry Andric /// all parts. If IsReverse is true, compute pointers for accessing the input in 1654647cbc5dSDimitry Andric /// reverse order per part. 16557a6dacacSDimitry Andric class VPVectorPointerRecipe : public VPRecipeWithIRFlags { 1656647cbc5dSDimitry Andric Type *IndexedTy; 1657647cbc5dSDimitry Andric bool IsReverse; 1658647cbc5dSDimitry Andric 1659647cbc5dSDimitry Andric public: 1660647cbc5dSDimitry Andric VPVectorPointerRecipe(VPValue *Ptr, Type *IndexedTy, bool IsReverse, 16611db9f3b2SDimitry Andric bool IsInBounds, DebugLoc DL) 16621db9f3b2SDimitry Andric : VPRecipeWithIRFlags(VPDef::VPVectorPointerSC, ArrayRef<VPValue *>(Ptr), 16631db9f3b2SDimitry Andric GEPFlagsTy(IsInBounds), DL), 16647a6dacacSDimitry Andric IndexedTy(IndexedTy), IsReverse(IsReverse) {} 1665647cbc5dSDimitry Andric 1666647cbc5dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPVectorPointerSC) 1667647cbc5dSDimitry Andric 1668647cbc5dSDimitry Andric void execute(VPTransformState &State) override; 1669647cbc5dSDimitry Andric 1670647cbc5dSDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 1671647cbc5dSDimitry Andric assert(is_contained(operands(), Op) && 1672647cbc5dSDimitry Andric "Op must be an operand of the recipe"); 1673647cbc5dSDimitry Andric return true; 1674647cbc5dSDimitry Andric } 1675647cbc5dSDimitry Andric 1676*0fca6ea1SDimitry Andric VPVectorPointerRecipe *clone() override { 1677*0fca6ea1SDimitry Andric return new VPVectorPointerRecipe(getOperand(0), IndexedTy, IsReverse, 1678*0fca6ea1SDimitry Andric isInBounds(), getDebugLoc()); 1679*0fca6ea1SDimitry Andric } 1680*0fca6ea1SDimitry Andric 1681647cbc5dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1682647cbc5dSDimitry Andric /// Print the recipe. 1683647cbc5dSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 1684647cbc5dSDimitry Andric VPSlotTracker &SlotTracker) const override; 1685647cbc5dSDimitry Andric #endif 1686647cbc5dSDimitry Andric }; 1687647cbc5dSDimitry Andric 168804eeddc0SDimitry Andric /// A pure virtual base class for all recipes modeling header phis, including 168904eeddc0SDimitry Andric /// phis for first order recurrences, pointer inductions and reductions. The 169004eeddc0SDimitry Andric /// start value is the first operand of the recipe and the incoming value from 169104eeddc0SDimitry Andric /// the backedge is the second operand. 1692bdd1243dSDimitry Andric /// 1693bdd1243dSDimitry Andric /// Inductions are modeled using the following sub-classes: 1694bdd1243dSDimitry Andric /// * VPCanonicalIVPHIRecipe: Canonical scalar induction of the vector loop, 1695bdd1243dSDimitry Andric /// starting at a specified value (zero for the main vector loop, the resume 1696bdd1243dSDimitry Andric /// value for the epilogue vector loop) and stepping by 1. The induction 1697bdd1243dSDimitry Andric /// controls exiting of the vector loop by comparing against the vector trip 1698bdd1243dSDimitry Andric /// count. Produces a single scalar PHI for the induction value per 1699bdd1243dSDimitry Andric /// iteration. 1700bdd1243dSDimitry Andric /// * VPWidenIntOrFpInductionRecipe: Generates vector values for integer and 1701bdd1243dSDimitry Andric /// floating point inductions with arbitrary start and step values. Produces 1702bdd1243dSDimitry Andric /// a vector PHI per-part. 1703bdd1243dSDimitry Andric /// * VPDerivedIVRecipe: Converts the canonical IV value to the corresponding 1704bdd1243dSDimitry Andric /// value of an IV with different start and step values. Produces a single 1705bdd1243dSDimitry Andric /// scalar value per iteration 1706bdd1243dSDimitry Andric /// * VPScalarIVStepsRecipe: Generates scalar values per-lane based on a 1707bdd1243dSDimitry Andric /// canonical or derived induction. 1708bdd1243dSDimitry Andric /// * VPWidenPointerInductionRecipe: Generate vector and scalar values for a 1709bdd1243dSDimitry Andric /// pointer induction. Produces either a vector PHI per-part or scalar values 1710bdd1243dSDimitry Andric /// per-lane based on the canonical induction. 17117a6dacacSDimitry Andric class VPHeaderPHIRecipe : public VPSingleDefRecipe { 1712fe6060f1SDimitry Andric protected: 171306c3fb27SDimitry Andric VPHeaderPHIRecipe(unsigned char VPDefID, Instruction *UnderlyingInstr, 17145f757f3fSDimitry Andric VPValue *Start = nullptr, DebugLoc DL = {}) 17157a6dacacSDimitry Andric : VPSingleDefRecipe(VPDefID, ArrayRef<VPValue *>(), UnderlyingInstr, DL) { 1716fe6060f1SDimitry Andric if (Start) 1717fe6060f1SDimitry Andric addOperand(Start); 1718fe6060f1SDimitry Andric } 1719e8d8bef9SDimitry Andric 17200b57cec5SDimitry Andric public: 172104eeddc0SDimitry Andric ~VPHeaderPHIRecipe() override = default; 1722fe6060f1SDimitry Andric 172304eeddc0SDimitry Andric /// Method to support type inquiry through isa, cast, and dyn_cast. 172404eeddc0SDimitry Andric static inline bool classof(const VPRecipeBase *B) { 1725bdd1243dSDimitry Andric return B->getVPDefID() >= VPDef::VPFirstHeaderPHISC && 172606c3fb27SDimitry Andric B->getVPDefID() <= VPDef::VPLastHeaderPHISC; 172704eeddc0SDimitry Andric } 172804eeddc0SDimitry Andric static inline bool classof(const VPValue *V) { 1729bdd1243dSDimitry Andric auto *B = V->getDefiningRecipe(); 1730bdd1243dSDimitry Andric return B && B->getVPDefID() >= VPRecipeBase::VPFirstHeaderPHISC && 173106c3fb27SDimitry Andric B->getVPDefID() <= VPRecipeBase::VPLastHeaderPHISC; 173204eeddc0SDimitry Andric } 173304eeddc0SDimitry Andric 173404eeddc0SDimitry Andric /// Generate the phi nodes. 173504eeddc0SDimitry Andric void execute(VPTransformState &State) override = 0; 173604eeddc0SDimitry Andric 173704eeddc0SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 173804eeddc0SDimitry Andric /// Print the recipe. 173904eeddc0SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 174004eeddc0SDimitry Andric VPSlotTracker &SlotTracker) const override = 0; 174104eeddc0SDimitry Andric #endif 174204eeddc0SDimitry Andric 174304eeddc0SDimitry Andric /// Returns the start value of the phi, if one is set. 174404eeddc0SDimitry Andric VPValue *getStartValue() { 174504eeddc0SDimitry Andric return getNumOperands() == 0 ? nullptr : getOperand(0); 174604eeddc0SDimitry Andric } 174781ad6265SDimitry Andric VPValue *getStartValue() const { 174881ad6265SDimitry Andric return getNumOperands() == 0 ? nullptr : getOperand(0); 174981ad6265SDimitry Andric } 175004eeddc0SDimitry Andric 1751bdd1243dSDimitry Andric /// Update the start value of the recipe. 1752bdd1243dSDimitry Andric void setStartValue(VPValue *V) { setOperand(0, V); } 1753bdd1243dSDimitry Andric 175404eeddc0SDimitry Andric /// Returns the incoming value from the loop backedge. 175506c3fb27SDimitry Andric virtual VPValue *getBackedgeValue() { 175604eeddc0SDimitry Andric return getOperand(1); 175704eeddc0SDimitry Andric } 175804eeddc0SDimitry Andric 175904eeddc0SDimitry Andric /// Returns the backedge value as a recipe. The backedge value is guaranteed 176004eeddc0SDimitry Andric /// to be a recipe. 176106c3fb27SDimitry Andric virtual VPRecipeBase &getBackedgeRecipe() { 1762bdd1243dSDimitry Andric return *getBackedgeValue()->getDefiningRecipe(); 176304eeddc0SDimitry Andric } 176404eeddc0SDimitry Andric }; 176504eeddc0SDimitry Andric 176606c3fb27SDimitry Andric /// A recipe for handling phi nodes of integer and floating-point inductions, 176706c3fb27SDimitry Andric /// producing their vector values. 176806c3fb27SDimitry Andric class VPWidenIntOrFpInductionRecipe : public VPHeaderPHIRecipe { 176906c3fb27SDimitry Andric PHINode *IV; 177006c3fb27SDimitry Andric TruncInst *Trunc; 177106c3fb27SDimitry Andric const InductionDescriptor &IndDesc; 177206c3fb27SDimitry Andric 177306c3fb27SDimitry Andric public: 177406c3fb27SDimitry Andric VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, VPValue *Step, 177506c3fb27SDimitry Andric const InductionDescriptor &IndDesc) 177606c3fb27SDimitry Andric : VPHeaderPHIRecipe(VPDef::VPWidenIntOrFpInductionSC, IV, Start), IV(IV), 177706c3fb27SDimitry Andric Trunc(nullptr), IndDesc(IndDesc) { 177806c3fb27SDimitry Andric addOperand(Step); 177906c3fb27SDimitry Andric } 178006c3fb27SDimitry Andric 178106c3fb27SDimitry Andric VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, VPValue *Step, 178206c3fb27SDimitry Andric const InductionDescriptor &IndDesc, 178306c3fb27SDimitry Andric TruncInst *Trunc) 178406c3fb27SDimitry Andric : VPHeaderPHIRecipe(VPDef::VPWidenIntOrFpInductionSC, Trunc, Start), 178506c3fb27SDimitry Andric IV(IV), Trunc(Trunc), IndDesc(IndDesc) { 178606c3fb27SDimitry Andric addOperand(Step); 178706c3fb27SDimitry Andric } 178806c3fb27SDimitry Andric 178906c3fb27SDimitry Andric ~VPWidenIntOrFpInductionRecipe() override = default; 179006c3fb27SDimitry Andric 1791*0fca6ea1SDimitry Andric VPWidenIntOrFpInductionRecipe *clone() override { 1792*0fca6ea1SDimitry Andric return new VPWidenIntOrFpInductionRecipe(IV, getStartValue(), 1793*0fca6ea1SDimitry Andric getStepValue(), IndDesc, Trunc); 1794*0fca6ea1SDimitry Andric } 1795*0fca6ea1SDimitry Andric 179606c3fb27SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenIntOrFpInductionSC) 179706c3fb27SDimitry Andric 179806c3fb27SDimitry Andric /// Generate the vectorized and scalarized versions of the phi node as 179906c3fb27SDimitry Andric /// needed by their users. 180006c3fb27SDimitry Andric void execute(VPTransformState &State) override; 180106c3fb27SDimitry Andric 180206c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 180306c3fb27SDimitry Andric /// Print the recipe. 180406c3fb27SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 180506c3fb27SDimitry Andric VPSlotTracker &SlotTracker) const override; 180606c3fb27SDimitry Andric #endif 180706c3fb27SDimitry Andric 180806c3fb27SDimitry Andric VPValue *getBackedgeValue() override { 180906c3fb27SDimitry Andric // TODO: All operands of base recipe must exist and be at same index in 181006c3fb27SDimitry Andric // derived recipe. 181106c3fb27SDimitry Andric llvm_unreachable( 181206c3fb27SDimitry Andric "VPWidenIntOrFpInductionRecipe generates its own backedge value"); 181306c3fb27SDimitry Andric } 181406c3fb27SDimitry Andric 181506c3fb27SDimitry Andric VPRecipeBase &getBackedgeRecipe() override { 181606c3fb27SDimitry Andric // TODO: All operands of base recipe must exist and be at same index in 181706c3fb27SDimitry Andric // derived recipe. 181806c3fb27SDimitry Andric llvm_unreachable( 181906c3fb27SDimitry Andric "VPWidenIntOrFpInductionRecipe generates its own backedge value"); 182006c3fb27SDimitry Andric } 182106c3fb27SDimitry Andric 182206c3fb27SDimitry Andric /// Returns the step value of the induction. 182306c3fb27SDimitry Andric VPValue *getStepValue() { return getOperand(1); } 182406c3fb27SDimitry Andric const VPValue *getStepValue() const { return getOperand(1); } 182506c3fb27SDimitry Andric 182606c3fb27SDimitry Andric /// Returns the first defined value as TruncInst, if it is one or nullptr 182706c3fb27SDimitry Andric /// otherwise. 182806c3fb27SDimitry Andric TruncInst *getTruncInst() { return Trunc; } 182906c3fb27SDimitry Andric const TruncInst *getTruncInst() const { return Trunc; } 183006c3fb27SDimitry Andric 183106c3fb27SDimitry Andric PHINode *getPHINode() { return IV; } 183206c3fb27SDimitry Andric 183306c3fb27SDimitry Andric /// Returns the induction descriptor for the recipe. 183406c3fb27SDimitry Andric const InductionDescriptor &getInductionDescriptor() const { return IndDesc; } 183506c3fb27SDimitry Andric 183606c3fb27SDimitry Andric /// Returns true if the induction is canonical, i.e. starting at 0 and 1837*0fca6ea1SDimitry Andric /// incremented by UF * VF (= the original IV is incremented by 1) and has the 1838*0fca6ea1SDimitry Andric /// same type as the canonical induction. 183906c3fb27SDimitry Andric bool isCanonical() const; 184006c3fb27SDimitry Andric 184106c3fb27SDimitry Andric /// Returns the scalar type of the induction. 18425f757f3fSDimitry Andric Type *getScalarType() const { 184306c3fb27SDimitry Andric return Trunc ? Trunc->getType() : IV->getType(); 184406c3fb27SDimitry Andric } 184506c3fb27SDimitry Andric }; 184606c3fb27SDimitry Andric 184781ad6265SDimitry Andric class VPWidenPointerInductionRecipe : public VPHeaderPHIRecipe { 184881ad6265SDimitry Andric const InductionDescriptor &IndDesc; 184981ad6265SDimitry Andric 18506246ae0bSDimitry Andric bool IsScalarAfterVectorization; 18516246ae0bSDimitry Andric 185281ad6265SDimitry Andric public: 185381ad6265SDimitry Andric /// Create a new VPWidenPointerInductionRecipe for \p Phi with start value \p 185481ad6265SDimitry Andric /// Start. 1855bdd1243dSDimitry Andric VPWidenPointerInductionRecipe(PHINode *Phi, VPValue *Start, VPValue *Step, 185681ad6265SDimitry Andric const InductionDescriptor &IndDesc, 18576246ae0bSDimitry Andric bool IsScalarAfterVectorization) 1858bdd1243dSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPWidenPointerInductionSC, Phi), 1859bdd1243dSDimitry Andric IndDesc(IndDesc), 18606246ae0bSDimitry Andric IsScalarAfterVectorization(IsScalarAfterVectorization) { 186181ad6265SDimitry Andric addOperand(Start); 1862bdd1243dSDimitry Andric addOperand(Step); 186381ad6265SDimitry Andric } 186481ad6265SDimitry Andric 186581ad6265SDimitry Andric ~VPWidenPointerInductionRecipe() override = default; 186681ad6265SDimitry Andric 1867*0fca6ea1SDimitry Andric VPWidenPointerInductionRecipe *clone() override { 1868*0fca6ea1SDimitry Andric return new VPWidenPointerInductionRecipe( 1869*0fca6ea1SDimitry Andric cast<PHINode>(getUnderlyingInstr()), getOperand(0), getOperand(1), 1870*0fca6ea1SDimitry Andric IndDesc, IsScalarAfterVectorization); 1871*0fca6ea1SDimitry Andric } 1872*0fca6ea1SDimitry Andric 1873bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenPointerInductionSC) 187481ad6265SDimitry Andric 187581ad6265SDimitry Andric /// Generate vector values for the pointer induction. 187681ad6265SDimitry Andric void execute(VPTransformState &State) override; 187781ad6265SDimitry Andric 187881ad6265SDimitry Andric /// Returns true if only scalar values will be generated. 1879*0fca6ea1SDimitry Andric bool onlyScalarsGenerated(bool IsScalable); 188081ad6265SDimitry Andric 1881bdd1243dSDimitry Andric /// Returns the induction descriptor for the recipe. 1882bdd1243dSDimitry Andric const InductionDescriptor &getInductionDescriptor() const { return IndDesc; } 1883bdd1243dSDimitry Andric 188481ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 188581ad6265SDimitry Andric /// Print the recipe. 188681ad6265SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 188781ad6265SDimitry Andric VPSlotTracker &SlotTracker) const override; 188881ad6265SDimitry Andric #endif 188981ad6265SDimitry Andric }; 189081ad6265SDimitry Andric 1891*0fca6ea1SDimitry Andric /// A recipe for handling phis that are widened in the vector loop. 189204eeddc0SDimitry Andric /// In the VPlan native path, all incoming VPValues & VPBasicBlock pairs are 189304eeddc0SDimitry Andric /// managed in the recipe directly. 1894*0fca6ea1SDimitry Andric class VPWidenPHIRecipe : public VPSingleDefRecipe { 189504eeddc0SDimitry Andric /// List of incoming blocks. Only used in the VPlan native path. 189604eeddc0SDimitry Andric SmallVector<VPBasicBlock *, 2> IncomingBlocks; 189704eeddc0SDimitry Andric 189804eeddc0SDimitry Andric public: 1899fe6060f1SDimitry Andric /// Create a new VPWidenPHIRecipe for \p Phi with start value \p Start. 190004eeddc0SDimitry Andric VPWidenPHIRecipe(PHINode *Phi, VPValue *Start = nullptr) 1901*0fca6ea1SDimitry Andric : VPSingleDefRecipe(VPDef::VPWidenPHISC, ArrayRef<VPValue *>(), Phi) { 190204eeddc0SDimitry Andric if (Start) 190304eeddc0SDimitry Andric addOperand(Start); 1904e8d8bef9SDimitry Andric } 1905e8d8bef9SDimitry Andric 1906*0fca6ea1SDimitry Andric VPWidenPHIRecipe *clone() override { 1907*0fca6ea1SDimitry Andric llvm_unreachable("cloning not implemented yet"); 1908*0fca6ea1SDimitry Andric } 1909*0fca6ea1SDimitry Andric 19100b57cec5SDimitry Andric ~VPWidenPHIRecipe() override = default; 19110b57cec5SDimitry Andric 1912bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenPHISC) 19130b57cec5SDimitry Andric 19140b57cec5SDimitry Andric /// Generate the phi/select nodes. 19150b57cec5SDimitry Andric void execute(VPTransformState &State) override; 19160b57cec5SDimitry Andric 1917fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 19180b57cec5SDimitry Andric /// Print the recipe. 19195ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 19205ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 1921fe6060f1SDimitry Andric #endif 1922e8d8bef9SDimitry Andric 1923fe6060f1SDimitry Andric /// Adds a pair (\p IncomingV, \p IncomingBlock) to the phi. 1924fe6060f1SDimitry Andric void addIncoming(VPValue *IncomingV, VPBasicBlock *IncomingBlock) { 1925fe6060f1SDimitry Andric addOperand(IncomingV); 1926fe6060f1SDimitry Andric IncomingBlocks.push_back(IncomingBlock); 1927fe6060f1SDimitry Andric } 1928fe6060f1SDimitry Andric 1929fe6060f1SDimitry Andric /// Returns the \p I th incoming VPBasicBlock. 1930fe6060f1SDimitry Andric VPBasicBlock *getIncomingBlock(unsigned I) { return IncomingBlocks[I]; } 193104eeddc0SDimitry Andric 193204eeddc0SDimitry Andric /// Returns the \p I th incoming VPValue. 193304eeddc0SDimitry Andric VPValue *getIncomingValue(unsigned I) { return getOperand(I); } 1934fe6060f1SDimitry Andric }; 1935fe6060f1SDimitry Andric 1936fe6060f1SDimitry Andric /// A recipe for handling first-order recurrence phis. The start value is the 1937fe6060f1SDimitry Andric /// first operand of the recipe and the incoming value from the backedge is the 1938fe6060f1SDimitry Andric /// second operand. 193904eeddc0SDimitry Andric struct VPFirstOrderRecurrencePHIRecipe : public VPHeaderPHIRecipe { 1940fe6060f1SDimitry Andric VPFirstOrderRecurrencePHIRecipe(PHINode *Phi, VPValue &Start) 1941bdd1243dSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPFirstOrderRecurrencePHISC, Phi, &Start) {} 1942fe6060f1SDimitry Andric 1943bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPFirstOrderRecurrencePHISC) 1944bdd1243dSDimitry Andric 194504eeddc0SDimitry Andric static inline bool classof(const VPHeaderPHIRecipe *R) { 1946bdd1243dSDimitry Andric return R->getVPDefID() == VPDef::VPFirstOrderRecurrencePHISC; 1947fe6060f1SDimitry Andric } 1948fe6060f1SDimitry Andric 1949*0fca6ea1SDimitry Andric VPFirstOrderRecurrencePHIRecipe *clone() override { 1950*0fca6ea1SDimitry Andric return new VPFirstOrderRecurrencePHIRecipe( 1951*0fca6ea1SDimitry Andric cast<PHINode>(getUnderlyingInstr()), *getOperand(0)); 1952*0fca6ea1SDimitry Andric } 1953*0fca6ea1SDimitry Andric 1954fe6060f1SDimitry Andric void execute(VPTransformState &State) override; 1955fe6060f1SDimitry Andric 1956fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1957fe6060f1SDimitry Andric /// Print the recipe. 1958fe6060f1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 1959fe6060f1SDimitry Andric VPSlotTracker &SlotTracker) const override; 1960fe6060f1SDimitry Andric #endif 1961fe6060f1SDimitry Andric }; 1962fe6060f1SDimitry Andric 1963fe6060f1SDimitry Andric /// A recipe for handling reduction phis. The start value is the first operand 1964fe6060f1SDimitry Andric /// of the recipe and the incoming value from the backedge is the second 1965fe6060f1SDimitry Andric /// operand. 196604eeddc0SDimitry Andric class VPReductionPHIRecipe : public VPHeaderPHIRecipe { 1967fe6060f1SDimitry Andric /// Descriptor for the reduction. 19680eae32dcSDimitry Andric const RecurrenceDescriptor &RdxDesc; 1969fe6060f1SDimitry Andric 1970fe6060f1SDimitry Andric /// The phi is part of an in-loop reduction. 1971fe6060f1SDimitry Andric bool IsInLoop; 1972fe6060f1SDimitry Andric 1973fe6060f1SDimitry Andric /// The phi is part of an ordered reduction. Requires IsInLoop to be true. 1974fe6060f1SDimitry Andric bool IsOrdered; 1975fe6060f1SDimitry Andric 1976fe6060f1SDimitry Andric public: 1977fe6060f1SDimitry Andric /// Create a new VPReductionPHIRecipe for the reduction \p Phi described by \p 1978fe6060f1SDimitry Andric /// RdxDesc. 19790eae32dcSDimitry Andric VPReductionPHIRecipe(PHINode *Phi, const RecurrenceDescriptor &RdxDesc, 1980fe6060f1SDimitry Andric VPValue &Start, bool IsInLoop = false, 1981fe6060f1SDimitry Andric bool IsOrdered = false) 1982bdd1243dSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPReductionPHISC, Phi, &Start), 1983fe6060f1SDimitry Andric RdxDesc(RdxDesc), IsInLoop(IsInLoop), IsOrdered(IsOrdered) { 1984fe6060f1SDimitry Andric assert((!IsOrdered || IsInLoop) && "IsOrdered requires IsInLoop"); 1985fe6060f1SDimitry Andric } 1986fe6060f1SDimitry Andric 1987fe6060f1SDimitry Andric ~VPReductionPHIRecipe() override = default; 1988fe6060f1SDimitry Andric 1989*0fca6ea1SDimitry Andric VPReductionPHIRecipe *clone() override { 1990*0fca6ea1SDimitry Andric auto *R = 1991*0fca6ea1SDimitry Andric new VPReductionPHIRecipe(cast<PHINode>(getUnderlyingInstr()), RdxDesc, 1992*0fca6ea1SDimitry Andric *getOperand(0), IsInLoop, IsOrdered); 1993*0fca6ea1SDimitry Andric R->addOperand(getBackedgeValue()); 1994*0fca6ea1SDimitry Andric return R; 1995*0fca6ea1SDimitry Andric } 1996*0fca6ea1SDimitry Andric 1997bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPReductionPHISC) 1998bdd1243dSDimitry Andric 199904eeddc0SDimitry Andric static inline bool classof(const VPHeaderPHIRecipe *R) { 2000bdd1243dSDimitry Andric return R->getVPDefID() == VPDef::VPReductionPHISC; 2001fe6060f1SDimitry Andric } 2002fe6060f1SDimitry Andric 2003fe6060f1SDimitry Andric /// Generate the phi/select nodes. 2004fe6060f1SDimitry Andric void execute(VPTransformState &State) override; 2005fe6060f1SDimitry Andric 2006fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2007fe6060f1SDimitry Andric /// Print the recipe. 2008fe6060f1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2009fe6060f1SDimitry Andric VPSlotTracker &SlotTracker) const override; 2010fe6060f1SDimitry Andric #endif 2011fe6060f1SDimitry Andric 20120eae32dcSDimitry Andric const RecurrenceDescriptor &getRecurrenceDescriptor() const { 20130eae32dcSDimitry Andric return RdxDesc; 20140eae32dcSDimitry Andric } 2015fe6060f1SDimitry Andric 2016fe6060f1SDimitry Andric /// Returns true, if the phi is part of an ordered reduction. 2017fe6060f1SDimitry Andric bool isOrdered() const { return IsOrdered; } 2018fe6060f1SDimitry Andric 2019fe6060f1SDimitry Andric /// Returns true, if the phi is part of an in-loop reduction. 2020fe6060f1SDimitry Andric bool isInLoop() const { return IsInLoop; } 20210b57cec5SDimitry Andric }; 20220b57cec5SDimitry Andric 20230b57cec5SDimitry Andric /// A recipe for vectorizing a phi-node as a sequence of mask-based select 20240b57cec5SDimitry Andric /// instructions. 20257a6dacacSDimitry Andric class VPBlendRecipe : public VPSingleDefRecipe { 2026e8d8bef9SDimitry Andric public: 20275ffd83dbSDimitry Andric /// The blend operation is a User of the incoming values and of their 2028*0fca6ea1SDimitry Andric /// respective masks, ordered [I0, I1, M1, I2, M2, ...]. Note that the first 2029*0fca6ea1SDimitry Andric /// incoming value does not have a mask associated. 20305ffd83dbSDimitry Andric VPBlendRecipe(PHINode *Phi, ArrayRef<VPValue *> Operands) 20317a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPBlendSC, Operands, Phi, Phi->getDebugLoc()) { 2032*0fca6ea1SDimitry Andric assert((Operands.size() + 1) % 2 == 0 && 2033*0fca6ea1SDimitry Andric "Expected an odd number of operands"); 2034*0fca6ea1SDimitry Andric } 2035*0fca6ea1SDimitry Andric 2036*0fca6ea1SDimitry Andric VPBlendRecipe *clone() override { 2037*0fca6ea1SDimitry Andric SmallVector<VPValue *> Ops(operands()); 2038*0fca6ea1SDimitry Andric return new VPBlendRecipe(cast<PHINode>(getUnderlyingValue()), Ops); 20390b57cec5SDimitry Andric } 20400b57cec5SDimitry Andric 2041bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPBlendSC) 20420b57cec5SDimitry Andric 2043*0fca6ea1SDimitry Andric /// Return the number of incoming values, taking into account that the first 20445ffd83dbSDimitry Andric /// incoming value has no mask. 2045e8d8bef9SDimitry Andric unsigned getNumIncomingValues() const { return (getNumOperands() + 1) / 2; } 20465ffd83dbSDimitry Andric 20475ffd83dbSDimitry Andric /// Return incoming value number \p Idx. 2048*0fca6ea1SDimitry Andric VPValue *getIncomingValue(unsigned Idx) const { 2049*0fca6ea1SDimitry Andric return Idx == 0 ? getOperand(0) : getOperand(Idx * 2 - 1); 2050*0fca6ea1SDimitry Andric } 20515ffd83dbSDimitry Andric 20525ffd83dbSDimitry Andric /// Return mask number \p Idx. 2053*0fca6ea1SDimitry Andric VPValue *getMask(unsigned Idx) const { 2054*0fca6ea1SDimitry Andric assert(Idx > 0 && "First index has no mask associated."); 2055*0fca6ea1SDimitry Andric return getOperand(Idx * 2); 2056*0fca6ea1SDimitry Andric } 20575ffd83dbSDimitry Andric 20580b57cec5SDimitry Andric /// Generate the phi/select nodes. 20590b57cec5SDimitry Andric void execute(VPTransformState &State) override; 20600b57cec5SDimitry Andric 2061fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 20620b57cec5SDimitry Andric /// Print the recipe. 20635ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 20645ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 2065fe6060f1SDimitry Andric #endif 20661fd87a68SDimitry Andric 20671fd87a68SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 20681fd87a68SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 20691fd87a68SDimitry Andric assert(is_contained(operands(), Op) && 20701fd87a68SDimitry Andric "Op must be an operand of the recipe"); 20711fd87a68SDimitry Andric // Recursing through Blend recipes only, must terminate at header phi's the 20721fd87a68SDimitry Andric // latest. 207381ad6265SDimitry Andric return all_of(users(), 207481ad6265SDimitry Andric [this](VPUser *U) { return U->onlyFirstLaneUsed(this); }); 20751fd87a68SDimitry Andric } 20760b57cec5SDimitry Andric }; 20770b57cec5SDimitry Andric 20780b57cec5SDimitry Andric /// VPInterleaveRecipe is a recipe for transforming an interleave group of load 2079e8d8bef9SDimitry Andric /// or stores into one wide load/store and shuffles. The first operand of a 2080e8d8bef9SDimitry Andric /// VPInterleave recipe is the address, followed by the stored values, followed 2081e8d8bef9SDimitry Andric /// by an optional mask. 2082fe6060f1SDimitry Andric class VPInterleaveRecipe : public VPRecipeBase { 20830b57cec5SDimitry Andric const InterleaveGroup<Instruction> *IG; 2084e8d8bef9SDimitry Andric 208506c3fb27SDimitry Andric /// Indicates if the interleave group is in a conditional block and requires a 208606c3fb27SDimitry Andric /// mask. 2087e8d8bef9SDimitry Andric bool HasMask = false; 20880b57cec5SDimitry Andric 208906c3fb27SDimitry Andric /// Indicates if gaps between members of the group need to be masked out or if 209006c3fb27SDimitry Andric /// unusued gaps can be loaded speculatively. 209106c3fb27SDimitry Andric bool NeedsMaskForGaps = false; 209206c3fb27SDimitry Andric 20930b57cec5SDimitry Andric public: 2094480093f4SDimitry Andric VPInterleaveRecipe(const InterleaveGroup<Instruction> *IG, VPValue *Addr, 209506c3fb27SDimitry Andric ArrayRef<VPValue *> StoredValues, VPValue *Mask, 209606c3fb27SDimitry Andric bool NeedsMaskForGaps) 209706c3fb27SDimitry Andric : VPRecipeBase(VPDef::VPInterleaveSC, {Addr}), IG(IG), 209806c3fb27SDimitry Andric NeedsMaskForGaps(NeedsMaskForGaps) { 2099e8d8bef9SDimitry Andric for (unsigned i = 0; i < IG->getFactor(); ++i) 2100e8d8bef9SDimitry Andric if (Instruction *I = IG->getMember(i)) { 2101e8d8bef9SDimitry Andric if (I->getType()->isVoidTy()) 2102e8d8bef9SDimitry Andric continue; 2103e8d8bef9SDimitry Andric new VPValue(I, this); 2104e8d8bef9SDimitry Andric } 2105e8d8bef9SDimitry Andric 2106e8d8bef9SDimitry Andric for (auto *SV : StoredValues) 2107e8d8bef9SDimitry Andric addOperand(SV); 2108e8d8bef9SDimitry Andric if (Mask) { 2109e8d8bef9SDimitry Andric HasMask = true; 2110e8d8bef9SDimitry Andric addOperand(Mask); 2111e8d8bef9SDimitry Andric } 21120b57cec5SDimitry Andric } 21130b57cec5SDimitry Andric ~VPInterleaveRecipe() override = default; 21140b57cec5SDimitry Andric 2115*0fca6ea1SDimitry Andric VPInterleaveRecipe *clone() override { 2116*0fca6ea1SDimitry Andric return new VPInterleaveRecipe(IG, getAddr(), getStoredValues(), getMask(), 2117*0fca6ea1SDimitry Andric NeedsMaskForGaps); 2118*0fca6ea1SDimitry Andric } 2119*0fca6ea1SDimitry Andric 2120bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPInterleaveSC) 21210b57cec5SDimitry Andric 2122480093f4SDimitry Andric /// Return the address accessed by this recipe. 2123480093f4SDimitry Andric VPValue *getAddr() const { 2124e8d8bef9SDimitry Andric return getOperand(0); // Address is the 1st, mandatory operand. 2125480093f4SDimitry Andric } 2126480093f4SDimitry Andric 2127480093f4SDimitry Andric /// Return the mask used by this recipe. Note that a full mask is represented 2128480093f4SDimitry Andric /// by a nullptr. 2129480093f4SDimitry Andric VPValue *getMask() const { 2130480093f4SDimitry Andric // Mask is optional and therefore the last, currently 2nd operand. 2131e8d8bef9SDimitry Andric return HasMask ? getOperand(getNumOperands() - 1) : nullptr; 2132e8d8bef9SDimitry Andric } 2133e8d8bef9SDimitry Andric 2134e8d8bef9SDimitry Andric /// Return the VPValues stored by this interleave group. If it is a load 2135e8d8bef9SDimitry Andric /// interleave group, return an empty ArrayRef. 2136e8d8bef9SDimitry Andric ArrayRef<VPValue *> getStoredValues() const { 2137e8d8bef9SDimitry Andric // The first operand is the address, followed by the stored values, followed 2138e8d8bef9SDimitry Andric // by an optional mask. 2139e8d8bef9SDimitry Andric return ArrayRef<VPValue *>(op_begin(), getNumOperands()) 2140349cc55cSDimitry Andric .slice(1, getNumStoreOperands()); 2141480093f4SDimitry Andric } 2142480093f4SDimitry Andric 21430b57cec5SDimitry Andric /// Generate the wide load or store, and shuffles. 21440b57cec5SDimitry Andric void execute(VPTransformState &State) override; 21450b57cec5SDimitry Andric 2146fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 21470b57cec5SDimitry Andric /// Print the recipe. 21485ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 21495ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 2150fe6060f1SDimitry Andric #endif 21510b57cec5SDimitry Andric 21520b57cec5SDimitry Andric const InterleaveGroup<Instruction> *getInterleaveGroup() { return IG; } 2153349cc55cSDimitry Andric 2154349cc55cSDimitry Andric /// Returns the number of stored operands of this interleave group. Returns 0 2155349cc55cSDimitry Andric /// for load interleave groups. 2156349cc55cSDimitry Andric unsigned getNumStoreOperands() const { 2157349cc55cSDimitry Andric return getNumOperands() - (HasMask ? 2 : 1); 2158349cc55cSDimitry Andric } 215981ad6265SDimitry Andric 216081ad6265SDimitry Andric /// The recipe only uses the first lane of the address. 216181ad6265SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 216281ad6265SDimitry Andric assert(is_contained(operands(), Op) && 216381ad6265SDimitry Andric "Op must be an operand of the recipe"); 2164bdd1243dSDimitry Andric return Op == getAddr() && !llvm::is_contained(getStoredValues(), Op); 216581ad6265SDimitry Andric } 2166*0fca6ea1SDimitry Andric 2167*0fca6ea1SDimitry Andric Instruction *getInsertPos() const { return IG->getInsertPos(); } 21680b57cec5SDimitry Andric }; 21690b57cec5SDimitry Andric 2170e8d8bef9SDimitry Andric /// A recipe to represent inloop reduction operations, performing a reduction on 2171e8d8bef9SDimitry Andric /// a vector operand into a scalar value, and adding the result to a chain. 2172e8d8bef9SDimitry Andric /// The Operands are {ChainOp, VecOp, [Condition]}. 21737a6dacacSDimitry Andric class VPReductionRecipe : public VPSingleDefRecipe { 2174e8d8bef9SDimitry Andric /// The recurrence decriptor for the reduction in question. 21755f757f3fSDimitry Andric const RecurrenceDescriptor &RdxDesc; 2176*0fca6ea1SDimitry Andric bool IsOrdered; 2177*0fca6ea1SDimitry Andric /// Whether the reduction is conditional. 2178*0fca6ea1SDimitry Andric bool IsConditional = false; 2179*0fca6ea1SDimitry Andric 2180*0fca6ea1SDimitry Andric protected: 2181*0fca6ea1SDimitry Andric VPReductionRecipe(const unsigned char SC, const RecurrenceDescriptor &R, 2182*0fca6ea1SDimitry Andric Instruction *I, ArrayRef<VPValue *> Operands, 2183*0fca6ea1SDimitry Andric VPValue *CondOp, bool IsOrdered) 2184*0fca6ea1SDimitry Andric : VPSingleDefRecipe(SC, Operands, I), RdxDesc(R), IsOrdered(IsOrdered) { 2185*0fca6ea1SDimitry Andric if (CondOp) { 2186*0fca6ea1SDimitry Andric IsConditional = true; 2187*0fca6ea1SDimitry Andric addOperand(CondOp); 2188*0fca6ea1SDimitry Andric } 2189*0fca6ea1SDimitry Andric } 2190e8d8bef9SDimitry Andric 2191e8d8bef9SDimitry Andric public: 21925f757f3fSDimitry Andric VPReductionRecipe(const RecurrenceDescriptor &R, Instruction *I, 2193*0fca6ea1SDimitry Andric VPValue *ChainOp, VPValue *VecOp, VPValue *CondOp, 2194*0fca6ea1SDimitry Andric bool IsOrdered) 2195*0fca6ea1SDimitry Andric : VPReductionRecipe(VPDef::VPReductionSC, R, I, 2196*0fca6ea1SDimitry Andric ArrayRef<VPValue *>({ChainOp, VecOp}), CondOp, 2197*0fca6ea1SDimitry Andric IsOrdered) {} 2198e8d8bef9SDimitry Andric 2199e8d8bef9SDimitry Andric ~VPReductionRecipe() override = default; 2200e8d8bef9SDimitry Andric 2201*0fca6ea1SDimitry Andric VPReductionRecipe *clone() override { 2202*0fca6ea1SDimitry Andric return new VPReductionRecipe(RdxDesc, getUnderlyingInstr(), getChainOp(), 2203*0fca6ea1SDimitry Andric getVecOp(), getCondOp(), IsOrdered); 2204*0fca6ea1SDimitry Andric } 2205*0fca6ea1SDimitry Andric 2206*0fca6ea1SDimitry Andric static inline bool classof(const VPRecipeBase *R) { 2207*0fca6ea1SDimitry Andric return R->getVPDefID() == VPRecipeBase::VPReductionSC || 2208*0fca6ea1SDimitry Andric R->getVPDefID() == VPRecipeBase::VPReductionEVLSC; 2209*0fca6ea1SDimitry Andric } 2210*0fca6ea1SDimitry Andric 2211*0fca6ea1SDimitry Andric static inline bool classof(const VPUser *U) { 2212*0fca6ea1SDimitry Andric auto *R = dyn_cast<VPRecipeBase>(U); 2213*0fca6ea1SDimitry Andric return R && classof(R); 2214*0fca6ea1SDimitry Andric } 2215e8d8bef9SDimitry Andric 2216e8d8bef9SDimitry Andric /// Generate the reduction in the loop 2217e8d8bef9SDimitry Andric void execute(VPTransformState &State) override; 2218e8d8bef9SDimitry Andric 2219fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2220e8d8bef9SDimitry Andric /// Print the recipe. 2221e8d8bef9SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2222e8d8bef9SDimitry Andric VPSlotTracker &SlotTracker) const override; 2223fe6060f1SDimitry Andric #endif 2224e8d8bef9SDimitry Andric 2225*0fca6ea1SDimitry Andric /// Return the recurrence decriptor for the in-loop reduction. 2226*0fca6ea1SDimitry Andric const RecurrenceDescriptor &getRecurrenceDescriptor() const { 2227*0fca6ea1SDimitry Andric return RdxDesc; 2228*0fca6ea1SDimitry Andric } 2229*0fca6ea1SDimitry Andric /// Return true if the in-loop reduction is ordered. 2230*0fca6ea1SDimitry Andric bool isOrdered() const { return IsOrdered; }; 2231*0fca6ea1SDimitry Andric /// Return true if the in-loop reduction is conditional. 2232*0fca6ea1SDimitry Andric bool isConditional() const { return IsConditional; }; 2233e8d8bef9SDimitry Andric /// The VPValue of the scalar Chain being accumulated. 2234e8d8bef9SDimitry Andric VPValue *getChainOp() const { return getOperand(0); } 2235e8d8bef9SDimitry Andric /// The VPValue of the vector value to be reduced. 2236e8d8bef9SDimitry Andric VPValue *getVecOp() const { return getOperand(1); } 2237e8d8bef9SDimitry Andric /// The VPValue of the condition for the block. 2238e8d8bef9SDimitry Andric VPValue *getCondOp() const { 2239*0fca6ea1SDimitry Andric return isConditional() ? getOperand(getNumOperands() - 1) : nullptr; 2240*0fca6ea1SDimitry Andric } 2241*0fca6ea1SDimitry Andric }; 2242*0fca6ea1SDimitry Andric 2243*0fca6ea1SDimitry Andric /// A recipe to represent inloop reduction operations with vector-predication 2244*0fca6ea1SDimitry Andric /// intrinsics, performing a reduction on a vector operand with the explicit 2245*0fca6ea1SDimitry Andric /// vector length (EVL) into a scalar value, and adding the result to a chain. 2246*0fca6ea1SDimitry Andric /// The Operands are {ChainOp, VecOp, EVL, [Condition]}. 2247*0fca6ea1SDimitry Andric class VPReductionEVLRecipe : public VPReductionRecipe { 2248*0fca6ea1SDimitry Andric public: 2249*0fca6ea1SDimitry Andric VPReductionEVLRecipe(VPReductionRecipe *R, VPValue *EVL, VPValue *CondOp) 2250*0fca6ea1SDimitry Andric : VPReductionRecipe( 2251*0fca6ea1SDimitry Andric VPDef::VPReductionEVLSC, R->getRecurrenceDescriptor(), 2252*0fca6ea1SDimitry Andric cast_or_null<Instruction>(R->getUnderlyingValue()), 2253*0fca6ea1SDimitry Andric ArrayRef<VPValue *>({R->getChainOp(), R->getVecOp(), EVL}), CondOp, 2254*0fca6ea1SDimitry Andric R->isOrdered()) {} 2255*0fca6ea1SDimitry Andric 2256*0fca6ea1SDimitry Andric ~VPReductionEVLRecipe() override = default; 2257*0fca6ea1SDimitry Andric 2258*0fca6ea1SDimitry Andric VPReductionEVLRecipe *clone() override { 2259*0fca6ea1SDimitry Andric llvm_unreachable("cloning not implemented yet"); 2260*0fca6ea1SDimitry Andric } 2261*0fca6ea1SDimitry Andric 2262*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPReductionEVLSC) 2263*0fca6ea1SDimitry Andric 2264*0fca6ea1SDimitry Andric /// Generate the reduction in the loop 2265*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override; 2266*0fca6ea1SDimitry Andric 2267*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2268*0fca6ea1SDimitry Andric /// Print the recipe. 2269*0fca6ea1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2270*0fca6ea1SDimitry Andric VPSlotTracker &SlotTracker) const override; 2271*0fca6ea1SDimitry Andric #endif 2272*0fca6ea1SDimitry Andric 2273*0fca6ea1SDimitry Andric /// The VPValue of the explicit vector length. 2274*0fca6ea1SDimitry Andric VPValue *getEVL() const { return getOperand(2); } 2275*0fca6ea1SDimitry Andric 2276*0fca6ea1SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 2277*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 2278*0fca6ea1SDimitry Andric assert(is_contained(operands(), Op) && 2279*0fca6ea1SDimitry Andric "Op must be an operand of the recipe"); 2280*0fca6ea1SDimitry Andric return Op == getEVL(); 2281e8d8bef9SDimitry Andric } 2282e8d8bef9SDimitry Andric }; 2283e8d8bef9SDimitry Andric 22840b57cec5SDimitry Andric /// VPReplicateRecipe replicates a given instruction producing multiple scalar 22850b57cec5SDimitry Andric /// copies of the original scalar type, one per lane, instead of producing a 22860b57cec5SDimitry Andric /// single copy of widened type for all lanes. If the instruction is known to be 22870b57cec5SDimitry Andric /// uniform only one copy, per lane zero, will be generated. 22887a6dacacSDimitry Andric class VPReplicateRecipe : public VPRecipeWithIRFlags { 22890b57cec5SDimitry Andric /// Indicator if only a single replica per lane is needed. 22900b57cec5SDimitry Andric bool IsUniform; 22910b57cec5SDimitry Andric 22920b57cec5SDimitry Andric /// Indicator if the replicas are also predicated. 22930b57cec5SDimitry Andric bool IsPredicated; 22940b57cec5SDimitry Andric 22950b57cec5SDimitry Andric public: 22965ffd83dbSDimitry Andric template <typename IterT> 22975ffd83dbSDimitry Andric VPReplicateRecipe(Instruction *I, iterator_range<IterT> Operands, 229806c3fb27SDimitry Andric bool IsUniform, VPValue *Mask = nullptr) 229906c3fb27SDimitry Andric : VPRecipeWithIRFlags(VPDef::VPReplicateSC, Operands, *I), 23007a6dacacSDimitry Andric IsUniform(IsUniform), IsPredicated(Mask) { 230106c3fb27SDimitry Andric if (Mask) 230206c3fb27SDimitry Andric addOperand(Mask); 23030b57cec5SDimitry Andric } 23040b57cec5SDimitry Andric 23050b57cec5SDimitry Andric ~VPReplicateRecipe() override = default; 23060b57cec5SDimitry Andric 2307*0fca6ea1SDimitry Andric VPReplicateRecipe *clone() override { 2308*0fca6ea1SDimitry Andric auto *Copy = 2309*0fca6ea1SDimitry Andric new VPReplicateRecipe(getUnderlyingInstr(), operands(), IsUniform, 2310*0fca6ea1SDimitry Andric isPredicated() ? getMask() : nullptr); 2311*0fca6ea1SDimitry Andric Copy->transferFlags(*this); 2312*0fca6ea1SDimitry Andric return Copy; 2313*0fca6ea1SDimitry Andric } 2314*0fca6ea1SDimitry Andric 2315bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPReplicateSC) 23160b57cec5SDimitry Andric 23170b57cec5SDimitry Andric /// Generate replicas of the desired Ingredient. Replicas will be generated 23180b57cec5SDimitry Andric /// for all parts and lanes unless a specific part and lane are specified in 23190b57cec5SDimitry Andric /// the \p State. 23200b57cec5SDimitry Andric void execute(VPTransformState &State) override; 23210b57cec5SDimitry Andric 2322fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 23230b57cec5SDimitry Andric /// Print the recipe. 23245ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 23255ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 2326fe6060f1SDimitry Andric #endif 2327e8d8bef9SDimitry Andric 2328e8d8bef9SDimitry Andric bool isUniform() const { return IsUniform; } 2329fe6060f1SDimitry Andric 2330fe6060f1SDimitry Andric bool isPredicated() const { return IsPredicated; } 23311fd87a68SDimitry Andric 23321fd87a68SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 23331fd87a68SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 23341fd87a68SDimitry Andric assert(is_contained(operands(), Op) && 23351fd87a68SDimitry Andric "Op must be an operand of the recipe"); 23361fd87a68SDimitry Andric return isUniform(); 23371fd87a68SDimitry Andric } 233881ad6265SDimitry Andric 233981ad6265SDimitry Andric /// Returns true if the recipe uses scalars of operand \p Op. 234081ad6265SDimitry Andric bool usesScalars(const VPValue *Op) const override { 234181ad6265SDimitry Andric assert(is_contained(operands(), Op) && 234281ad6265SDimitry Andric "Op must be an operand of the recipe"); 234381ad6265SDimitry Andric return true; 234481ad6265SDimitry Andric } 234506c3fb27SDimitry Andric 234606c3fb27SDimitry Andric /// Returns true if the recipe is used by a widened recipe via an intervening 234706c3fb27SDimitry Andric /// VPPredInstPHIRecipe. In this case, the scalar values should also be packed 234806c3fb27SDimitry Andric /// in a vector. 234906c3fb27SDimitry Andric bool shouldPack() const; 235006c3fb27SDimitry Andric 235106c3fb27SDimitry Andric /// Return the mask of a predicated VPReplicateRecipe. 235206c3fb27SDimitry Andric VPValue *getMask() { 235306c3fb27SDimitry Andric assert(isPredicated() && "Trying to get the mask of a unpredicated recipe"); 235406c3fb27SDimitry Andric return getOperand(getNumOperands() - 1); 235506c3fb27SDimitry Andric } 2356*0fca6ea1SDimitry Andric 2357*0fca6ea1SDimitry Andric unsigned getOpcode() const { return getUnderlyingInstr()->getOpcode(); } 23580b57cec5SDimitry Andric }; 23590b57cec5SDimitry Andric 23600b57cec5SDimitry Andric /// A recipe for generating conditional branches on the bits of a mask. 2361fe6060f1SDimitry Andric class VPBranchOnMaskRecipe : public VPRecipeBase { 23620b57cec5SDimitry Andric public: 2363fe6060f1SDimitry Andric VPBranchOnMaskRecipe(VPValue *BlockInMask) 2364bdd1243dSDimitry Andric : VPRecipeBase(VPDef::VPBranchOnMaskSC, {}) { 23650b57cec5SDimitry Andric if (BlockInMask) // nullptr means all-one mask. 2366e8d8bef9SDimitry Andric addOperand(BlockInMask); 23670b57cec5SDimitry Andric } 23680b57cec5SDimitry Andric 2369*0fca6ea1SDimitry Andric VPBranchOnMaskRecipe *clone() override { 2370*0fca6ea1SDimitry Andric return new VPBranchOnMaskRecipe(getOperand(0)); 2371*0fca6ea1SDimitry Andric } 2372*0fca6ea1SDimitry Andric 2373bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPBranchOnMaskSC) 23740b57cec5SDimitry Andric 23750b57cec5SDimitry Andric /// Generate the extraction of the appropriate bit from the block mask and the 23760b57cec5SDimitry Andric /// conditional branch. 23770b57cec5SDimitry Andric void execute(VPTransformState &State) override; 23780b57cec5SDimitry Andric 2379fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 23800b57cec5SDimitry Andric /// Print the recipe. 23815ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 23825ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override { 2383fe6060f1SDimitry Andric O << Indent << "BRANCH-ON-MASK "; 23845ffd83dbSDimitry Andric if (VPValue *Mask = getMask()) 2385e8d8bef9SDimitry Andric Mask->printAsOperand(O, SlotTracker); 23860b57cec5SDimitry Andric else 23870b57cec5SDimitry Andric O << " All-One"; 23880b57cec5SDimitry Andric } 2389fe6060f1SDimitry Andric #endif 23905ffd83dbSDimitry Andric 23915ffd83dbSDimitry Andric /// Return the mask used by this recipe. Note that a full mask is represented 23925ffd83dbSDimitry Andric /// by a nullptr. 23935ffd83dbSDimitry Andric VPValue *getMask() const { 2394e8d8bef9SDimitry Andric assert(getNumOperands() <= 1 && "should have either 0 or 1 operands"); 23955ffd83dbSDimitry Andric // Mask is optional. 2396e8d8bef9SDimitry Andric return getNumOperands() == 1 ? getOperand(0) : nullptr; 23975ffd83dbSDimitry Andric } 239881ad6265SDimitry Andric 239981ad6265SDimitry Andric /// Returns true if the recipe uses scalars of operand \p Op. 240081ad6265SDimitry Andric bool usesScalars(const VPValue *Op) const override { 240181ad6265SDimitry Andric assert(is_contained(operands(), Op) && 240281ad6265SDimitry Andric "Op must be an operand of the recipe"); 240381ad6265SDimitry Andric return true; 240481ad6265SDimitry Andric } 24050b57cec5SDimitry Andric }; 24060b57cec5SDimitry Andric 24070b57cec5SDimitry Andric /// VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when 24080b57cec5SDimitry Andric /// control converges back from a Branch-on-Mask. The phi nodes are needed in 24090b57cec5SDimitry Andric /// order to merge values that are set under such a branch and feed their uses. 24100b57cec5SDimitry Andric /// The phi nodes can be scalar or vector depending on the users of the value. 24110b57cec5SDimitry Andric /// This recipe works in concert with VPBranchOnMaskRecipe. 24127a6dacacSDimitry Andric class VPPredInstPHIRecipe : public VPSingleDefRecipe { 24130b57cec5SDimitry Andric public: 24140b57cec5SDimitry Andric /// Construct a VPPredInstPHIRecipe given \p PredInst whose value needs a phi 24150b57cec5SDimitry Andric /// nodes after merging back from a Branch-on-Mask. 2416e8d8bef9SDimitry Andric VPPredInstPHIRecipe(VPValue *PredV) 24177a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPPredInstPHISC, PredV) {} 24180b57cec5SDimitry Andric ~VPPredInstPHIRecipe() override = default; 24190b57cec5SDimitry Andric 2420*0fca6ea1SDimitry Andric VPPredInstPHIRecipe *clone() override { 2421*0fca6ea1SDimitry Andric return new VPPredInstPHIRecipe(getOperand(0)); 2422*0fca6ea1SDimitry Andric } 2423*0fca6ea1SDimitry Andric 2424bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPPredInstPHISC) 24250b57cec5SDimitry Andric 24260b57cec5SDimitry Andric /// Generates phi nodes for live-outs as needed to retain SSA form. 24270b57cec5SDimitry Andric void execute(VPTransformState &State) override; 24280b57cec5SDimitry Andric 2429fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 24300b57cec5SDimitry Andric /// Print the recipe. 24315ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 24325ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 2433fe6060f1SDimitry Andric #endif 243481ad6265SDimitry Andric 243581ad6265SDimitry Andric /// Returns true if the recipe uses scalars of operand \p Op. 243681ad6265SDimitry Andric bool usesScalars(const VPValue *Op) const override { 243781ad6265SDimitry Andric assert(is_contained(operands(), Op) && 243881ad6265SDimitry Andric "Op must be an operand of the recipe"); 243981ad6265SDimitry Andric return true; 244081ad6265SDimitry Andric } 24410b57cec5SDimitry Andric }; 24420b57cec5SDimitry Andric 2443*0fca6ea1SDimitry Andric /// A common base class for widening memory operations. An optional mask can be 2444*0fca6ea1SDimitry Andric /// provided as the last operand. 2445*0fca6ea1SDimitry Andric class VPWidenMemoryRecipe : public VPRecipeBase { 2446*0fca6ea1SDimitry Andric protected: 2447e8d8bef9SDimitry Andric Instruction &Ingredient; 24480b57cec5SDimitry Andric 2449*0fca6ea1SDimitry Andric /// Whether the accessed addresses are consecutive. 2450349cc55cSDimitry Andric bool Consecutive; 2451349cc55cSDimitry Andric 2452*0fca6ea1SDimitry Andric /// Whether the consecutive accessed addresses are in reverse order. 2453349cc55cSDimitry Andric bool Reverse; 2454349cc55cSDimitry Andric 2455*0fca6ea1SDimitry Andric /// Whether the memory access is masked. 2456*0fca6ea1SDimitry Andric bool IsMasked = false; 2457*0fca6ea1SDimitry Andric 24585ffd83dbSDimitry Andric void setMask(VPValue *Mask) { 2459*0fca6ea1SDimitry Andric assert(!IsMasked && "cannot re-set mask"); 24605ffd83dbSDimitry Andric if (!Mask) 24615ffd83dbSDimitry Andric return; 2462e8d8bef9SDimitry Andric addOperand(Mask); 2463*0fca6ea1SDimitry Andric IsMasked = true; 24640b57cec5SDimitry Andric } 24650b57cec5SDimitry Andric 2466*0fca6ea1SDimitry Andric VPWidenMemoryRecipe(const char unsigned SC, Instruction &I, 2467*0fca6ea1SDimitry Andric std::initializer_list<VPValue *> Operands, 2468*0fca6ea1SDimitry Andric bool Consecutive, bool Reverse, DebugLoc DL) 2469*0fca6ea1SDimitry Andric : VPRecipeBase(SC, Operands, DL), Ingredient(I), Consecutive(Consecutive), 2470*0fca6ea1SDimitry Andric Reverse(Reverse) { 2471*0fca6ea1SDimitry Andric assert((Consecutive || !Reverse) && "Reverse implies consecutive"); 24725ffd83dbSDimitry Andric } 24735ffd83dbSDimitry Andric 24745ffd83dbSDimitry Andric public: 2475*0fca6ea1SDimitry Andric VPWidenMemoryRecipe *clone() override { 2476*0fca6ea1SDimitry Andric llvm_unreachable("cloning not supported"); 24775ffd83dbSDimitry Andric } 24785ffd83dbSDimitry Andric 2479*0fca6ea1SDimitry Andric static inline bool classof(const VPRecipeBase *R) { 2480*0fca6ea1SDimitry Andric return R->getVPDefID() == VPRecipeBase::VPWidenLoadSC || 2481*0fca6ea1SDimitry Andric R->getVPDefID() == VPRecipeBase::VPWidenStoreSC || 2482*0fca6ea1SDimitry Andric R->getVPDefID() == VPRecipeBase::VPWidenLoadEVLSC || 2483*0fca6ea1SDimitry Andric R->getVPDefID() == VPRecipeBase::VPWidenStoreEVLSC; 24845ffd83dbSDimitry Andric } 24855ffd83dbSDimitry Andric 2486*0fca6ea1SDimitry Andric static inline bool classof(const VPUser *U) { 2487*0fca6ea1SDimitry Andric auto *R = dyn_cast<VPRecipeBase>(U); 2488*0fca6ea1SDimitry Andric return R && classof(R); 2489*0fca6ea1SDimitry Andric } 2490*0fca6ea1SDimitry Andric 2491*0fca6ea1SDimitry Andric /// Return whether the loaded-from / stored-to addresses are consecutive. 2492*0fca6ea1SDimitry Andric bool isConsecutive() const { return Consecutive; } 2493*0fca6ea1SDimitry Andric 2494*0fca6ea1SDimitry Andric /// Return whether the consecutive loaded/stored addresses are in reverse 2495*0fca6ea1SDimitry Andric /// order. 2496*0fca6ea1SDimitry Andric bool isReverse() const { return Reverse; } 24970b57cec5SDimitry Andric 2498480093f4SDimitry Andric /// Return the address accessed by this recipe. 2499*0fca6ea1SDimitry Andric VPValue *getAddr() const { return getOperand(0); } 2500*0fca6ea1SDimitry Andric 2501*0fca6ea1SDimitry Andric /// Returns true if the recipe is masked. 2502*0fca6ea1SDimitry Andric bool isMasked() const { return IsMasked; } 2503480093f4SDimitry Andric 2504480093f4SDimitry Andric /// Return the mask used by this recipe. Note that a full mask is represented 2505480093f4SDimitry Andric /// by a nullptr. 2506480093f4SDimitry Andric VPValue *getMask() const { 25075ffd83dbSDimitry Andric // Mask is optional and therefore the last operand. 2508e8d8bef9SDimitry Andric return isMasked() ? getOperand(getNumOperands() - 1) : nullptr; 25095ffd83dbSDimitry Andric } 25105ffd83dbSDimitry Andric 2511*0fca6ea1SDimitry Andric /// Generate the wide load/store. 2512*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override { 2513*0fca6ea1SDimitry Andric llvm_unreachable("VPWidenMemoryRecipe should not be instantiated."); 2514480093f4SDimitry Andric } 2515480093f4SDimitry Andric 2516*0fca6ea1SDimitry Andric Instruction &getIngredient() const { return Ingredient; } 2517*0fca6ea1SDimitry Andric }; 2518349cc55cSDimitry Andric 2519*0fca6ea1SDimitry Andric /// A recipe for widening load operations, using the address to load from and an 2520*0fca6ea1SDimitry Andric /// optional mask. 2521*0fca6ea1SDimitry Andric struct VPWidenLoadRecipe final : public VPWidenMemoryRecipe, public VPValue { 2522*0fca6ea1SDimitry Andric VPWidenLoadRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask, 2523*0fca6ea1SDimitry Andric bool Consecutive, bool Reverse, DebugLoc DL) 2524*0fca6ea1SDimitry Andric : VPWidenMemoryRecipe(VPDef::VPWidenLoadSC, Load, {Addr}, Consecutive, 2525*0fca6ea1SDimitry Andric Reverse, DL), 2526*0fca6ea1SDimitry Andric VPValue(this, &Load) { 2527*0fca6ea1SDimitry Andric setMask(Mask); 2528*0fca6ea1SDimitry Andric } 2529349cc55cSDimitry Andric 2530*0fca6ea1SDimitry Andric VPWidenLoadRecipe *clone() override { 2531*0fca6ea1SDimitry Andric return new VPWidenLoadRecipe(cast<LoadInst>(Ingredient), getAddr(), 2532*0fca6ea1SDimitry Andric getMask(), Consecutive, Reverse, 2533*0fca6ea1SDimitry Andric getDebugLoc()); 2534*0fca6ea1SDimitry Andric } 2535*0fca6ea1SDimitry Andric 2536*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenLoadSC); 2537*0fca6ea1SDimitry Andric 2538*0fca6ea1SDimitry Andric /// Generate a wide load or gather. 25390b57cec5SDimitry Andric void execute(VPTransformState &State) override; 25400b57cec5SDimitry Andric 2541fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 25420b57cec5SDimitry Andric /// Print the recipe. 25435ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 25445ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 2545fe6060f1SDimitry Andric #endif 25461fd87a68SDimitry Andric 25471fd87a68SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 25481fd87a68SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 25491fd87a68SDimitry Andric assert(is_contained(operands(), Op) && 25501fd87a68SDimitry Andric "Op must be an operand of the recipe"); 2551*0fca6ea1SDimitry Andric // Widened, consecutive loads operations only demand the first lane of 2552*0fca6ea1SDimitry Andric // their address. 2553*0fca6ea1SDimitry Andric return Op == getAddr() && isConsecutive(); 2554*0fca6ea1SDimitry Andric } 2555*0fca6ea1SDimitry Andric }; 25561fd87a68SDimitry Andric 2557*0fca6ea1SDimitry Andric /// A recipe for widening load operations with vector-predication intrinsics, 2558*0fca6ea1SDimitry Andric /// using the address to load from, the explicit vector length and an optional 2559*0fca6ea1SDimitry Andric /// mask. 2560*0fca6ea1SDimitry Andric struct VPWidenLoadEVLRecipe final : public VPWidenMemoryRecipe, public VPValue { 2561*0fca6ea1SDimitry Andric VPWidenLoadEVLRecipe(VPWidenLoadRecipe *L, VPValue *EVL, VPValue *Mask) 2562*0fca6ea1SDimitry Andric : VPWidenMemoryRecipe(VPDef::VPWidenLoadEVLSC, L->getIngredient(), 2563*0fca6ea1SDimitry Andric {L->getAddr(), EVL}, L->isConsecutive(), 2564*0fca6ea1SDimitry Andric L->isReverse(), L->getDebugLoc()), 2565*0fca6ea1SDimitry Andric VPValue(this, &getIngredient()) { 2566*0fca6ea1SDimitry Andric setMask(Mask); 2567*0fca6ea1SDimitry Andric } 2568*0fca6ea1SDimitry Andric 2569*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenLoadEVLSC) 2570*0fca6ea1SDimitry Andric 2571*0fca6ea1SDimitry Andric /// Return the EVL operand. 2572*0fca6ea1SDimitry Andric VPValue *getEVL() const { return getOperand(1); } 2573*0fca6ea1SDimitry Andric 2574*0fca6ea1SDimitry Andric /// Generate the wide load or gather. 2575*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override; 2576*0fca6ea1SDimitry Andric 2577*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2578*0fca6ea1SDimitry Andric /// Print the recipe. 2579*0fca6ea1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2580*0fca6ea1SDimitry Andric VPSlotTracker &SlotTracker) const override; 2581*0fca6ea1SDimitry Andric #endif 2582*0fca6ea1SDimitry Andric 2583*0fca6ea1SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 2584*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 2585*0fca6ea1SDimitry Andric assert(is_contained(operands(), Op) && 2586*0fca6ea1SDimitry Andric "Op must be an operand of the recipe"); 2587*0fca6ea1SDimitry Andric // Widened loads only demand the first lane of EVL and consecutive loads 2588*0fca6ea1SDimitry Andric // only demand the first lane of their address. 2589*0fca6ea1SDimitry Andric return Op == getEVL() || (Op == getAddr() && isConsecutive()); 2590*0fca6ea1SDimitry Andric } 2591*0fca6ea1SDimitry Andric }; 2592*0fca6ea1SDimitry Andric 2593*0fca6ea1SDimitry Andric /// A recipe for widening store operations, using the stored value, the address 2594*0fca6ea1SDimitry Andric /// to store to and an optional mask. 2595*0fca6ea1SDimitry Andric struct VPWidenStoreRecipe final : public VPWidenMemoryRecipe { 2596*0fca6ea1SDimitry Andric VPWidenStoreRecipe(StoreInst &Store, VPValue *Addr, VPValue *StoredVal, 2597*0fca6ea1SDimitry Andric VPValue *Mask, bool Consecutive, bool Reverse, DebugLoc DL) 2598*0fca6ea1SDimitry Andric : VPWidenMemoryRecipe(VPDef::VPWidenStoreSC, Store, {Addr, StoredVal}, 2599*0fca6ea1SDimitry Andric Consecutive, Reverse, DL) { 2600*0fca6ea1SDimitry Andric setMask(Mask); 2601*0fca6ea1SDimitry Andric } 2602*0fca6ea1SDimitry Andric 2603*0fca6ea1SDimitry Andric VPWidenStoreRecipe *clone() override { 2604*0fca6ea1SDimitry Andric return new VPWidenStoreRecipe(cast<StoreInst>(Ingredient), getAddr(), 2605*0fca6ea1SDimitry Andric getStoredValue(), getMask(), Consecutive, 2606*0fca6ea1SDimitry Andric Reverse, getDebugLoc()); 2607*0fca6ea1SDimitry Andric } 2608*0fca6ea1SDimitry Andric 2609*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenStoreSC); 2610*0fca6ea1SDimitry Andric 2611*0fca6ea1SDimitry Andric /// Return the value stored by this recipe. 2612*0fca6ea1SDimitry Andric VPValue *getStoredValue() const { return getOperand(1); } 2613*0fca6ea1SDimitry Andric 2614*0fca6ea1SDimitry Andric /// Generate a wide store or scatter. 2615*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override; 2616*0fca6ea1SDimitry Andric 2617*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2618*0fca6ea1SDimitry Andric /// Print the recipe. 2619*0fca6ea1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2620*0fca6ea1SDimitry Andric VPSlotTracker &SlotTracker) const override; 2621*0fca6ea1SDimitry Andric #endif 2622*0fca6ea1SDimitry Andric 2623*0fca6ea1SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 2624*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 2625*0fca6ea1SDimitry Andric assert(is_contained(operands(), Op) && 2626*0fca6ea1SDimitry Andric "Op must be an operand of the recipe"); 2627*0fca6ea1SDimitry Andric // Widened, consecutive stores only demand the first lane of their address, 2628*0fca6ea1SDimitry Andric // unless the same operand is also stored. 2629*0fca6ea1SDimitry Andric return Op == getAddr() && isConsecutive() && Op != getStoredValue(); 2630*0fca6ea1SDimitry Andric } 2631*0fca6ea1SDimitry Andric }; 2632*0fca6ea1SDimitry Andric 2633*0fca6ea1SDimitry Andric /// A recipe for widening store operations with vector-predication intrinsics, 2634*0fca6ea1SDimitry Andric /// using the value to store, the address to store to, the explicit vector 2635*0fca6ea1SDimitry Andric /// length and an optional mask. 2636*0fca6ea1SDimitry Andric struct VPWidenStoreEVLRecipe final : public VPWidenMemoryRecipe { 2637*0fca6ea1SDimitry Andric VPWidenStoreEVLRecipe(VPWidenStoreRecipe *S, VPValue *EVL, VPValue *Mask) 2638*0fca6ea1SDimitry Andric : VPWidenMemoryRecipe(VPDef::VPWidenStoreEVLSC, S->getIngredient(), 2639*0fca6ea1SDimitry Andric {S->getAddr(), S->getStoredValue(), EVL}, 2640*0fca6ea1SDimitry Andric S->isConsecutive(), S->isReverse(), 2641*0fca6ea1SDimitry Andric S->getDebugLoc()) { 2642*0fca6ea1SDimitry Andric setMask(Mask); 2643*0fca6ea1SDimitry Andric } 2644*0fca6ea1SDimitry Andric 2645*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenStoreEVLSC) 2646*0fca6ea1SDimitry Andric 2647*0fca6ea1SDimitry Andric /// Return the address accessed by this recipe. 2648*0fca6ea1SDimitry Andric VPValue *getStoredValue() const { return getOperand(1); } 2649*0fca6ea1SDimitry Andric 2650*0fca6ea1SDimitry Andric /// Return the EVL operand. 2651*0fca6ea1SDimitry Andric VPValue *getEVL() const { return getOperand(2); } 2652*0fca6ea1SDimitry Andric 2653*0fca6ea1SDimitry Andric /// Generate the wide store or scatter. 2654*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override; 2655*0fca6ea1SDimitry Andric 2656*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2657*0fca6ea1SDimitry Andric /// Print the recipe. 2658*0fca6ea1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2659*0fca6ea1SDimitry Andric VPSlotTracker &SlotTracker) const override; 2660*0fca6ea1SDimitry Andric #endif 2661*0fca6ea1SDimitry Andric 2662*0fca6ea1SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 2663*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 2664*0fca6ea1SDimitry Andric assert(is_contained(operands(), Op) && 2665*0fca6ea1SDimitry Andric "Op must be an operand of the recipe"); 2666*0fca6ea1SDimitry Andric if (Op == getEVL()) { 2667*0fca6ea1SDimitry Andric assert(getStoredValue() != Op && "unexpected store of EVL"); 2668*0fca6ea1SDimitry Andric return true; 2669*0fca6ea1SDimitry Andric } 26701fd87a68SDimitry Andric // Widened, consecutive memory operations only demand the first lane of 267181ad6265SDimitry Andric // their address, unless the same operand is also stored. That latter can 267281ad6265SDimitry Andric // happen with opaque pointers. 2673*0fca6ea1SDimitry Andric return Op == getAddr() && isConsecutive() && Op != getStoredValue(); 26741fd87a68SDimitry Andric } 267581ad6265SDimitry Andric }; 267681ad6265SDimitry Andric 267781ad6265SDimitry Andric /// Recipe to expand a SCEV expression. 26787a6dacacSDimitry Andric class VPExpandSCEVRecipe : public VPSingleDefRecipe { 267981ad6265SDimitry Andric const SCEV *Expr; 268081ad6265SDimitry Andric ScalarEvolution &SE; 268181ad6265SDimitry Andric 268281ad6265SDimitry Andric public: 268381ad6265SDimitry Andric VPExpandSCEVRecipe(const SCEV *Expr, ScalarEvolution &SE) 26847a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPExpandSCEVSC, {}), Expr(Expr), SE(SE) {} 268581ad6265SDimitry Andric 268681ad6265SDimitry Andric ~VPExpandSCEVRecipe() override = default; 268781ad6265SDimitry Andric 2688*0fca6ea1SDimitry Andric VPExpandSCEVRecipe *clone() override { 2689*0fca6ea1SDimitry Andric return new VPExpandSCEVRecipe(Expr, SE); 2690*0fca6ea1SDimitry Andric } 2691*0fca6ea1SDimitry Andric 2692bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPExpandSCEVSC) 269381ad6265SDimitry Andric 269481ad6265SDimitry Andric /// Generate a canonical vector induction variable of the vector loop, with 269581ad6265SDimitry Andric void execute(VPTransformState &State) override; 269681ad6265SDimitry Andric 269781ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 269881ad6265SDimitry Andric /// Print the recipe. 269981ad6265SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 270081ad6265SDimitry Andric VPSlotTracker &SlotTracker) const override; 270181ad6265SDimitry Andric #endif 270281ad6265SDimitry Andric 270381ad6265SDimitry Andric const SCEV *getSCEV() const { return Expr; } 27045ffd83dbSDimitry Andric }; 27055ffd83dbSDimitry Andric 270604eeddc0SDimitry Andric /// Canonical scalar induction phi of the vector loop. Starting at the specified 270704eeddc0SDimitry Andric /// start value (either 0 or the resume value when vectorizing the epilogue 270804eeddc0SDimitry Andric /// loop). VPWidenCanonicalIVRecipe represents the vector version of the 270904eeddc0SDimitry Andric /// canonical induction variable. 271004eeddc0SDimitry Andric class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe { 271104eeddc0SDimitry Andric public: 271204eeddc0SDimitry Andric VPCanonicalIVPHIRecipe(VPValue *StartV, DebugLoc DL) 27135f757f3fSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPCanonicalIVPHISC, nullptr, StartV, DL) {} 271404eeddc0SDimitry Andric 271504eeddc0SDimitry Andric ~VPCanonicalIVPHIRecipe() override = default; 271604eeddc0SDimitry Andric 2717*0fca6ea1SDimitry Andric VPCanonicalIVPHIRecipe *clone() override { 2718*0fca6ea1SDimitry Andric auto *R = new VPCanonicalIVPHIRecipe(getOperand(0), getDebugLoc()); 2719*0fca6ea1SDimitry Andric R->addOperand(getBackedgeValue()); 2720*0fca6ea1SDimitry Andric return R; 2721*0fca6ea1SDimitry Andric } 2722*0fca6ea1SDimitry Andric 2723bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPCanonicalIVPHISC) 2724bdd1243dSDimitry Andric 272581ad6265SDimitry Andric static inline bool classof(const VPHeaderPHIRecipe *D) { 2726bdd1243dSDimitry Andric return D->getVPDefID() == VPDef::VPCanonicalIVPHISC; 272781ad6265SDimitry Andric } 272804eeddc0SDimitry Andric 272904eeddc0SDimitry Andric /// Generate the canonical scalar induction phi of the vector loop. 273004eeddc0SDimitry Andric void execute(VPTransformState &State) override; 273104eeddc0SDimitry Andric 273204eeddc0SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 273304eeddc0SDimitry Andric /// Print the recipe. 273404eeddc0SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 273504eeddc0SDimitry Andric VPSlotTracker &SlotTracker) const override; 273604eeddc0SDimitry Andric #endif 273704eeddc0SDimitry Andric 273804eeddc0SDimitry Andric /// Returns the scalar type of the induction. 27395f757f3fSDimitry Andric Type *getScalarType() const { 27405f757f3fSDimitry Andric return getStartValue()->getLiveInIRValue()->getType(); 274104eeddc0SDimitry Andric } 27421fd87a68SDimitry Andric 27431fd87a68SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 27441fd87a68SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 27451fd87a68SDimitry Andric assert(is_contained(operands(), Op) && 27461fd87a68SDimitry Andric "Op must be an operand of the recipe"); 27471fd87a68SDimitry Andric return true; 27481fd87a68SDimitry Andric } 2749bdd1243dSDimitry Andric 27505f757f3fSDimitry Andric /// Returns true if the recipe only uses the first part of operand \p Op. 27515f757f3fSDimitry Andric bool onlyFirstPartUsed(const VPValue *Op) const override { 27525f757f3fSDimitry Andric assert(is_contained(operands(), Op) && 27535f757f3fSDimitry Andric "Op must be an operand of the recipe"); 27545f757f3fSDimitry Andric return true; 27555f757f3fSDimitry Andric } 27565f757f3fSDimitry Andric 275706c3fb27SDimitry Andric /// Check if the induction described by \p Kind, /p Start and \p Step is 2758*0fca6ea1SDimitry Andric /// canonical, i.e. has the same start and step (of 1) as the canonical IV. 275906c3fb27SDimitry Andric bool isCanonical(InductionDescriptor::InductionKind Kind, VPValue *Start, 2760*0fca6ea1SDimitry Andric VPValue *Step) const; 276104eeddc0SDimitry Andric }; 276204eeddc0SDimitry Andric 2763753f127fSDimitry Andric /// A recipe for generating the active lane mask for the vector loop that is 2764753f127fSDimitry Andric /// used to predicate the vector operations. 2765753f127fSDimitry Andric /// TODO: It would be good to use the existing VPWidenPHIRecipe instead and 2766753f127fSDimitry Andric /// remove VPActiveLaneMaskPHIRecipe. 2767753f127fSDimitry Andric class VPActiveLaneMaskPHIRecipe : public VPHeaderPHIRecipe { 2768753f127fSDimitry Andric public: 2769753f127fSDimitry Andric VPActiveLaneMaskPHIRecipe(VPValue *StartMask, DebugLoc DL) 27705f757f3fSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPActiveLaneMaskPHISC, nullptr, StartMask, 27715f757f3fSDimitry Andric DL) {} 2772753f127fSDimitry Andric 2773753f127fSDimitry Andric ~VPActiveLaneMaskPHIRecipe() override = default; 2774753f127fSDimitry Andric 2775*0fca6ea1SDimitry Andric VPActiveLaneMaskPHIRecipe *clone() override { 2776*0fca6ea1SDimitry Andric return new VPActiveLaneMaskPHIRecipe(getOperand(0), getDebugLoc()); 2777*0fca6ea1SDimitry Andric } 2778*0fca6ea1SDimitry Andric 2779bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPActiveLaneMaskPHISC) 2780bdd1243dSDimitry Andric 2781753f127fSDimitry Andric static inline bool classof(const VPHeaderPHIRecipe *D) { 2782bdd1243dSDimitry Andric return D->getVPDefID() == VPDef::VPActiveLaneMaskPHISC; 2783753f127fSDimitry Andric } 2784753f127fSDimitry Andric 2785753f127fSDimitry Andric /// Generate the active lane mask phi of the vector loop. 2786753f127fSDimitry Andric void execute(VPTransformState &State) override; 2787753f127fSDimitry Andric 2788753f127fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2789753f127fSDimitry Andric /// Print the recipe. 2790753f127fSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2791753f127fSDimitry Andric VPSlotTracker &SlotTracker) const override; 2792753f127fSDimitry Andric #endif 2793753f127fSDimitry Andric }; 2794753f127fSDimitry Andric 2795*0fca6ea1SDimitry Andric /// A recipe for generating the phi node for the current index of elements, 2796*0fca6ea1SDimitry Andric /// adjusted in accordance with EVL value. It starts at the start value of the 2797*0fca6ea1SDimitry Andric /// canonical induction and gets incremented by EVL in each iteration of the 2798*0fca6ea1SDimitry Andric /// vector loop. 2799*0fca6ea1SDimitry Andric class VPEVLBasedIVPHIRecipe : public VPHeaderPHIRecipe { 2800*0fca6ea1SDimitry Andric public: 2801*0fca6ea1SDimitry Andric VPEVLBasedIVPHIRecipe(VPValue *StartIV, DebugLoc DL) 2802*0fca6ea1SDimitry Andric : VPHeaderPHIRecipe(VPDef::VPEVLBasedIVPHISC, nullptr, StartIV, DL) {} 2803*0fca6ea1SDimitry Andric 2804*0fca6ea1SDimitry Andric ~VPEVLBasedIVPHIRecipe() override = default; 2805*0fca6ea1SDimitry Andric 2806*0fca6ea1SDimitry Andric VPEVLBasedIVPHIRecipe *clone() override { 2807*0fca6ea1SDimitry Andric llvm_unreachable("cloning not implemented yet"); 2808*0fca6ea1SDimitry Andric } 2809*0fca6ea1SDimitry Andric 2810*0fca6ea1SDimitry Andric VP_CLASSOF_IMPL(VPDef::VPEVLBasedIVPHISC) 2811*0fca6ea1SDimitry Andric 2812*0fca6ea1SDimitry Andric static inline bool classof(const VPHeaderPHIRecipe *D) { 2813*0fca6ea1SDimitry Andric return D->getVPDefID() == VPDef::VPEVLBasedIVPHISC; 2814*0fca6ea1SDimitry Andric } 2815*0fca6ea1SDimitry Andric 2816*0fca6ea1SDimitry Andric /// Generate phi for handling IV based on EVL over iterations correctly. 2817*0fca6ea1SDimitry Andric /// TODO: investigate if it can share the code with VPCanonicalIVPHIRecipe. 2818*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override; 2819*0fca6ea1SDimitry Andric 2820*0fca6ea1SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 2821*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 2822*0fca6ea1SDimitry Andric assert(is_contained(operands(), Op) && 2823*0fca6ea1SDimitry Andric "Op must be an operand of the recipe"); 2824*0fca6ea1SDimitry Andric return true; 2825*0fca6ea1SDimitry Andric } 2826*0fca6ea1SDimitry Andric 2827*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2828*0fca6ea1SDimitry Andric /// Print the recipe. 2829*0fca6ea1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2830*0fca6ea1SDimitry Andric VPSlotTracker &SlotTracker) const override; 2831*0fca6ea1SDimitry Andric #endif 2832*0fca6ea1SDimitry Andric }; 2833*0fca6ea1SDimitry Andric 28345ffd83dbSDimitry Andric /// A Recipe for widening the canonical induction variable of the vector loop. 28357a6dacacSDimitry Andric class VPWidenCanonicalIVRecipe : public VPSingleDefRecipe { 28365ffd83dbSDimitry Andric public: 283704eeddc0SDimitry Andric VPWidenCanonicalIVRecipe(VPCanonicalIVPHIRecipe *CanonicalIV) 28387a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPWidenCanonicalIVSC, {CanonicalIV}) {} 2839e8d8bef9SDimitry Andric 28405ffd83dbSDimitry Andric ~VPWidenCanonicalIVRecipe() override = default; 28415ffd83dbSDimitry Andric 2842*0fca6ea1SDimitry Andric VPWidenCanonicalIVRecipe *clone() override { 2843*0fca6ea1SDimitry Andric return new VPWidenCanonicalIVRecipe( 2844*0fca6ea1SDimitry Andric cast<VPCanonicalIVPHIRecipe>(getOperand(0))); 2845*0fca6ea1SDimitry Andric } 2846*0fca6ea1SDimitry Andric 2847bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPWidenCanonicalIVSC) 284804eeddc0SDimitry Andric 28495ffd83dbSDimitry Andric /// Generate a canonical vector induction variable of the vector loop, with 28505ffd83dbSDimitry Andric /// start = {<Part*VF, Part*VF+1, ..., Part*VF+VF-1> for 0 <= Part < UF}, and 28515ffd83dbSDimitry Andric /// step = <VF*UF, VF*UF, ..., VF*UF>. 28525ffd83dbSDimitry Andric void execute(VPTransformState &State) override; 28535ffd83dbSDimitry Andric 2854fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 28555ffd83dbSDimitry Andric /// Print the recipe. 28565ffd83dbSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 28575ffd83dbSDimitry Andric VPSlotTracker &SlotTracker) const override; 2858fe6060f1SDimitry Andric #endif 28590b57cec5SDimitry Andric }; 28600b57cec5SDimitry Andric 2861*0fca6ea1SDimitry Andric /// A recipe for converting the input value \p IV value to the corresponding 2862*0fca6ea1SDimitry Andric /// value of an IV with different start and step values, using Start + IV * 2863bdd1243dSDimitry Andric /// Step. 28647a6dacacSDimitry Andric class VPDerivedIVRecipe : public VPSingleDefRecipe { 28655f757f3fSDimitry Andric /// Kind of the induction. 28665f757f3fSDimitry Andric const InductionDescriptor::InductionKind Kind; 28675f757f3fSDimitry Andric /// If not nullptr, the floating point induction binary operator. Must be set 28685f757f3fSDimitry Andric /// for floating point inductions. 28695f757f3fSDimitry Andric const FPMathOperator *FPBinOp; 2870bdd1243dSDimitry Andric 2871bdd1243dSDimitry Andric public: 2872bdd1243dSDimitry Andric VPDerivedIVRecipe(const InductionDescriptor &IndDesc, VPValue *Start, 2873*0fca6ea1SDimitry Andric VPCanonicalIVPHIRecipe *CanonicalIV, VPValue *Step) 2874*0fca6ea1SDimitry Andric : VPDerivedIVRecipe( 2875*0fca6ea1SDimitry Andric IndDesc.getKind(), 2876*0fca6ea1SDimitry Andric dyn_cast_or_null<FPMathOperator>(IndDesc.getInductionBinOp()), 2877*0fca6ea1SDimitry Andric Start, CanonicalIV, Step) {} 2878*0fca6ea1SDimitry Andric 2879*0fca6ea1SDimitry Andric VPDerivedIVRecipe(InductionDescriptor::InductionKind Kind, 2880*0fca6ea1SDimitry Andric const FPMathOperator *FPBinOp, VPValue *Start, VPValue *IV, 2881*0fca6ea1SDimitry Andric VPValue *Step) 2882*0fca6ea1SDimitry Andric : VPSingleDefRecipe(VPDef::VPDerivedIVSC, {Start, IV, Step}), Kind(Kind), 2883*0fca6ea1SDimitry Andric FPBinOp(FPBinOp) {} 2884bdd1243dSDimitry Andric 2885bdd1243dSDimitry Andric ~VPDerivedIVRecipe() override = default; 2886bdd1243dSDimitry Andric 2887*0fca6ea1SDimitry Andric VPDerivedIVRecipe *clone() override { 2888*0fca6ea1SDimitry Andric return new VPDerivedIVRecipe(Kind, FPBinOp, getStartValue(), getOperand(1), 2889*0fca6ea1SDimitry Andric getStepValue()); 2890*0fca6ea1SDimitry Andric } 2891*0fca6ea1SDimitry Andric 2892bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPDerivedIVSC) 2893bdd1243dSDimitry Andric 2894bdd1243dSDimitry Andric /// Generate the transformed value of the induction at offset StartValue (1. 2895bdd1243dSDimitry Andric /// operand) + IV (2. operand) * StepValue (3, operand). 2896bdd1243dSDimitry Andric void execute(VPTransformState &State) override; 2897bdd1243dSDimitry Andric 2898bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2899bdd1243dSDimitry Andric /// Print the recipe. 2900bdd1243dSDimitry Andric void print(raw_ostream &O, const Twine &Indent, 2901bdd1243dSDimitry Andric VPSlotTracker &SlotTracker) const override; 2902bdd1243dSDimitry Andric #endif 2903bdd1243dSDimitry Andric 29045f757f3fSDimitry Andric Type *getScalarType() const { 2905*0fca6ea1SDimitry Andric return getStartValue()->getLiveInIRValue()->getType(); 29065f757f3fSDimitry Andric } 29075f757f3fSDimitry Andric 2908bdd1243dSDimitry Andric VPValue *getStartValue() const { return getOperand(0); } 2909bdd1243dSDimitry Andric VPValue *getStepValue() const { return getOperand(2); } 2910bdd1243dSDimitry Andric 2911bdd1243dSDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 2912bdd1243dSDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 2913bdd1243dSDimitry Andric assert(is_contained(operands(), Op) && 2914bdd1243dSDimitry Andric "Op must be an operand of the recipe"); 2915bdd1243dSDimitry Andric return true; 2916bdd1243dSDimitry Andric } 2917bdd1243dSDimitry Andric }; 2918bdd1243dSDimitry Andric 291981ad6265SDimitry Andric /// A recipe for handling phi nodes of integer and floating-point inductions, 292081ad6265SDimitry Andric /// producing their scalar values. 29217a6dacacSDimitry Andric class VPScalarIVStepsRecipe : public VPRecipeWithIRFlags { 29225f757f3fSDimitry Andric Instruction::BinaryOps InductionOpcode; 292381ad6265SDimitry Andric 292481ad6265SDimitry Andric public: 29255f757f3fSDimitry Andric VPScalarIVStepsRecipe(VPValue *IV, VPValue *Step, 29265f757f3fSDimitry Andric Instruction::BinaryOps Opcode, FastMathFlags FMFs) 29275f757f3fSDimitry Andric : VPRecipeWithIRFlags(VPDef::VPScalarIVStepsSC, 29285f757f3fSDimitry Andric ArrayRef<VPValue *>({IV, Step}), FMFs), 29297a6dacacSDimitry Andric InductionOpcode(Opcode) {} 29305f757f3fSDimitry Andric 2931bdd1243dSDimitry Andric VPScalarIVStepsRecipe(const InductionDescriptor &IndDesc, VPValue *IV, 2932bdd1243dSDimitry Andric VPValue *Step) 29335f757f3fSDimitry Andric : VPScalarIVStepsRecipe( 29345f757f3fSDimitry Andric IV, Step, IndDesc.getInductionOpcode(), 29355f757f3fSDimitry Andric dyn_cast_or_null<FPMathOperator>(IndDesc.getInductionBinOp()) 29365f757f3fSDimitry Andric ? IndDesc.getInductionBinOp()->getFastMathFlags() 29375f757f3fSDimitry Andric : FastMathFlags()) {} 293881ad6265SDimitry Andric 293981ad6265SDimitry Andric ~VPScalarIVStepsRecipe() override = default; 294081ad6265SDimitry Andric 2941*0fca6ea1SDimitry Andric VPScalarIVStepsRecipe *clone() override { 2942*0fca6ea1SDimitry Andric return new VPScalarIVStepsRecipe( 2943*0fca6ea1SDimitry Andric getOperand(0), getOperand(1), InductionOpcode, 2944*0fca6ea1SDimitry Andric hasFastMathFlags() ? getFastMathFlags() : FastMathFlags()); 2945*0fca6ea1SDimitry Andric } 2946*0fca6ea1SDimitry Andric 2947bdd1243dSDimitry Andric VP_CLASSOF_IMPL(VPDef::VPScalarIVStepsSC) 294881ad6265SDimitry Andric 294981ad6265SDimitry Andric /// Generate the scalarized versions of the phi node as needed by their users. 295081ad6265SDimitry Andric void execute(VPTransformState &State) override; 295181ad6265SDimitry Andric 295281ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 295381ad6265SDimitry Andric /// Print the recipe. 295481ad6265SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 295581ad6265SDimitry Andric VPSlotTracker &SlotTracker) const override; 295681ad6265SDimitry Andric #endif 295781ad6265SDimitry Andric 2958bdd1243dSDimitry Andric VPValue *getStepValue() const { return getOperand(1); } 295981ad6265SDimitry Andric 296081ad6265SDimitry Andric /// Returns true if the recipe only uses the first lane of operand \p Op. 296181ad6265SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Op) const override { 296281ad6265SDimitry Andric assert(is_contained(operands(), Op) && 296381ad6265SDimitry Andric "Op must be an operand of the recipe"); 296481ad6265SDimitry Andric return true; 296581ad6265SDimitry Andric } 296681ad6265SDimitry Andric }; 296781ad6265SDimitry Andric 29680b57cec5SDimitry Andric /// VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph. It 29690b57cec5SDimitry Andric /// holds a sequence of zero or more VPRecipe's each representing a sequence of 2970fe6060f1SDimitry Andric /// output IR instructions. All PHI-like recipes must come before any non-PHI recipes. 29710b57cec5SDimitry Andric class VPBasicBlock : public VPBlockBase { 29720b57cec5SDimitry Andric public: 29730b57cec5SDimitry Andric using RecipeListTy = iplist<VPRecipeBase>; 29740b57cec5SDimitry Andric 2975*0fca6ea1SDimitry Andric protected: 29760b57cec5SDimitry Andric /// The VPRecipes held in the order of output instructions to generate. 29770b57cec5SDimitry Andric RecipeListTy Recipes; 29780b57cec5SDimitry Andric 2979*0fca6ea1SDimitry Andric VPBasicBlock(const unsigned char BlockSC, const Twine &Name = "") 2980*0fca6ea1SDimitry Andric : VPBlockBase(BlockSC, Name.str()) {} 2981*0fca6ea1SDimitry Andric 29820b57cec5SDimitry Andric public: 29830b57cec5SDimitry Andric VPBasicBlock(const Twine &Name = "", VPRecipeBase *Recipe = nullptr) 29840b57cec5SDimitry Andric : VPBlockBase(VPBasicBlockSC, Name.str()) { 29850b57cec5SDimitry Andric if (Recipe) 29860b57cec5SDimitry Andric appendRecipe(Recipe); 29870b57cec5SDimitry Andric } 29880b57cec5SDimitry Andric 2989fe6060f1SDimitry Andric ~VPBasicBlock() override { 2990fe6060f1SDimitry Andric while (!Recipes.empty()) 2991fe6060f1SDimitry Andric Recipes.pop_back(); 2992fe6060f1SDimitry Andric } 29930b57cec5SDimitry Andric 29940b57cec5SDimitry Andric /// Instruction iterators... 29950b57cec5SDimitry Andric using iterator = RecipeListTy::iterator; 29960b57cec5SDimitry Andric using const_iterator = RecipeListTy::const_iterator; 29970b57cec5SDimitry Andric using reverse_iterator = RecipeListTy::reverse_iterator; 29980b57cec5SDimitry Andric using const_reverse_iterator = RecipeListTy::const_reverse_iterator; 29990b57cec5SDimitry Andric 30000b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 30010b57cec5SDimitry Andric /// Recipe iterator methods 30020b57cec5SDimitry Andric /// 30030b57cec5SDimitry Andric inline iterator begin() { return Recipes.begin(); } 30040b57cec5SDimitry Andric inline const_iterator begin() const { return Recipes.begin(); } 30050b57cec5SDimitry Andric inline iterator end() { return Recipes.end(); } 30060b57cec5SDimitry Andric inline const_iterator end() const { return Recipes.end(); } 30070b57cec5SDimitry Andric 30080b57cec5SDimitry Andric inline reverse_iterator rbegin() { return Recipes.rbegin(); } 30090b57cec5SDimitry Andric inline const_reverse_iterator rbegin() const { return Recipes.rbegin(); } 30100b57cec5SDimitry Andric inline reverse_iterator rend() { return Recipes.rend(); } 30110b57cec5SDimitry Andric inline const_reverse_iterator rend() const { return Recipes.rend(); } 30120b57cec5SDimitry Andric 30130b57cec5SDimitry Andric inline size_t size() const { return Recipes.size(); } 30140b57cec5SDimitry Andric inline bool empty() const { return Recipes.empty(); } 30150b57cec5SDimitry Andric inline const VPRecipeBase &front() const { return Recipes.front(); } 30160b57cec5SDimitry Andric inline VPRecipeBase &front() { return Recipes.front(); } 30170b57cec5SDimitry Andric inline const VPRecipeBase &back() const { return Recipes.back(); } 30180b57cec5SDimitry Andric inline VPRecipeBase &back() { return Recipes.back(); } 30190b57cec5SDimitry Andric 30200b57cec5SDimitry Andric /// Returns a reference to the list of recipes. 30210b57cec5SDimitry Andric RecipeListTy &getRecipeList() { return Recipes; } 30220b57cec5SDimitry Andric 30230b57cec5SDimitry Andric /// Returns a pointer to a member of the recipe list. 30240b57cec5SDimitry Andric static RecipeListTy VPBasicBlock::*getSublistAccess(VPRecipeBase *) { 30250b57cec5SDimitry Andric return &VPBasicBlock::Recipes; 30260b57cec5SDimitry Andric } 30270b57cec5SDimitry Andric 30280b57cec5SDimitry Andric /// Method to support type inquiry through isa, cast, and dyn_cast. 30290b57cec5SDimitry Andric static inline bool classof(const VPBlockBase *V) { 3030*0fca6ea1SDimitry Andric return V->getVPBlockID() == VPBlockBase::VPBasicBlockSC || 3031*0fca6ea1SDimitry Andric V->getVPBlockID() == VPBlockBase::VPIRBasicBlockSC; 30320b57cec5SDimitry Andric } 30330b57cec5SDimitry Andric 30340b57cec5SDimitry Andric void insert(VPRecipeBase *Recipe, iterator InsertPt) { 30350b57cec5SDimitry Andric assert(Recipe && "No recipe to append."); 30360b57cec5SDimitry Andric assert(!Recipe->Parent && "Recipe already in VPlan"); 30370b57cec5SDimitry Andric Recipe->Parent = this; 30380b57cec5SDimitry Andric Recipes.insert(InsertPt, Recipe); 30390b57cec5SDimitry Andric } 30400b57cec5SDimitry Andric 30410b57cec5SDimitry Andric /// Augment the existing recipes of a VPBasicBlock with an additional 30420b57cec5SDimitry Andric /// \p Recipe as the last recipe. 30430b57cec5SDimitry Andric void appendRecipe(VPRecipeBase *Recipe) { insert(Recipe, end()); } 30440b57cec5SDimitry Andric 30450b57cec5SDimitry Andric /// The method which generates the output IR instructions that correspond to 30460b57cec5SDimitry Andric /// this VPBasicBlock, thereby "executing" the VPlan. 3047bdd1243dSDimitry Andric void execute(VPTransformState *State) override; 30480b57cec5SDimitry Andric 3049*0fca6ea1SDimitry Andric /// Return the cost of this VPBasicBlock. 3050*0fca6ea1SDimitry Andric InstructionCost cost(ElementCount VF, VPCostContext &Ctx) override; 3051*0fca6ea1SDimitry Andric 3052e8d8bef9SDimitry Andric /// Return the position of the first non-phi node recipe in the block. 3053e8d8bef9SDimitry Andric iterator getFirstNonPhi(); 3054e8d8bef9SDimitry Andric 3055fe6060f1SDimitry Andric /// Returns an iterator range over the PHI-like recipes in the block. 3056fe6060f1SDimitry Andric iterator_range<iterator> phis() { 3057fe6060f1SDimitry Andric return make_range(begin(), getFirstNonPhi()); 3058fe6060f1SDimitry Andric } 3059fe6060f1SDimitry Andric 3060e8d8bef9SDimitry Andric void dropAllReferences(VPValue *NewValue) override; 3061e8d8bef9SDimitry Andric 3062fe6060f1SDimitry Andric /// Split current block at \p SplitAt by inserting a new block between the 3063fe6060f1SDimitry Andric /// current block and its successors and moving all recipes starting at 3064fe6060f1SDimitry Andric /// SplitAt to the new block. Returns the new block. 3065fe6060f1SDimitry Andric VPBasicBlock *splitAt(iterator SplitAt); 3066fe6060f1SDimitry Andric 306781ad6265SDimitry Andric VPRegionBlock *getEnclosingLoopRegion(); 306881ad6265SDimitry Andric 3069fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 3070fe6060f1SDimitry Andric /// Print this VPBsicBlock to \p O, prefixing all lines with \p Indent. \p 3071fe6060f1SDimitry Andric /// SlotTracker is used to print unnamed VPValue's using consequtive numbers. 3072fe6060f1SDimitry Andric /// 3073fe6060f1SDimitry Andric /// Note that the numbering is applied to the whole VPlan, so printing 3074fe6060f1SDimitry Andric /// individual blocks is consistent with the whole VPlan printing. 3075fe6060f1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 3076fe6060f1SDimitry Andric VPSlotTracker &SlotTracker) const override; 3077fe6060f1SDimitry Andric using VPBlockBase::print; // Get the print(raw_stream &O) version. 3078fe6060f1SDimitry Andric #endif 3079fe6060f1SDimitry Andric 308081ad6265SDimitry Andric /// If the block has multiple successors, return the branch recipe terminating 308181ad6265SDimitry Andric /// the block. If there are no or only a single successor, return nullptr; 308281ad6265SDimitry Andric VPRecipeBase *getTerminator(); 308381ad6265SDimitry Andric const VPRecipeBase *getTerminator() const; 308481ad6265SDimitry Andric 308581ad6265SDimitry Andric /// Returns true if the block is exiting it's parent region. 308681ad6265SDimitry Andric bool isExiting() const; 308781ad6265SDimitry Andric 3088*0fca6ea1SDimitry Andric /// Clone the current block and it's recipes, without updating the operands of 3089*0fca6ea1SDimitry Andric /// the cloned recipes. 3090*0fca6ea1SDimitry Andric VPBasicBlock *clone() override { 3091*0fca6ea1SDimitry Andric auto *NewBlock = new VPBasicBlock(getName()); 3092*0fca6ea1SDimitry Andric for (VPRecipeBase &R : *this) 3093*0fca6ea1SDimitry Andric NewBlock->appendRecipe(R.clone()); 3094*0fca6ea1SDimitry Andric return NewBlock; 3095*0fca6ea1SDimitry Andric } 3096*0fca6ea1SDimitry Andric 3097*0fca6ea1SDimitry Andric protected: 3098*0fca6ea1SDimitry Andric /// Execute the recipes in the IR basic block \p BB. 3099*0fca6ea1SDimitry Andric void executeRecipes(VPTransformState *State, BasicBlock *BB); 3100*0fca6ea1SDimitry Andric 31010b57cec5SDimitry Andric private: 31020b57cec5SDimitry Andric /// Create an IR BasicBlock to hold the output instructions generated by this 31030b57cec5SDimitry Andric /// VPBasicBlock, and return it. Update the CFGState accordingly. 31040b57cec5SDimitry Andric BasicBlock *createEmptyBasicBlock(VPTransformState::CFGState &CFG); 31050b57cec5SDimitry Andric }; 31060b57cec5SDimitry Andric 3107*0fca6ea1SDimitry Andric /// A special type of VPBasicBlock that wraps an existing IR basic block. 3108*0fca6ea1SDimitry Andric /// Recipes of the block get added before the first non-phi instruction in the 3109*0fca6ea1SDimitry Andric /// wrapped block. 3110*0fca6ea1SDimitry Andric /// Note: At the moment, VPIRBasicBlock can only be used to wrap VPlan's 3111*0fca6ea1SDimitry Andric /// preheader block. 3112*0fca6ea1SDimitry Andric class VPIRBasicBlock : public VPBasicBlock { 3113*0fca6ea1SDimitry Andric BasicBlock *IRBB; 3114*0fca6ea1SDimitry Andric 3115*0fca6ea1SDimitry Andric public: 3116*0fca6ea1SDimitry Andric VPIRBasicBlock(BasicBlock *IRBB) 3117*0fca6ea1SDimitry Andric : VPBasicBlock(VPIRBasicBlockSC, 3118*0fca6ea1SDimitry Andric (Twine("ir-bb<") + IRBB->getName() + Twine(">")).str()), 3119*0fca6ea1SDimitry Andric IRBB(IRBB) {} 3120*0fca6ea1SDimitry Andric 3121*0fca6ea1SDimitry Andric ~VPIRBasicBlock() override {} 3122*0fca6ea1SDimitry Andric 3123*0fca6ea1SDimitry Andric static inline bool classof(const VPBlockBase *V) { 3124*0fca6ea1SDimitry Andric return V->getVPBlockID() == VPBlockBase::VPIRBasicBlockSC; 3125*0fca6ea1SDimitry Andric } 3126*0fca6ea1SDimitry Andric 3127*0fca6ea1SDimitry Andric /// The method which generates the output IR instructions that correspond to 3128*0fca6ea1SDimitry Andric /// this VPBasicBlock, thereby "executing" the VPlan. 3129*0fca6ea1SDimitry Andric void execute(VPTransformState *State) override; 3130*0fca6ea1SDimitry Andric 3131*0fca6ea1SDimitry Andric VPIRBasicBlock *clone() override { 3132*0fca6ea1SDimitry Andric auto *NewBlock = new VPIRBasicBlock(IRBB); 3133*0fca6ea1SDimitry Andric for (VPRecipeBase &R : Recipes) 3134*0fca6ea1SDimitry Andric NewBlock->appendRecipe(R.clone()); 3135*0fca6ea1SDimitry Andric return NewBlock; 3136*0fca6ea1SDimitry Andric } 3137*0fca6ea1SDimitry Andric 3138*0fca6ea1SDimitry Andric BasicBlock *getIRBasicBlock() const { return IRBB; } 3139*0fca6ea1SDimitry Andric }; 3140*0fca6ea1SDimitry Andric 31410b57cec5SDimitry Andric /// VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks 314281ad6265SDimitry Andric /// which form a Single-Entry-Single-Exiting subgraph of the output IR CFG. 31430b57cec5SDimitry Andric /// A VPRegionBlock may indicate that its contents are to be replicated several 31440b57cec5SDimitry Andric /// times. This is designed to support predicated scalarization, in which a 31450b57cec5SDimitry Andric /// scalar if-then code structure needs to be generated VF * UF times. Having 31460b57cec5SDimitry Andric /// this replication indicator helps to keep a single model for multiple 31470b57cec5SDimitry Andric /// candidate VF's. The actual replication takes place only once the desired VF 31480b57cec5SDimitry Andric /// and UF have been determined. 31490b57cec5SDimitry Andric class VPRegionBlock : public VPBlockBase { 31500b57cec5SDimitry Andric /// Hold the Single Entry of the SESE region modelled by the VPRegionBlock. 31510b57cec5SDimitry Andric VPBlockBase *Entry; 31520b57cec5SDimitry Andric 315381ad6265SDimitry Andric /// Hold the Single Exiting block of the SESE region modelled by the 315481ad6265SDimitry Andric /// VPRegionBlock. 315581ad6265SDimitry Andric VPBlockBase *Exiting; 31560b57cec5SDimitry Andric 31570b57cec5SDimitry Andric /// An indicator whether this region is to generate multiple replicated 31580b57cec5SDimitry Andric /// instances of output IR corresponding to its VPBlockBases. 31590b57cec5SDimitry Andric bool IsReplicator; 31600b57cec5SDimitry Andric 31610b57cec5SDimitry Andric public: 316281ad6265SDimitry Andric VPRegionBlock(VPBlockBase *Entry, VPBlockBase *Exiting, 31630b57cec5SDimitry Andric const std::string &Name = "", bool IsReplicator = false) 316481ad6265SDimitry Andric : VPBlockBase(VPRegionBlockSC, Name), Entry(Entry), Exiting(Exiting), 31650b57cec5SDimitry Andric IsReplicator(IsReplicator) { 31660b57cec5SDimitry Andric assert(Entry->getPredecessors().empty() && "Entry block has predecessors."); 316781ad6265SDimitry Andric assert(Exiting->getSuccessors().empty() && "Exit block has successors."); 31680b57cec5SDimitry Andric Entry->setParent(this); 316981ad6265SDimitry Andric Exiting->setParent(this); 31700b57cec5SDimitry Andric } 31710b57cec5SDimitry Andric VPRegionBlock(const std::string &Name = "", bool IsReplicator = false) 317281ad6265SDimitry Andric : VPBlockBase(VPRegionBlockSC, Name), Entry(nullptr), Exiting(nullptr), 31730b57cec5SDimitry Andric IsReplicator(IsReplicator) {} 31740b57cec5SDimitry Andric 31750b57cec5SDimitry Andric ~VPRegionBlock() override { 3176e8d8bef9SDimitry Andric if (Entry) { 3177e8d8bef9SDimitry Andric VPValue DummyValue; 3178e8d8bef9SDimitry Andric Entry->dropAllReferences(&DummyValue); 31790b57cec5SDimitry Andric deleteCFG(Entry); 31800b57cec5SDimitry Andric } 3181e8d8bef9SDimitry Andric } 31820b57cec5SDimitry Andric 31830b57cec5SDimitry Andric /// Method to support type inquiry through isa, cast, and dyn_cast. 31840b57cec5SDimitry Andric static inline bool classof(const VPBlockBase *V) { 31850b57cec5SDimitry Andric return V->getVPBlockID() == VPBlockBase::VPRegionBlockSC; 31860b57cec5SDimitry Andric } 31870b57cec5SDimitry Andric 31880b57cec5SDimitry Andric const VPBlockBase *getEntry() const { return Entry; } 31890b57cec5SDimitry Andric VPBlockBase *getEntry() { return Entry; } 31900b57cec5SDimitry Andric 31910b57cec5SDimitry Andric /// Set \p EntryBlock as the entry VPBlockBase of this VPRegionBlock. \p 31920b57cec5SDimitry Andric /// EntryBlock must have no predecessors. 31930b57cec5SDimitry Andric void setEntry(VPBlockBase *EntryBlock) { 31940b57cec5SDimitry Andric assert(EntryBlock->getPredecessors().empty() && 31950b57cec5SDimitry Andric "Entry block cannot have predecessors."); 31960b57cec5SDimitry Andric Entry = EntryBlock; 31970b57cec5SDimitry Andric EntryBlock->setParent(this); 31980b57cec5SDimitry Andric } 31990b57cec5SDimitry Andric 320081ad6265SDimitry Andric const VPBlockBase *getExiting() const { return Exiting; } 320181ad6265SDimitry Andric VPBlockBase *getExiting() { return Exiting; } 32020b57cec5SDimitry Andric 320381ad6265SDimitry Andric /// Set \p ExitingBlock as the exiting VPBlockBase of this VPRegionBlock. \p 320481ad6265SDimitry Andric /// ExitingBlock must have no successors. 320581ad6265SDimitry Andric void setExiting(VPBlockBase *ExitingBlock) { 320681ad6265SDimitry Andric assert(ExitingBlock->getSuccessors().empty() && 32070b57cec5SDimitry Andric "Exit block cannot have successors."); 320881ad6265SDimitry Andric Exiting = ExitingBlock; 320981ad6265SDimitry Andric ExitingBlock->setParent(this); 321081ad6265SDimitry Andric } 321181ad6265SDimitry Andric 321281ad6265SDimitry Andric /// Returns the pre-header VPBasicBlock of the loop region. 321381ad6265SDimitry Andric VPBasicBlock *getPreheaderVPBB() { 321481ad6265SDimitry Andric assert(!isReplicator() && "should only get pre-header of loop regions"); 321581ad6265SDimitry Andric return getSinglePredecessor()->getExitingBasicBlock(); 32160b57cec5SDimitry Andric } 32170b57cec5SDimitry Andric 32180b57cec5SDimitry Andric /// An indicator whether this region is to generate multiple replicated 32190b57cec5SDimitry Andric /// instances of output IR corresponding to its VPBlockBases. 32200b57cec5SDimitry Andric bool isReplicator() const { return IsReplicator; } 32210b57cec5SDimitry Andric 32220b57cec5SDimitry Andric /// The method which generates the output IR instructions that correspond to 32230b57cec5SDimitry Andric /// this VPRegionBlock, thereby "executing" the VPlan. 3224bdd1243dSDimitry Andric void execute(VPTransformState *State) override; 3225e8d8bef9SDimitry Andric 3226*0fca6ea1SDimitry Andric // Return the cost of this region. 3227*0fca6ea1SDimitry Andric InstructionCost cost(ElementCount VF, VPCostContext &Ctx) override; 3228*0fca6ea1SDimitry Andric 3229e8d8bef9SDimitry Andric void dropAllReferences(VPValue *NewValue) override; 3230fe6060f1SDimitry Andric 3231fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 3232fe6060f1SDimitry Andric /// Print this VPRegionBlock to \p O (recursively), prefixing all lines with 3233fe6060f1SDimitry Andric /// \p Indent. \p SlotTracker is used to print unnamed VPValue's using 3234fe6060f1SDimitry Andric /// consequtive numbers. 3235fe6060f1SDimitry Andric /// 3236fe6060f1SDimitry Andric /// Note that the numbering is applied to the whole VPlan, so printing 3237fe6060f1SDimitry Andric /// individual regions is consistent with the whole VPlan printing. 3238fe6060f1SDimitry Andric void print(raw_ostream &O, const Twine &Indent, 3239fe6060f1SDimitry Andric VPSlotTracker &SlotTracker) const override; 3240fe6060f1SDimitry Andric using VPBlockBase::print; // Get the print(raw_stream &O) version. 3241fe6060f1SDimitry Andric #endif 3242*0fca6ea1SDimitry Andric 3243*0fca6ea1SDimitry Andric /// Clone all blocks in the single-entry single-exit region of the block and 3244*0fca6ea1SDimitry Andric /// their recipes without updating the operands of the cloned recipes. 3245*0fca6ea1SDimitry Andric VPRegionBlock *clone() override; 32460b57cec5SDimitry Andric }; 32470b57cec5SDimitry Andric 3248480093f4SDimitry Andric /// VPlan models a candidate for vectorization, encoding various decisions take 3249480093f4SDimitry Andric /// to produce efficient output IR, including which branches, basic-blocks and 3250480093f4SDimitry Andric /// output IR instructions to generate, and their cost. VPlan holds a 3251480093f4SDimitry Andric /// Hierarchical-CFG of VPBasicBlocks and VPRegionBlocks rooted at an Entry 325206c3fb27SDimitry Andric /// VPBasicBlock. 3253480093f4SDimitry Andric class VPlan { 3254480093f4SDimitry Andric friend class VPlanPrinter; 32555ffd83dbSDimitry Andric friend class VPSlotTracker; 3256480093f4SDimitry Andric 325706c3fb27SDimitry Andric /// Hold the single entry to the Hierarchical CFG of the VPlan, i.e. the 325806c3fb27SDimitry Andric /// preheader of the vector loop. 325906c3fb27SDimitry Andric VPBasicBlock *Entry; 326006c3fb27SDimitry Andric 326106c3fb27SDimitry Andric /// VPBasicBlock corresponding to the original preheader. Used to place 326206c3fb27SDimitry Andric /// VPExpandSCEV recipes for expressions used during skeleton creation and the 326306c3fb27SDimitry Andric /// rest of VPlan execution. 326406c3fb27SDimitry Andric VPBasicBlock *Preheader; 3265480093f4SDimitry Andric 3266480093f4SDimitry Andric /// Holds the VFs applicable to this VPlan. 3267e8d8bef9SDimitry Andric SmallSetVector<ElementCount, 2> VFs; 3268480093f4SDimitry Andric 3269bdd1243dSDimitry Andric /// Holds the UFs applicable to this VPlan. If empty, the VPlan is valid for 3270bdd1243dSDimitry Andric /// any UF. 3271bdd1243dSDimitry Andric SmallSetVector<unsigned, 2> UFs; 3272bdd1243dSDimitry Andric 3273480093f4SDimitry Andric /// Holds the name of the VPlan, for printing. 3274480093f4SDimitry Andric std::string Name; 3275480093f4SDimitry Andric 327604eeddc0SDimitry Andric /// Represents the trip count of the original loop, for folding 3277480093f4SDimitry Andric /// the tail. 327804eeddc0SDimitry Andric VPValue *TripCount = nullptr; 327904eeddc0SDimitry Andric 328004eeddc0SDimitry Andric /// Represents the backedge taken count of the original loop, for folding 328104eeddc0SDimitry Andric /// the tail. It equals TripCount - 1. 3282480093f4SDimitry Andric VPValue *BackedgeTakenCount = nullptr; 3283480093f4SDimitry Andric 328404eeddc0SDimitry Andric /// Represents the vector trip count. 328504eeddc0SDimitry Andric VPValue VectorTripCount; 328604eeddc0SDimitry Andric 32875f757f3fSDimitry Andric /// Represents the loop-invariant VF * UF of the vector loop region. 32885f757f3fSDimitry Andric VPValue VFxUF; 32895f757f3fSDimitry Andric 3290480093f4SDimitry Andric /// Holds a mapping between Values and their corresponding VPValue inside 3291480093f4SDimitry Andric /// VPlan. 3292480093f4SDimitry Andric Value2VPValueTy Value2VPValue; 3293480093f4SDimitry Andric 329406c3fb27SDimitry Andric /// Contains all the external definitions created for this VPlan. External 329506c3fb27SDimitry Andric /// definitions are VPValues that hold a pointer to their underlying IR. 329606c3fb27SDimitry Andric SmallVector<VPValue *, 16> VPLiveInsToFree; 3297e8d8bef9SDimitry Andric 3298*0fca6ea1SDimitry Andric /// Values used outside the plan. It contains live-outs that need fixing. Any 3299*0fca6ea1SDimitry Andric /// live-out that is fixed outside VPlan needs to be removed. The remaining 3300*0fca6ea1SDimitry Andric /// live-outs are fixed via VPLiveOut::fixPhi. 330181ad6265SDimitry Andric MapVector<PHINode *, VPLiveOut *> LiveOuts; 330281ad6265SDimitry Andric 330306c3fb27SDimitry Andric /// Mapping from SCEVs to the VPValues representing their expansions. 330406c3fb27SDimitry Andric /// NOTE: This mapping is temporary and will be removed once all users have 330506c3fb27SDimitry Andric /// been modeled in VPlan directly. 330606c3fb27SDimitry Andric DenseMap<const SCEV *, VPValue *> SCEVToExpansion; 330706c3fb27SDimitry Andric 3308480093f4SDimitry Andric public: 330906c3fb27SDimitry Andric /// Construct a VPlan with original preheader \p Preheader, trip count \p TC 331006c3fb27SDimitry Andric /// and \p Entry to the plan. At the moment, \p Preheader and \p Entry need to 331106c3fb27SDimitry Andric /// be disconnected, as the bypass blocks between them are not yet modeled in 331206c3fb27SDimitry Andric /// VPlan. 331306c3fb27SDimitry Andric VPlan(VPBasicBlock *Preheader, VPValue *TC, VPBasicBlock *Entry) 331406c3fb27SDimitry Andric : VPlan(Preheader, Entry) { 331506c3fb27SDimitry Andric TripCount = TC; 331606c3fb27SDimitry Andric } 331706c3fb27SDimitry Andric 331806c3fb27SDimitry Andric /// Construct a VPlan with original preheader \p Preheader and \p Entry to 331906c3fb27SDimitry Andric /// the plan. At the moment, \p Preheader and \p Entry need to be 332006c3fb27SDimitry Andric /// disconnected, as the bypass blocks between them are not yet modeled in 332106c3fb27SDimitry Andric /// VPlan. 332206c3fb27SDimitry Andric VPlan(VPBasicBlock *Preheader, VPBasicBlock *Entry) 332306c3fb27SDimitry Andric : Entry(Entry), Preheader(Preheader) { 33245ffd83dbSDimitry Andric Entry->setPlan(this); 332506c3fb27SDimitry Andric Preheader->setPlan(this); 332606c3fb27SDimitry Andric assert(Preheader->getNumSuccessors() == 0 && 332706c3fb27SDimitry Andric Preheader->getNumPredecessors() == 0 && 332806c3fb27SDimitry Andric "preheader must be disconnected"); 33295ffd83dbSDimitry Andric } 3330480093f4SDimitry Andric 3331bdd1243dSDimitry Andric ~VPlan(); 3332480093f4SDimitry Andric 3333*0fca6ea1SDimitry Andric /// Create initial VPlan, having an "entry" VPBasicBlock (wrapping 3334*0fca6ea1SDimitry Andric /// original scalar pre-header ) which contains SCEV expansions that need 3335*0fca6ea1SDimitry Andric /// to happen before the CFG is modified; a VPBasicBlock for the vector 33365f757f3fSDimitry Andric /// pre-header, followed by a region for the vector loop, followed by the 3337*0fca6ea1SDimitry Andric /// middle VPBasicBlock. If a check is needed to guard executing the scalar 3338*0fca6ea1SDimitry Andric /// epilogue loop, it will be added to the middle block, together with 3339*0fca6ea1SDimitry Andric /// VPBasicBlocks for the scalar preheader and exit blocks. 334006c3fb27SDimitry Andric static VPlanPtr createInitialVPlan(const SCEV *TripCount, 3341*0fca6ea1SDimitry Andric ScalarEvolution &PSE, 3342*0fca6ea1SDimitry Andric bool RequiresScalarEpilogueCheck, 3343*0fca6ea1SDimitry Andric bool TailFolded, Loop *TheLoop); 334406c3fb27SDimitry Andric 334504eeddc0SDimitry Andric /// Prepare the plan for execution, setting up the required live-in values. 334604eeddc0SDimitry Andric void prepareToExecute(Value *TripCount, Value *VectorTripCount, 33475f757f3fSDimitry Andric Value *CanonicalIVStartValue, VPTransformState &State); 334804eeddc0SDimitry Andric 3349480093f4SDimitry Andric /// Generate the IR code for this VPlan. 3350bdd1243dSDimitry Andric void execute(VPTransformState *State); 3351480093f4SDimitry Andric 3352*0fca6ea1SDimitry Andric /// Return the cost of this plan. 3353*0fca6ea1SDimitry Andric InstructionCost cost(ElementCount VF, VPCostContext &Ctx); 3354*0fca6ea1SDimitry Andric 335506c3fb27SDimitry Andric VPBasicBlock *getEntry() { return Entry; } 335606c3fb27SDimitry Andric const VPBasicBlock *getEntry() const { return Entry; } 3357480093f4SDimitry Andric 335804eeddc0SDimitry Andric /// The trip count of the original loop. 335906c3fb27SDimitry Andric VPValue *getTripCount() const { 336006c3fb27SDimitry Andric assert(TripCount && "trip count needs to be set before accessing it"); 336104eeddc0SDimitry Andric return TripCount; 336204eeddc0SDimitry Andric } 336304eeddc0SDimitry Andric 3364*0fca6ea1SDimitry Andric /// Resets the trip count for the VPlan. The caller must make sure all uses of 3365*0fca6ea1SDimitry Andric /// the original trip count have been replaced. 3366*0fca6ea1SDimitry Andric void resetTripCount(VPValue *NewTripCount) { 3367*0fca6ea1SDimitry Andric assert(TripCount && NewTripCount && TripCount->getNumUsers() == 0 && 3368*0fca6ea1SDimitry Andric "TripCount always must be set"); 3369*0fca6ea1SDimitry Andric TripCount = NewTripCount; 3370*0fca6ea1SDimitry Andric } 3371*0fca6ea1SDimitry Andric 3372480093f4SDimitry Andric /// The backedge taken count of the original loop. 3373480093f4SDimitry Andric VPValue *getOrCreateBackedgeTakenCount() { 3374480093f4SDimitry Andric if (!BackedgeTakenCount) 3375480093f4SDimitry Andric BackedgeTakenCount = new VPValue(); 3376480093f4SDimitry Andric return BackedgeTakenCount; 3377480093f4SDimitry Andric } 3378480093f4SDimitry Andric 337904eeddc0SDimitry Andric /// The vector trip count. 338004eeddc0SDimitry Andric VPValue &getVectorTripCount() { return VectorTripCount; } 338104eeddc0SDimitry Andric 33825f757f3fSDimitry Andric /// Returns VF * UF of the vector loop region. 33835f757f3fSDimitry Andric VPValue &getVFxUF() { return VFxUF; } 33845f757f3fSDimitry Andric 3385e8d8bef9SDimitry Andric void addVF(ElementCount VF) { VFs.insert(VF); } 3386480093f4SDimitry Andric 3387bdd1243dSDimitry Andric void setVF(ElementCount VF) { 3388bdd1243dSDimitry Andric assert(hasVF(VF) && "Cannot set VF not already in plan"); 3389bdd1243dSDimitry Andric VFs.clear(); 3390bdd1243dSDimitry Andric VFs.insert(VF); 3391bdd1243dSDimitry Andric } 3392bdd1243dSDimitry Andric 3393e8d8bef9SDimitry Andric bool hasVF(ElementCount VF) { return VFs.count(VF); } 3394*0fca6ea1SDimitry Andric bool hasScalableVF() { 3395*0fca6ea1SDimitry Andric return any_of(VFs, [](ElementCount VF) { return VF.isScalable(); }); 3396*0fca6ea1SDimitry Andric } 3397*0fca6ea1SDimitry Andric 3398*0fca6ea1SDimitry Andric /// Returns an iterator range over all VFs of the plan. 3399*0fca6ea1SDimitry Andric iterator_range<SmallSetVector<ElementCount, 2>::iterator> 3400*0fca6ea1SDimitry Andric vectorFactors() const { 3401*0fca6ea1SDimitry Andric return {VFs.begin(), VFs.end()}; 3402*0fca6ea1SDimitry Andric } 3403480093f4SDimitry Andric 3404bdd1243dSDimitry Andric bool hasScalarVFOnly() const { return VFs.size() == 1 && VFs[0].isScalar(); } 3405bdd1243dSDimitry Andric 3406bdd1243dSDimitry Andric bool hasUF(unsigned UF) const { return UFs.empty() || UFs.contains(UF); } 3407bdd1243dSDimitry Andric 3408bdd1243dSDimitry Andric void setUF(unsigned UF) { 3409bdd1243dSDimitry Andric assert(hasUF(UF) && "Cannot set the UF not already in plan"); 3410bdd1243dSDimitry Andric UFs.clear(); 3411bdd1243dSDimitry Andric UFs.insert(UF); 3412bdd1243dSDimitry Andric } 3413bdd1243dSDimitry Andric 3414bdd1243dSDimitry Andric /// Return a string with the name of the plan and the applicable VFs and UFs. 3415bdd1243dSDimitry Andric std::string getName() const; 3416480093f4SDimitry Andric 3417480093f4SDimitry Andric void setName(const Twine &newName) { Name = newName.str(); } 3418480093f4SDimitry Andric 3419*0fca6ea1SDimitry Andric /// Gets the live-in VPValue for \p V or adds a new live-in (if none exists 3420*0fca6ea1SDimitry Andric /// yet) for \p V. 3421*0fca6ea1SDimitry Andric VPValue *getOrAddLiveIn(Value *V) { 3422480093f4SDimitry Andric assert(V && "Trying to get or add the VPValue of a null Value"); 342306c3fb27SDimitry Andric if (!Value2VPValue.count(V)) { 342406c3fb27SDimitry Andric VPValue *VPV = new VPValue(V); 342506c3fb27SDimitry Andric VPLiveInsToFree.push_back(VPV); 3426*0fca6ea1SDimitry Andric assert(VPV->isLiveIn() && "VPV must be a live-in."); 3427*0fca6ea1SDimitry Andric assert(!Value2VPValue.count(V) && "Value already exists in VPlan"); 3428*0fca6ea1SDimitry Andric Value2VPValue[V] = VPV; 342906c3fb27SDimitry Andric } 343006c3fb27SDimitry Andric 3431*0fca6ea1SDimitry Andric assert(Value2VPValue.count(V) && "Value does not exist in VPlan"); 3432*0fca6ea1SDimitry Andric assert(Value2VPValue[V]->isLiveIn() && 3433*0fca6ea1SDimitry Andric "Only live-ins should be in mapping"); 3434*0fca6ea1SDimitry Andric return Value2VPValue[V]; 3435480093f4SDimitry Andric } 3436480093f4SDimitry Andric 3437*0fca6ea1SDimitry Andric /// Return the live-in VPValue for \p V, if there is one or nullptr otherwise. 3438*0fca6ea1SDimitry Andric VPValue *getLiveIn(Value *V) const { return Value2VPValue.lookup(V); } 3439*0fca6ea1SDimitry Andric 3440fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 34415f757f3fSDimitry Andric /// Print the live-ins of this VPlan to \p O. 34425f757f3fSDimitry Andric void printLiveIns(raw_ostream &O) const; 34435f757f3fSDimitry Andric 3444fe6060f1SDimitry Andric /// Print this VPlan to \p O. 3445fe6060f1SDimitry Andric void print(raw_ostream &O) const; 3446fe6060f1SDimitry Andric 3447fe6060f1SDimitry Andric /// Print this VPlan in DOT format to \p O. 3448fe6060f1SDimitry Andric void printDOT(raw_ostream &O) const; 3449fe6060f1SDimitry Andric 3450480093f4SDimitry Andric /// Dump the plan to stderr (for debugging). 3451fe6060f1SDimitry Andric LLVM_DUMP_METHOD void dump() const; 3452fe6060f1SDimitry Andric #endif 3453480093f4SDimitry Andric 345404eeddc0SDimitry Andric /// Returns the VPRegionBlock of the vector loop. 345504eeddc0SDimitry Andric VPRegionBlock *getVectorLoopRegion() { 345681ad6265SDimitry Andric return cast<VPRegionBlock>(getEntry()->getSingleSuccessor()); 345781ad6265SDimitry Andric } 345881ad6265SDimitry Andric const VPRegionBlock *getVectorLoopRegion() const { 345981ad6265SDimitry Andric return cast<VPRegionBlock>(getEntry()->getSingleSuccessor()); 346004eeddc0SDimitry Andric } 346104eeddc0SDimitry Andric 346204eeddc0SDimitry Andric /// Returns the canonical induction recipe of the vector loop. 346304eeddc0SDimitry Andric VPCanonicalIVPHIRecipe *getCanonicalIV() { 346404eeddc0SDimitry Andric VPBasicBlock *EntryVPBB = getVectorLoopRegion()->getEntryBasicBlock(); 346504eeddc0SDimitry Andric if (EntryVPBB->empty()) { 346604eeddc0SDimitry Andric // VPlan native path. 346704eeddc0SDimitry Andric EntryVPBB = cast<VPBasicBlock>(EntryVPBB->getSingleSuccessor()); 346804eeddc0SDimitry Andric } 346904eeddc0SDimitry Andric return cast<VPCanonicalIVPHIRecipe>(&*EntryVPBB->begin()); 347004eeddc0SDimitry Andric } 347104eeddc0SDimitry Andric 347281ad6265SDimitry Andric void addLiveOut(PHINode *PN, VPValue *V); 347381ad6265SDimitry Andric 347481ad6265SDimitry Andric void removeLiveOut(PHINode *PN) { 347581ad6265SDimitry Andric delete LiveOuts[PN]; 347681ad6265SDimitry Andric LiveOuts.erase(PN); 347781ad6265SDimitry Andric } 347881ad6265SDimitry Andric 347981ad6265SDimitry Andric const MapVector<PHINode *, VPLiveOut *> &getLiveOuts() const { 348081ad6265SDimitry Andric return LiveOuts; 348181ad6265SDimitry Andric } 348281ad6265SDimitry Andric 348306c3fb27SDimitry Andric VPValue *getSCEVExpansion(const SCEV *S) const { 348406c3fb27SDimitry Andric return SCEVToExpansion.lookup(S); 348506c3fb27SDimitry Andric } 348606c3fb27SDimitry Andric 348706c3fb27SDimitry Andric void addSCEVExpansion(const SCEV *S, VPValue *V) { 348806c3fb27SDimitry Andric assert(!SCEVToExpansion.contains(S) && "SCEV already expanded"); 348906c3fb27SDimitry Andric SCEVToExpansion[S] = V; 349006c3fb27SDimitry Andric } 349106c3fb27SDimitry Andric 349206c3fb27SDimitry Andric /// \return The block corresponding to the original preheader. 349306c3fb27SDimitry Andric VPBasicBlock *getPreheader() { return Preheader; } 349406c3fb27SDimitry Andric const VPBasicBlock *getPreheader() const { return Preheader; } 349506c3fb27SDimitry Andric 3496*0fca6ea1SDimitry Andric /// Clone the current VPlan, update all VPValues of the new VPlan and cloned 3497*0fca6ea1SDimitry Andric /// recipes to refer to the clones, and return it. 3498*0fca6ea1SDimitry Andric VPlan *duplicate(); 3499480093f4SDimitry Andric }; 3500480093f4SDimitry Andric 3501fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 3502480093f4SDimitry Andric /// VPlanPrinter prints a given VPlan to a given output stream. The printing is 3503480093f4SDimitry Andric /// indented and follows the dot format. 3504480093f4SDimitry Andric class VPlanPrinter { 3505480093f4SDimitry Andric raw_ostream &OS; 3506480093f4SDimitry Andric const VPlan &Plan; 3507480093f4SDimitry Andric unsigned Depth = 0; 3508480093f4SDimitry Andric unsigned TabWidth = 2; 3509480093f4SDimitry Andric std::string Indent; 3510480093f4SDimitry Andric unsigned BID = 0; 3511480093f4SDimitry Andric SmallDenseMap<const VPBlockBase *, unsigned> BlockID; 3512480093f4SDimitry Andric 35135ffd83dbSDimitry Andric VPSlotTracker SlotTracker; 35145ffd83dbSDimitry Andric 3515480093f4SDimitry Andric /// Handle indentation. 3516480093f4SDimitry Andric void bumpIndent(int b) { Indent = std::string((Depth += b) * TabWidth, ' '); } 3517480093f4SDimitry Andric 3518480093f4SDimitry Andric /// Print a given \p Block of the Plan. 3519480093f4SDimitry Andric void dumpBlock(const VPBlockBase *Block); 3520480093f4SDimitry Andric 3521480093f4SDimitry Andric /// Print the information related to the CFG edges going out of a given 3522480093f4SDimitry Andric /// \p Block, followed by printing the successor blocks themselves. 3523480093f4SDimitry Andric void dumpEdges(const VPBlockBase *Block); 3524480093f4SDimitry Andric 3525480093f4SDimitry Andric /// Print a given \p BasicBlock, including its VPRecipes, followed by printing 3526480093f4SDimitry Andric /// its successor blocks. 3527480093f4SDimitry Andric void dumpBasicBlock(const VPBasicBlock *BasicBlock); 3528480093f4SDimitry Andric 3529480093f4SDimitry Andric /// Print a given \p Region of the Plan. 3530480093f4SDimitry Andric void dumpRegion(const VPRegionBlock *Region); 3531480093f4SDimitry Andric 3532480093f4SDimitry Andric unsigned getOrCreateBID(const VPBlockBase *Block) { 3533480093f4SDimitry Andric return BlockID.count(Block) ? BlockID[Block] : BlockID[Block] = BID++; 3534480093f4SDimitry Andric } 3535480093f4SDimitry Andric 3536349cc55cSDimitry Andric Twine getOrCreateName(const VPBlockBase *Block); 3537480093f4SDimitry Andric 3538349cc55cSDimitry Andric Twine getUID(const VPBlockBase *Block); 3539480093f4SDimitry Andric 3540480093f4SDimitry Andric /// Print the information related to a CFG edge between two VPBlockBases. 3541480093f4SDimitry Andric void drawEdge(const VPBlockBase *From, const VPBlockBase *To, bool Hidden, 3542480093f4SDimitry Andric const Twine &Label); 3543480093f4SDimitry Andric 3544fe6060f1SDimitry Andric public: 3545fe6060f1SDimitry Andric VPlanPrinter(raw_ostream &O, const VPlan &P) 3546fe6060f1SDimitry Andric : OS(O), Plan(P), SlotTracker(&P) {} 3547480093f4SDimitry Andric 3548fe6060f1SDimitry Andric LLVM_DUMP_METHOD void dump(); 3549480093f4SDimitry Andric }; 3550480093f4SDimitry Andric 3551480093f4SDimitry Andric struct VPlanIngredient { 3552e8d8bef9SDimitry Andric const Value *V; 3553480093f4SDimitry Andric 3554e8d8bef9SDimitry Andric VPlanIngredient(const Value *V) : V(V) {} 3555fe6060f1SDimitry Andric 3556fe6060f1SDimitry Andric void print(raw_ostream &O) const; 3557480093f4SDimitry Andric }; 3558480093f4SDimitry Andric 3559480093f4SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VPlanIngredient &I) { 3560fe6060f1SDimitry Andric I.print(OS); 3561480093f4SDimitry Andric return OS; 3562480093f4SDimitry Andric } 3563480093f4SDimitry Andric 3564480093f4SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VPlan &Plan) { 3565fe6060f1SDimitry Andric Plan.print(OS); 3566480093f4SDimitry Andric return OS; 3567480093f4SDimitry Andric } 3568fe6060f1SDimitry Andric #endif 3569480093f4SDimitry Andric 35700b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 35710b57cec5SDimitry Andric // VPlan Utilities 35720b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 35730b57cec5SDimitry Andric 35740b57cec5SDimitry Andric /// Class that provides utilities for VPBlockBases in VPlan. 35750b57cec5SDimitry Andric class VPBlockUtils { 35760b57cec5SDimitry Andric public: 35770b57cec5SDimitry Andric VPBlockUtils() = delete; 35780b57cec5SDimitry Andric 35790b57cec5SDimitry Andric /// Insert disconnected VPBlockBase \p NewBlock after \p BlockPtr. Add \p 35800b57cec5SDimitry Andric /// NewBlock as successor of \p BlockPtr and \p BlockPtr as predecessor of \p 35810eae32dcSDimitry Andric /// NewBlock, and propagate \p BlockPtr parent to \p NewBlock. \p BlockPtr's 358281ad6265SDimitry Andric /// successors are moved from \p BlockPtr to \p NewBlock. \p NewBlock must 358381ad6265SDimitry Andric /// have neither successors nor predecessors. 35840b57cec5SDimitry Andric static void insertBlockAfter(VPBlockBase *NewBlock, VPBlockBase *BlockPtr) { 35850b57cec5SDimitry Andric assert(NewBlock->getSuccessors().empty() && 35860eae32dcSDimitry Andric NewBlock->getPredecessors().empty() && 35870eae32dcSDimitry Andric "Can't insert new block with predecessors or successors."); 35880b57cec5SDimitry Andric NewBlock->setParent(BlockPtr->getParent()); 35890eae32dcSDimitry Andric SmallVector<VPBlockBase *> Succs(BlockPtr->successors()); 35900eae32dcSDimitry Andric for (VPBlockBase *Succ : Succs) { 35910eae32dcSDimitry Andric disconnectBlocks(BlockPtr, Succ); 35920eae32dcSDimitry Andric connectBlocks(NewBlock, Succ); 35930eae32dcSDimitry Andric } 35940eae32dcSDimitry Andric connectBlocks(BlockPtr, NewBlock); 35950b57cec5SDimitry Andric } 35960b57cec5SDimitry Andric 35970b57cec5SDimitry Andric /// Insert disconnected VPBlockBases \p IfTrue and \p IfFalse after \p 35980b57cec5SDimitry Andric /// BlockPtr. Add \p IfTrue and \p IfFalse as succesors of \p BlockPtr and \p 35990b57cec5SDimitry Andric /// BlockPtr as predecessor of \p IfTrue and \p IfFalse. Propagate \p BlockPtr 360081ad6265SDimitry Andric /// parent to \p IfTrue and \p IfFalse. \p BlockPtr must have no successors 360181ad6265SDimitry Andric /// and \p IfTrue and \p IfFalse must have neither successors nor 360281ad6265SDimitry Andric /// predecessors. 36030b57cec5SDimitry Andric static void insertTwoBlocksAfter(VPBlockBase *IfTrue, VPBlockBase *IfFalse, 360481ad6265SDimitry Andric VPBlockBase *BlockPtr) { 36050b57cec5SDimitry Andric assert(IfTrue->getSuccessors().empty() && 36060b57cec5SDimitry Andric "Can't insert IfTrue with successors."); 36070b57cec5SDimitry Andric assert(IfFalse->getSuccessors().empty() && 36080b57cec5SDimitry Andric "Can't insert IfFalse with successors."); 360981ad6265SDimitry Andric BlockPtr->setTwoSuccessors(IfTrue, IfFalse); 36100b57cec5SDimitry Andric IfTrue->setPredecessors({BlockPtr}); 36110b57cec5SDimitry Andric IfFalse->setPredecessors({BlockPtr}); 36120b57cec5SDimitry Andric IfTrue->setParent(BlockPtr->getParent()); 36130b57cec5SDimitry Andric IfFalse->setParent(BlockPtr->getParent()); 36140b57cec5SDimitry Andric } 36150b57cec5SDimitry Andric 36160b57cec5SDimitry Andric /// Connect VPBlockBases \p From and \p To bi-directionally. Append \p To to 36170b57cec5SDimitry Andric /// the successors of \p From and \p From to the predecessors of \p To. Both 36180b57cec5SDimitry Andric /// VPBlockBases must have the same parent, which can be null. Both 36190b57cec5SDimitry Andric /// VPBlockBases can be already connected to other VPBlockBases. 36200b57cec5SDimitry Andric static void connectBlocks(VPBlockBase *From, VPBlockBase *To) { 36210b57cec5SDimitry Andric assert((From->getParent() == To->getParent()) && 36220b57cec5SDimitry Andric "Can't connect two block with different parents"); 36230b57cec5SDimitry Andric assert(From->getNumSuccessors() < 2 && 36240b57cec5SDimitry Andric "Blocks can't have more than two successors."); 36250b57cec5SDimitry Andric From->appendSuccessor(To); 36260b57cec5SDimitry Andric To->appendPredecessor(From); 36270b57cec5SDimitry Andric } 36280b57cec5SDimitry Andric 36290b57cec5SDimitry Andric /// Disconnect VPBlockBases \p From and \p To bi-directionally. Remove \p To 36300b57cec5SDimitry Andric /// from the successors of \p From and \p From from the predecessors of \p To. 36310b57cec5SDimitry Andric static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To) { 36320b57cec5SDimitry Andric assert(To && "Successor to disconnect is null."); 36330b57cec5SDimitry Andric From->removeSuccessor(To); 36340b57cec5SDimitry Andric To->removePredecessor(From); 36350b57cec5SDimitry Andric } 36360b57cec5SDimitry Andric 3637fe6060f1SDimitry Andric /// Return an iterator range over \p Range which only includes \p BlockTy 3638fe6060f1SDimitry Andric /// blocks. The accesses are casted to \p BlockTy. 3639fe6060f1SDimitry Andric template <typename BlockTy, typename T> 3640fe6060f1SDimitry Andric static auto blocksOnly(const T &Range) { 3641fe6060f1SDimitry Andric // Create BaseTy with correct const-ness based on BlockTy. 3642bdd1243dSDimitry Andric using BaseTy = std::conditional_t<std::is_const<BlockTy>::value, 3643bdd1243dSDimitry Andric const VPBlockBase, VPBlockBase>; 3644fe6060f1SDimitry Andric 3645fe6060f1SDimitry Andric // We need to first create an iterator range over (const) BlocktTy & instead 3646fe6060f1SDimitry Andric // of (const) BlockTy * for filter_range to work properly. 3647fe6060f1SDimitry Andric auto Mapped = 3648fe6060f1SDimitry Andric map_range(Range, [](BaseTy *Block) -> BaseTy & { return *Block; }); 3649fe6060f1SDimitry Andric auto Filter = make_filter_range( 3650fe6060f1SDimitry Andric Mapped, [](BaseTy &Block) { return isa<BlockTy>(&Block); }); 3651fe6060f1SDimitry Andric return map_range(Filter, [](BaseTy &Block) -> BlockTy * { 3652fe6060f1SDimitry Andric return cast<BlockTy>(&Block); 3653fe6060f1SDimitry Andric }); 3654fe6060f1SDimitry Andric } 36550b57cec5SDimitry Andric }; 36560b57cec5SDimitry Andric 36570b57cec5SDimitry Andric class VPInterleavedAccessInfo { 36580b57cec5SDimitry Andric DenseMap<VPInstruction *, InterleaveGroup<VPInstruction> *> 36590b57cec5SDimitry Andric InterleaveGroupMap; 36600b57cec5SDimitry Andric 36610b57cec5SDimitry Andric /// Type for mapping of instruction based interleave groups to VPInstruction 36620b57cec5SDimitry Andric /// interleave groups 36630b57cec5SDimitry Andric using Old2NewTy = DenseMap<InterleaveGroup<Instruction> *, 36640b57cec5SDimitry Andric InterleaveGroup<VPInstruction> *>; 36650b57cec5SDimitry Andric 36660b57cec5SDimitry Andric /// Recursively \p Region and populate VPlan based interleave groups based on 36670b57cec5SDimitry Andric /// \p IAI. 36680b57cec5SDimitry Andric void visitRegion(VPRegionBlock *Region, Old2NewTy &Old2New, 36690b57cec5SDimitry Andric InterleavedAccessInfo &IAI); 36700b57cec5SDimitry Andric /// Recursively traverse \p Block and populate VPlan based interleave groups 36710b57cec5SDimitry Andric /// based on \p IAI. 36720b57cec5SDimitry Andric void visitBlock(VPBlockBase *Block, Old2NewTy &Old2New, 36730b57cec5SDimitry Andric InterleavedAccessInfo &IAI); 36740b57cec5SDimitry Andric 36750b57cec5SDimitry Andric public: 36760b57cec5SDimitry Andric VPInterleavedAccessInfo(VPlan &Plan, InterleavedAccessInfo &IAI); 36770b57cec5SDimitry Andric 36780b57cec5SDimitry Andric ~VPInterleavedAccessInfo() { 36790b57cec5SDimitry Andric SmallPtrSet<InterleaveGroup<VPInstruction> *, 4> DelSet; 36800b57cec5SDimitry Andric // Avoid releasing a pointer twice. 36810b57cec5SDimitry Andric for (auto &I : InterleaveGroupMap) 36820b57cec5SDimitry Andric DelSet.insert(I.second); 36830b57cec5SDimitry Andric for (auto *Ptr : DelSet) 36840b57cec5SDimitry Andric delete Ptr; 36850b57cec5SDimitry Andric } 36860b57cec5SDimitry Andric 36870b57cec5SDimitry Andric /// Get the interleave group that \p Instr belongs to. 36880b57cec5SDimitry Andric /// 36890b57cec5SDimitry Andric /// \returns nullptr if doesn't have such group. 36900b57cec5SDimitry Andric InterleaveGroup<VPInstruction> * 36910b57cec5SDimitry Andric getInterleaveGroup(VPInstruction *Instr) const { 3692e8d8bef9SDimitry Andric return InterleaveGroupMap.lookup(Instr); 36930b57cec5SDimitry Andric } 36940b57cec5SDimitry Andric }; 36950b57cec5SDimitry Andric 36960b57cec5SDimitry Andric /// Class that maps (parts of) an existing VPlan to trees of combined 36970b57cec5SDimitry Andric /// VPInstructions. 36980b57cec5SDimitry Andric class VPlanSlp { 36990b57cec5SDimitry Andric enum class OpMode { Failed, Load, Opcode }; 37000b57cec5SDimitry Andric 37010b57cec5SDimitry Andric /// A DenseMapInfo implementation for using SmallVector<VPValue *, 4> as 37020b57cec5SDimitry Andric /// DenseMap keys. 37030b57cec5SDimitry Andric struct BundleDenseMapInfo { 37040b57cec5SDimitry Andric static SmallVector<VPValue *, 4> getEmptyKey() { 37050b57cec5SDimitry Andric return {reinterpret_cast<VPValue *>(-1)}; 37060b57cec5SDimitry Andric } 37070b57cec5SDimitry Andric 37080b57cec5SDimitry Andric static SmallVector<VPValue *, 4> getTombstoneKey() { 37090b57cec5SDimitry Andric return {reinterpret_cast<VPValue *>(-2)}; 37100b57cec5SDimitry Andric } 37110b57cec5SDimitry Andric 37120b57cec5SDimitry Andric static unsigned getHashValue(const SmallVector<VPValue *, 4> &V) { 37130b57cec5SDimitry Andric return static_cast<unsigned>(hash_combine_range(V.begin(), V.end())); 37140b57cec5SDimitry Andric } 37150b57cec5SDimitry Andric 37160b57cec5SDimitry Andric static bool isEqual(const SmallVector<VPValue *, 4> &LHS, 37170b57cec5SDimitry Andric const SmallVector<VPValue *, 4> &RHS) { 37180b57cec5SDimitry Andric return LHS == RHS; 37190b57cec5SDimitry Andric } 37200b57cec5SDimitry Andric }; 37210b57cec5SDimitry Andric 37220b57cec5SDimitry Andric /// Mapping of values in the original VPlan to a combined VPInstruction. 37230b57cec5SDimitry Andric DenseMap<SmallVector<VPValue *, 4>, VPInstruction *, BundleDenseMapInfo> 37240b57cec5SDimitry Andric BundleToCombined; 37250b57cec5SDimitry Andric 37260b57cec5SDimitry Andric VPInterleavedAccessInfo &IAI; 37270b57cec5SDimitry Andric 37280b57cec5SDimitry Andric /// Basic block to operate on. For now, only instructions in a single BB are 37290b57cec5SDimitry Andric /// considered. 37300b57cec5SDimitry Andric const VPBasicBlock &BB; 37310b57cec5SDimitry Andric 37320b57cec5SDimitry Andric /// Indicates whether we managed to combine all visited instructions or not. 37330b57cec5SDimitry Andric bool CompletelySLP = true; 37340b57cec5SDimitry Andric 37350b57cec5SDimitry Andric /// Width of the widest combined bundle in bits. 37360b57cec5SDimitry Andric unsigned WidestBundleBits = 0; 37370b57cec5SDimitry Andric 37380b57cec5SDimitry Andric using MultiNodeOpTy = 37390b57cec5SDimitry Andric typename std::pair<VPInstruction *, SmallVector<VPValue *, 4>>; 37400b57cec5SDimitry Andric 37410b57cec5SDimitry Andric // Input operand bundles for the current multi node. Each multi node operand 37420b57cec5SDimitry Andric // bundle contains values not matching the multi node's opcode. They will 37430b57cec5SDimitry Andric // be reordered in reorderMultiNodeOps, once we completed building a 37440b57cec5SDimitry Andric // multi node. 37450b57cec5SDimitry Andric SmallVector<MultiNodeOpTy, 4> MultiNodeOps; 37460b57cec5SDimitry Andric 37470b57cec5SDimitry Andric /// Indicates whether we are building a multi node currently. 37480b57cec5SDimitry Andric bool MultiNodeActive = false; 37490b57cec5SDimitry Andric 37500b57cec5SDimitry Andric /// Check if we can vectorize Operands together. 37510b57cec5SDimitry Andric bool areVectorizable(ArrayRef<VPValue *> Operands) const; 37520b57cec5SDimitry Andric 37530b57cec5SDimitry Andric /// Add combined instruction \p New for the bundle \p Operands. 37540b57cec5SDimitry Andric void addCombined(ArrayRef<VPValue *> Operands, VPInstruction *New); 37550b57cec5SDimitry Andric 37560b57cec5SDimitry Andric /// Indicate we hit a bundle we failed to combine. Returns nullptr for now. 37570b57cec5SDimitry Andric VPInstruction *markFailed(); 37580b57cec5SDimitry Andric 37590b57cec5SDimitry Andric /// Reorder operands in the multi node to maximize sequential memory access 37600b57cec5SDimitry Andric /// and commutative operations. 37610b57cec5SDimitry Andric SmallVector<MultiNodeOpTy, 4> reorderMultiNodeOps(); 37620b57cec5SDimitry Andric 37630b57cec5SDimitry Andric /// Choose the best candidate to use for the lane after \p Last. The set of 37640b57cec5SDimitry Andric /// candidates to choose from are values with an opcode matching \p Last's 37650b57cec5SDimitry Andric /// or loads consecutive to \p Last. 37660b57cec5SDimitry Andric std::pair<OpMode, VPValue *> getBest(OpMode Mode, VPValue *Last, 37670b57cec5SDimitry Andric SmallPtrSetImpl<VPValue *> &Candidates, 37680b57cec5SDimitry Andric VPInterleavedAccessInfo &IAI); 37690b57cec5SDimitry Andric 3770fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 37710b57cec5SDimitry Andric /// Print bundle \p Values to dbgs(). 37720b57cec5SDimitry Andric void dumpBundle(ArrayRef<VPValue *> Values); 3773fe6060f1SDimitry Andric #endif 37740b57cec5SDimitry Andric 37750b57cec5SDimitry Andric public: 37760b57cec5SDimitry Andric VPlanSlp(VPInterleavedAccessInfo &IAI, VPBasicBlock &BB) : IAI(IAI), BB(BB) {} 37770b57cec5SDimitry Andric 3778e8d8bef9SDimitry Andric ~VPlanSlp() = default; 37790b57cec5SDimitry Andric 37800b57cec5SDimitry Andric /// Tries to build an SLP tree rooted at \p Operands and returns a 37810b57cec5SDimitry Andric /// VPInstruction combining \p Operands, if they can be combined. 37820b57cec5SDimitry Andric VPInstruction *buildGraph(ArrayRef<VPValue *> Operands); 37830b57cec5SDimitry Andric 37840b57cec5SDimitry Andric /// Return the width of the widest combined bundle in bits. 37850b57cec5SDimitry Andric unsigned getWidestBundleBits() const { return WidestBundleBits; } 37860b57cec5SDimitry Andric 37870b57cec5SDimitry Andric /// Return true if all visited instruction can be combined. 37880b57cec5SDimitry Andric bool isCompletelySLP() const { return CompletelySLP; } 37890b57cec5SDimitry Andric }; 37901fd87a68SDimitry Andric 37911fd87a68SDimitry Andric namespace vputils { 37921fd87a68SDimitry Andric 37931fd87a68SDimitry Andric /// Returns true if only the first lane of \p Def is used. 3794*0fca6ea1SDimitry Andric bool onlyFirstLaneUsed(const VPValue *Def); 37951fd87a68SDimitry Andric 37965f757f3fSDimitry Andric /// Returns true if only the first part of \p Def is used. 3797*0fca6ea1SDimitry Andric bool onlyFirstPartUsed(const VPValue *Def); 37985f757f3fSDimitry Andric 379981ad6265SDimitry Andric /// Get or create a VPValue that corresponds to the expansion of \p Expr. If \p 380081ad6265SDimitry Andric /// Expr is a SCEVConstant or SCEVUnknown, return a VPValue wrapping the live-in 380181ad6265SDimitry Andric /// value. Otherwise return a VPExpandSCEVRecipe to expand \p Expr. If \p Plan's 380281ad6265SDimitry Andric /// pre-header already contains a recipe expanding \p Expr, return it. If not, 380381ad6265SDimitry Andric /// create a new one. 380481ad6265SDimitry Andric VPValue *getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr, 380581ad6265SDimitry Andric ScalarEvolution &SE); 3806bdd1243dSDimitry Andric 3807bdd1243dSDimitry Andric /// Returns true if \p VPV is uniform after vectorization. 3808bdd1243dSDimitry Andric inline bool isUniformAfterVectorization(VPValue *VPV) { 3809bdd1243dSDimitry Andric // A value defined outside the vector region must be uniform after 3810bdd1243dSDimitry Andric // vectorization inside a vector region. 3811bdd1243dSDimitry Andric if (VPV->isDefinedOutsideVectorRegions()) 3812bdd1243dSDimitry Andric return true; 3813bdd1243dSDimitry Andric VPRecipeBase *Def = VPV->getDefiningRecipe(); 3814bdd1243dSDimitry Andric assert(Def && "Must have definition for value defined inside vector region"); 3815bdd1243dSDimitry Andric if (auto Rep = dyn_cast<VPReplicateRecipe>(Def)) 3816bdd1243dSDimitry Andric return Rep->isUniform(); 381706c3fb27SDimitry Andric if (auto *GEP = dyn_cast<VPWidenGEPRecipe>(Def)) 381806c3fb27SDimitry Andric return all_of(GEP->operands(), isUniformAfterVectorization); 38191db9f3b2SDimitry Andric if (auto *VPI = dyn_cast<VPInstruction>(Def)) 3820*0fca6ea1SDimitry Andric return VPI->isSingleScalar() || VPI->isVectorToScalar(); 3821bdd1243dSDimitry Andric return false; 3822bdd1243dSDimitry Andric } 3823*0fca6ea1SDimitry Andric 3824*0fca6ea1SDimitry Andric /// Return true if \p V is a header mask in \p Plan. 3825*0fca6ea1SDimitry Andric bool isHeaderMask(VPValue *V, VPlan &Plan); 38261fd87a68SDimitry Andric } // end namespace vputils 38271fd87a68SDimitry Andric 38280b57cec5SDimitry Andric } // end namespace llvm 38290b57cec5SDimitry Andric 38300b57cec5SDimitry Andric #endif // LLVM_TRANSFORMS_VECTORIZE_VPLAN_H 3831