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.
getReciprocalPredBlockProb()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
isEmptyVFRange107e8d8bef9SDimitry Andric bool isEmpty() const {
108e8d8bef9SDimitry Andric return End.getKnownMinValue() <= Start.getKnownMinValue();
109e8d8bef9SDimitry Andric }
110e8d8bef9SDimitry Andric
VFRangeVFRange111e8d8bef9SDimitry 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:
iteratorVFRange12806c3fb27SDimitry 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
beginVFRange14006c3fb27SDimitry Andric iterator begin() { return iterator(Start); }
endVFRange14106c3fb27SDimitry 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:
VPLane(unsigned Lane,Kind LaneKind)178fe6060f1SDimitry Andric VPLane(unsigned Lane, Kind LaneKind) : Lane(Lane), LaneKind(LaneKind) {}
179fe6060f1SDimitry Andric
getFirstLane()180fe6060f1SDimitry Andric static VPLane getFirstLane() { return VPLane(0, VPLane::Kind::First); }
181fe6060f1SDimitry Andric
getLaneFromEnd(const ElementCount & VF,unsigned Offset)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
getLastLaneForVF(const ElementCount & VF)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.
getKnownLane()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.
getKind()212fe6060f1SDimitry Andric Kind getKind() const { return LaneKind; }
213fe6060f1SDimitry Andric
214fe6060f1SDimitry Andric /// Returns true if this is the first lane of the whole vector.
isFirstLane()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.
mapToCacheIndex(const ElementCount & 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.
getNumCachedLanes(const ElementCount & 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)
PartVPIteration246fe6060f1SDimitry Andric : Part(Part), Lane(Lane, Kind) {}
2470b57cec5SDimitry Andric
VPIterationVPIteration248fe6060f1SDimitry Andric VPIteration(unsigned Part, const VPLane &Lane) : Part(Part), Lane(Lane) {}
2490b57cec5SDimitry Andric
isFirstIterationVPIteration250fe6060f1SDimitry 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
hasVectorValueVPTransformState289e8d8bef9SDimitry 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
hasScalarValueVPTransformState295e8d8bef9SDimitry 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.
resetVPTransformState322fe6060f1SDimitry 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.
setVPTransformState330e8d8bef9SDimitry 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.
resetVPTransformState344fe6060f1SDimitry 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
CFGStateVPTransformState::CFGState397*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.
appendSuccessor(VPBlockBase * Successor)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.
appendPredecessor(VPBlockBase * Predecessor)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.
removePredecessor(VPBlockBase * Predecessor)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.
removeSuccessor(VPBlockBase * Successor)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:
VPBlockBase(const unsigned char SC,const std::string & N)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
getName()5000b57cec5SDimitry Andric const std::string &getName() const { return Name; }
5010b57cec5SDimitry Andric
setName(const Twine & newName)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.
getVPBlockID()5070b57cec5SDimitry Andric unsigned getVPBlockID() const { return SubclassID; }
5080b57cec5SDimitry Andric
getParent()5090b57cec5SDimitry Andric VPRegionBlock *getParent() { return Parent; }
getParent()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
setParent(VPRegionBlock * P)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
getSuccessors()5340b57cec5SDimitry Andric const VPBlocksTy &getSuccessors() const { return Successors; }
getSuccessors()5350b57cec5SDimitry Andric VPBlocksTy &getSuccessors() { return Successors; }
5360b57cec5SDimitry Andric
successors()5370eae32dcSDimitry Andric iterator_range<VPBlockBase **> successors() { return Successors; }
5380eae32dcSDimitry Andric
getPredecessors()5390b57cec5SDimitry Andric const VPBlocksTy &getPredecessors() const { return Predecessors; }
getPredecessors()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.
getSingleSuccessor()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.
getSinglePredecessor()5500b57cec5SDimitry Andric VPBlockBase *getSinglePredecessor() const {
5510b57cec5SDimitry Andric return (Predecessors.size() == 1 ? *Predecessors.begin() : nullptr);
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric
getNumSuccessors()5540b57cec5SDimitry Andric size_t getNumSuccessors() const { return Successors.size(); }
getNumPredecessors()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.
getHierarchicalSuccessors()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.
getSingleHierarchicalSuccessor()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.
getHierarchicalPredecessors()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.
getSingleHierarchicalPredecessor()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.
setOneSuccessor(VPBlockBase * Successor)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.
setTwoSuccessors(VPBlockBase * IfTrue,VPBlockBase * IfFalse)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.
setPredecessors(ArrayRef<VPBlockBase * > 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.
setSuccessors(ArrayRef<VPBlockBase * > 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.
clearPredecessors()6390b57cec5SDimitry Andric void clearPredecessors() { Predecessors.clear(); }
6400b57cec5SDimitry Andric
64181ad6265SDimitry Andric /// Remove all the successors of this block.
clearSuccessors()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.
isLegalToHoistInto()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)
printAsOperand(raw_ostream & OS,bool PrintType)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.
print(raw_ostream & 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().
dump()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:
VPLiveOut(PHINode * Phi,VPValue * Op)70881ad6265SDimitry Andric VPLiveOut(PHINode *Phi, VPValue *Op)
70981ad6265SDimitry Andric : VPUser({Op}, VPUser::VPUserID::LiveOut), Phi(Phi) {}
71081ad6265SDimitry Andric
classof(const VPUser * U)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.
usesScalars(const VPValue * 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
getPhi()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
VPCostContextVPCostContext744*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 = {})
VPDef(SC)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 = {})
VPDef(SC)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.
getParent()7890b57cec5SDimitry Andric VPBasicBlock *getParent() { return Parent; }
getParent()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.
classof(const VPDef * D)831e8d8bef9SDimitry Andric static inline bool classof(const VPDef *D) {
832e8d8bef9SDimitry Andric // All VPDefs are also VPRecipeBases.
833e8d8bef9SDimitry Andric return true;
834e8d8bef9SDimitry Andric }
835fe6060f1SDimitry Andric
classof(const VPUser * U)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.
isPhi()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.
mayReadOrWriteMemory()855fe6060f1SDimitry Andric bool mayReadOrWriteMemory() const {
856fe6060f1SDimitry Andric return mayReadFromMemory() || mayWriteToMemory();
857fe6060f1SDimitry Andric }
8585f757f3fSDimitry Andric
8595f757f3fSDimitry Andric /// Returns the debug location of the recipe.
getDebugLoc()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 = {})
VPRecipeBase(SC,Operands,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 = {})
VPRecipeBase(SC,Operands,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 = {})
VPRecipeBase(SC,Operands,DL)9047a6dacacSDimitry Andric : VPRecipeBase(SC, Operands, DL), VPValue(this, UV) {}
9057a6dacacSDimitry Andric
classof(const VPRecipeBase * R)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
classof(const VPUser * U)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.
getUnderlyingInstr()9557a6dacacSDimitry Andric Instruction *getUnderlyingInstr() {
9567a6dacacSDimitry Andric return cast<Instruction>(getUnderlyingValue());
9577a6dacacSDimitry Andric }
getUnderlyingInstr()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
WrapFlagsTyWrapFlagsTy9815f757f3fSDimitry 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;
DisjointFlagsTyDisjointFlagsTy986*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;
GEPFlagsTyGEPFlagsTy9921db9f3b2SDimitry 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:
transferFlags(VPRecipeWithIRFlags & Other)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 = {})
VPSingleDefRecipe(SC,Operands,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>
VPRecipeWithIRFlags(const unsigned char SC,IterT Operands,Instruction & I)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 = {})
VPSingleDefRecipe(SC,Operands,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 = {})
VPSingleDefRecipe(SC,Operands,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 = {})
VPSingleDefRecipe(SC,Operands,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 = {})
VPSingleDefRecipe(SC,Operands,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 = {})
VPSingleDefRecipe(SC,Operands,DL)10997a6dacacSDimitry Andric : VPSingleDefRecipe(SC, Operands, DL), OpType(OperationType::GEPOp),
11001db9f3b2SDimitry Andric GEPFlags(GEPFlags) {}
11011db9f3b2SDimitry Andric
11021db9f3b2SDimitry Andric public:
classof(const VPRecipeBase * R)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
classof(const VPUser * U)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.
dropPoisonGeneratingFlags()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.
setFlags(Instruction * 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
getPredicate()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
isInBounds()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.
hasFastMathFlags()11985f757f3fSDimitry Andric bool hasFastMathFlags() const { return OpType == OperationType::FPMathOp; }
11995f757f3fSDimitry Andric
12005f757f3fSDimitry Andric FastMathFlags getFastMathFlags() const;
12015f757f3fSDimitry Andric
hasNoUnsignedWrap()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
hasNoSignedWrap()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
isDisjoint()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 = "")
VPRecipeWithIRFlags(VPDef::VPInstructionSC,Operands,DL)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 = "")
VPInstruction(Opcode,ArrayRef<VPValue * > (Operands),DL,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 = "")
VPRecipeWithIRFlags(VPDef::VPInstructionSC,Operands,WrapFlags,DL)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 = "")
VPRecipeWithIRFlags(VPDef::VPInstructionSC,Operands,DisjointFlag,DL)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
VP_CLASSOF_IMPL(VPDef::VPInstructionSC)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
getOpcode()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.
mayWriteToMemory()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
hasResult()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>
VPWidenRecipe(Instruction & I,iterator_range<IterT> Operands)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
clone()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
getOpcode()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:
VPWidenCastRecipe(Instruction::CastOps Opcode,VPValue * Op,Type * ResultTy,CastInst & UI)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
VPWidenCastRecipe(Instruction::CastOps Opcode,VPValue * Op,Type * ResultTy)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
clone()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
getOpcode()148006c3fb27SDimitry Andric Instruction::CastOps getOpcode() const { return Opcode; }
148106c3fb27SDimitry Andric
148206c3fb27SDimitry Andric /// Returns the result type of the cast.
getResultType()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:
VPScalarCastRecipe(Instruction::CastOps Opcode,VPValue * Op,Type * ResultTy)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
clone()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.
getResultType()1515*0fca6ea1SDimitry Andric Type *getResultType() const { return ResultTy; }
1516*0fca6ea1SDimitry Andric
onlyFirstLaneUsed(const VPValue * Op)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)
VPSingleDefRecipe(VPDef::VPWidenCallSC,CallArguments,UV,DL)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
clone()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
getCalledScalarFunction()1560*0fca6ea1SDimitry Andric Function *getCalledScalarFunction() const {
1561*0fca6ea1SDimitry Andric return cast<Function>(getOperand(getNumOperands() - 1)->getLiveInIRValue());
1562*0fca6ea1SDimitry Andric }
1563*0fca6ea1SDimitry Andric
arg_operands()1564*0fca6ea1SDimitry Andric operand_range arg_operands() {
1565*0fca6ea1SDimitry Andric return make_range(op_begin(), op_begin() + getNumOperands() - 1);
1566*0fca6ea1SDimitry Andric }
arg_operands()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>
VPWidenSelectRecipeVPWidenSelectRecipe158106c3fb27SDimitry 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
cloneVPWidenSelectRecipe1587*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
getCondVPWidenSelectRecipe160306c3fb27SDimitry Andric VPValue *getCond() const {
160406c3fb27SDimitry Andric return getOperand(0);
160506c3fb27SDimitry Andric }
160606c3fb27SDimitry Andric
isInvariantCondVPWidenSelectRecipe160706c3fb27SDimitry 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 {
isPointerLoopInvariant()161406c3fb27SDimitry Andric bool isPointerLoopInvariant() const {
161506c3fb27SDimitry Andric return getOperand(0)->isDefinedOutsideVectorRegions();
161606c3fb27SDimitry Andric }
161706c3fb27SDimitry Andric
isIndexLoopInvariant(unsigned I)161806c3fb27SDimitry Andric bool isIndexLoopInvariant(unsigned I) const {
161906c3fb27SDimitry Andric return getOperand(I + 1)->isDefinedOutsideVectorRegions();
162006c3fb27SDimitry Andric }
162106c3fb27SDimitry Andric
areAllOperandsInvariant()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>
VPWidenGEPRecipe(GetElementPtrInst * GEP,iterator_range<IterT> Operands)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
clone()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:
VPVectorPointerRecipe(VPValue * Ptr,Type * IndexedTy,bool IsReverse,bool IsInBounds,DebugLoc DL)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
onlyFirstLaneUsed(const VPValue * Op)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
clone()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 = {})
VPSingleDefRecipe(VPDefID,ArrayRef<VPValue * > (),UnderlyingInstr,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.
classof(const VPRecipeBase * B)172404eeddc0SDimitry Andric static inline bool classof(const VPRecipeBase *B) {
1725bdd1243dSDimitry Andric return B->getVPDefID() >= VPDef::VPFirstHeaderPHISC &&
172606c3fb27SDimitry Andric B->getVPDefID() <= VPDef::VPLastHeaderPHISC;
172704eeddc0SDimitry Andric }
classof(const VPValue * V)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.
getStartValue()174404eeddc0SDimitry Andric VPValue *getStartValue() {
174504eeddc0SDimitry Andric return getNumOperands() == 0 ? nullptr : getOperand(0);
174604eeddc0SDimitry Andric }
getStartValue()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.
setStartValue(VPValue * V)1752bdd1243dSDimitry Andric void setStartValue(VPValue *V) { setOperand(0, V); }
1753bdd1243dSDimitry Andric
175404eeddc0SDimitry Andric /// Returns the incoming value from the loop backedge.
getBackedgeValue()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.
getBackedgeRecipe()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:
VPWidenIntOrFpInductionRecipe(PHINode * IV,VPValue * Start,VPValue * Step,const InductionDescriptor & IndDesc)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
VPWidenIntOrFpInductionRecipe(PHINode * IV,VPValue * Start,VPValue * Step,const InductionDescriptor & IndDesc,TruncInst * Trunc)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
clone()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
getBackedgeValue()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
getBackedgeRecipe()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.
getStepValue()182306c3fb27SDimitry Andric VPValue *getStepValue() { return getOperand(1); }
getStepValue()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.
getTruncInst()182806c3fb27SDimitry Andric TruncInst *getTruncInst() { return Trunc; }
getTruncInst()182906c3fb27SDimitry Andric const TruncInst *getTruncInst() const { return Trunc; }
183006c3fb27SDimitry Andric
getPHINode()183106c3fb27SDimitry Andric PHINode *getPHINode() { return IV; }
183206c3fb27SDimitry Andric
183306c3fb27SDimitry Andric /// Returns the induction descriptor for the recipe.
getInductionDescriptor()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.
getScalarType()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.
VPWidenPointerInductionRecipe(PHINode * Phi,VPValue * Start,VPValue * Step,const InductionDescriptor & IndDesc,bool IsScalarAfterVectorization)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
clone()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.
getInductionDescriptor()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)
VPSingleDefRecipe(VPDef::VPWidenPHISC,ArrayRef<VPValue * > (),Phi)1901*0fca6ea1SDimitry Andric : VPSingleDefRecipe(VPDef::VPWidenPHISC, ArrayRef<VPValue *>(), Phi) {
190204eeddc0SDimitry Andric if (Start)
190304eeddc0SDimitry Andric addOperand(Start);
1904e8d8bef9SDimitry Andric }
1905e8d8bef9SDimitry Andric
clone()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.
addIncoming(VPValue * IncomingV,VPBasicBlock * IncomingBlock)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.
getIncomingBlock(unsigned I)1930fe6060f1SDimitry Andric VPBasicBlock *getIncomingBlock(unsigned I) { return IncomingBlocks[I]; }
193104eeddc0SDimitry Andric
193204eeddc0SDimitry Andric /// Returns the \p I th incoming VPValue.
getIncomingValue(unsigned I)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 {
VPFirstOrderRecurrencePHIRecipeVPFirstOrderRecurrencePHIRecipe1940fe6060f1SDimitry Andric VPFirstOrderRecurrencePHIRecipe(PHINode *Phi, VPValue &Start)
1941bdd1243dSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPFirstOrderRecurrencePHISC, Phi, &Start) {}
1942fe6060f1SDimitry Andric
VP_CLASSOF_IMPLVPFirstOrderRecurrencePHIRecipe1943bdd1243dSDimitry 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
cloneVPFirstOrderRecurrencePHIRecipe1949*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
clone()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
VP_CLASSOF_IMPL(VPDef::VPReductionPHISC)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
getRecurrenceDescriptor()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.
isOrdered()2017fe6060f1SDimitry Andric bool isOrdered() const { return IsOrdered; }
2018fe6060f1SDimitry Andric
2019fe6060f1SDimitry Andric /// Returns true, if the phi is part of an in-loop reduction.
isInLoop()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.
VPBlendRecipe(PHINode * Phi,ArrayRef<VPValue * > Operands)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
clone()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
VP_CLASSOF_IMPL(VPDef::VPBlendSC)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.
getIncomingValue(unsigned 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.
getMask(unsigned 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.
onlyFirstLaneUsed(const VPValue * 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:
VPInterleaveRecipe(const InterleaveGroup<Instruction> * IG,VPValue * Addr,ArrayRef<VPValue * > StoredValues,VPValue * Mask,bool NeedsMaskForGaps)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
clone()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
VP_CLASSOF_IMPL(VPDef::VPInterleaveSC)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.
getMask()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.
getStoredValues()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
getInterleaveGroup()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.
getNumStoreOperands()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.
onlyFirstLaneUsed(const VPValue * Op)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
getInsertPos()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:
VPReductionRecipe(const unsigned char SC,const RecurrenceDescriptor & R,Instruction * I,ArrayRef<VPValue * > Operands,VPValue * CondOp,bool IsOrdered)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:
VPReductionRecipe(const RecurrenceDescriptor & R,Instruction * I,VPValue * ChainOp,VPValue * VecOp,VPValue * CondOp,bool IsOrdered)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
clone()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
classof(const VPRecipeBase * R)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
classof(const VPUser * U)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.
getRecurrenceDescriptor()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.
isOrdered()2230*0fca6ea1SDimitry Andric bool isOrdered() const { return IsOrdered; };
2231*0fca6ea1SDimitry Andric /// Return true if the in-loop reduction is conditional.
isConditional()2232*0fca6ea1SDimitry Andric bool isConditional() const { return IsConditional; };
2233e8d8bef9SDimitry Andric /// The VPValue of the scalar Chain being accumulated.
getChainOp()2234e8d8bef9SDimitry Andric VPValue *getChainOp() const { return getOperand(0); }
2235e8d8bef9SDimitry Andric /// The VPValue of the vector value to be reduced.
getVecOp()2236e8d8bef9SDimitry Andric VPValue *getVecOp() const { return getOperand(1); }
2237e8d8bef9SDimitry Andric /// The VPValue of the condition for the block.
getCondOp()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:
VPReductionEVLRecipe(VPReductionRecipe * R,VPValue * EVL,VPValue * CondOp)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
clone()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.
getEVL()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.
onlyFirstLaneUsed(const VPValue * 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
clone()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
isUniform()2328e8d8bef9SDimitry Andric bool isUniform() const { return IsUniform; }
2329fe6060f1SDimitry Andric
isPredicated()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.
onlyFirstLaneUsed(const VPValue * 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.
usesScalars(const VPValue * 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.
getMask()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
getOpcode()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:
VPBranchOnMaskRecipe(VPValue * BlockInMask)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
clone()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.
print(raw_ostream & O,const Twine & Indent,VPSlotTracker & SlotTracker)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.
getMask()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.
usesScalars(const VPValue * 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.
VPPredInstPHIRecipe(VPValue * PredV)2416e8d8bef9SDimitry Andric VPPredInstPHIRecipe(VPValue *PredV)
24177a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPPredInstPHISC, PredV) {}
24180b57cec5SDimitry Andric ~VPPredInstPHIRecipe() override = default;
24190b57cec5SDimitry Andric
clone()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.
usesScalars(const VPValue * 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
setMask(VPValue * Mask)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
VPWidenMemoryRecipe(const char unsigned SC,Instruction & I,std::initializer_list<VPValue * > Operands,bool Consecutive,bool Reverse,DebugLoc DL)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:
clone()2475*0fca6ea1SDimitry Andric VPWidenMemoryRecipe *clone() override {
2476*0fca6ea1SDimitry Andric llvm_unreachable("cloning not supported");
24775ffd83dbSDimitry Andric }
24785ffd83dbSDimitry Andric
classof(const VPRecipeBase * R)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
classof(const VPUser * U)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.
isConsecutive()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.
isReverse()2496*0fca6ea1SDimitry Andric bool isReverse() const { return Reverse; }
24970b57cec5SDimitry Andric
2498480093f4SDimitry Andric /// Return the address accessed by this recipe.
getAddr()2499*0fca6ea1SDimitry Andric VPValue *getAddr() const { return getOperand(0); }
2500*0fca6ea1SDimitry Andric
2501*0fca6ea1SDimitry Andric /// Returns true if the recipe is masked.
isMasked()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.
getMask()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.
execute(VPTransformState & State)2512*0fca6ea1SDimitry Andric void execute(VPTransformState &State) override {
2513*0fca6ea1SDimitry Andric llvm_unreachable("VPWidenMemoryRecipe should not be instantiated.");
2514480093f4SDimitry Andric }
2515480093f4SDimitry Andric
getIngredient()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 {
VPWidenLoadRecipefinal2522*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
clonefinal2530*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.
onlyFirstLaneUsedfinal25481fd87a68SDimitry 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 {
VPWidenLoadEVLRecipefinal2561*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
VP_CLASSOF_IMPLfinal2569*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.
onlyFirstLaneUsedfinal2584*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 {
VPWidenStoreRecipefinal2596*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
clonefinal2603*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.
getStoredValuefinal2612*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.
onlyFirstLaneUsedfinal2624*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 {
VPWidenStoreEVLRecipefinal2637*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
VP_CLASSOF_IMPLfinal2645*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.
getEVLfinal2651*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.
onlyFirstLaneUsedfinal2663*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:
VPExpandSCEVRecipe(const SCEV * Expr,ScalarEvolution & SE)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
clone()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
getSCEV()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:
VPCanonicalIVPHIRecipe(VPValue * StartV,DebugLoc DL)271204eeddc0SDimitry Andric VPCanonicalIVPHIRecipe(VPValue *StartV, DebugLoc DL)
27135f757f3fSDimitry Andric : VPHeaderPHIRecipe(VPDef::VPCanonicalIVPHISC, nullptr, StartV, DL) {}
271404eeddc0SDimitry Andric
271504eeddc0SDimitry Andric ~VPCanonicalIVPHIRecipe() override = default;
271604eeddc0SDimitry Andric
clone()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
VP_CLASSOF_IMPL(VPDef::VPCanonicalIVPHISC)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.
getScalarType()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.
onlyFirstLaneUsed(const VPValue * 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.
onlyFirstPartUsed(const VPValue * 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:
VPActiveLaneMaskPHIRecipe(VPValue * StartMask,DebugLoc DL)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
clone()2775*0fca6ea1SDimitry Andric VPActiveLaneMaskPHIRecipe *clone() override {
2776*0fca6ea1SDimitry Andric return new VPActiveLaneMaskPHIRecipe(getOperand(0), getDebugLoc());
2777*0fca6ea1SDimitry Andric }
2778*0fca6ea1SDimitry Andric
VP_CLASSOF_IMPL(VPDef::VPActiveLaneMaskPHISC)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:
VPEVLBasedIVPHIRecipe(VPValue * StartIV,DebugLoc DL)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
clone()2806*0fca6ea1SDimitry Andric VPEVLBasedIVPHIRecipe *clone() override {
2807*0fca6ea1SDimitry Andric llvm_unreachable("cloning not implemented yet");
2808*0fca6ea1SDimitry Andric }
2809*0fca6ea1SDimitry Andric
VP_CLASSOF_IMPL(VPDef::VPEVLBasedIVPHISC)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.
onlyFirstLaneUsed(const VPValue * 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:
VPWidenCanonicalIVRecipe(VPCanonicalIVPHIRecipe * CanonicalIV)283704eeddc0SDimitry Andric VPWidenCanonicalIVRecipe(VPCanonicalIVPHIRecipe *CanonicalIV)
28387a6dacacSDimitry Andric : VPSingleDefRecipe(VPDef::VPWidenCanonicalIVSC, {CanonicalIV}) {}
2839e8d8bef9SDimitry Andric
28405ffd83dbSDimitry Andric ~VPWidenCanonicalIVRecipe() override = default;
28415ffd83dbSDimitry Andric
clone()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:
VPDerivedIVRecipe(const InductionDescriptor & IndDesc,VPValue * Start,VPCanonicalIVPHIRecipe * CanonicalIV,VPValue * Step)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
VPDerivedIVRecipe(InductionDescriptor::InductionKind Kind,const FPMathOperator * FPBinOp,VPValue * Start,VPValue * IV,VPValue * Step)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
clone()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
getScalarType()29045f757f3fSDimitry Andric Type *getScalarType() const {
2905*0fca6ea1SDimitry Andric return getStartValue()->getLiveInIRValue()->getType();
29065f757f3fSDimitry Andric }
29075f757f3fSDimitry Andric
getStartValue()2908bdd1243dSDimitry Andric VPValue *getStartValue() const { return getOperand(0); }
getStepValue()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.
onlyFirstLaneUsed(const VPValue * 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:
VPScalarIVStepsRecipe(VPValue * IV,VPValue * Step,Instruction::BinaryOps Opcode,FastMathFlags FMFs)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
VPScalarIVStepsRecipe(const InductionDescriptor & IndDesc,VPValue * IV,VPValue * Step)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
clone()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
getStepValue()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.
onlyFirstLaneUsed(const VPValue * 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
~VPBasicBlock()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 ///
begin()30030b57cec5SDimitry Andric inline iterator begin() { return Recipes.begin(); }
begin()30040b57cec5SDimitry Andric inline const_iterator begin() const { return Recipes.begin(); }
end()30050b57cec5SDimitry Andric inline iterator end() { return Recipes.end(); }
end()30060b57cec5SDimitry Andric inline const_iterator end() const { return Recipes.end(); }
30070b57cec5SDimitry Andric
rbegin()30080b57cec5SDimitry Andric inline reverse_iterator rbegin() { return Recipes.rbegin(); }
rbegin()30090b57cec5SDimitry Andric inline const_reverse_iterator rbegin() const { return Recipes.rbegin(); }
rend()30100b57cec5SDimitry Andric inline reverse_iterator rend() { return Recipes.rend(); }
rend()30110b57cec5SDimitry Andric inline const_reverse_iterator rend() const { return Recipes.rend(); }
30120b57cec5SDimitry Andric
size()30130b57cec5SDimitry Andric inline size_t size() const { return Recipes.size(); }
empty()30140b57cec5SDimitry Andric inline bool empty() const { return Recipes.empty(); }
front()30150b57cec5SDimitry Andric inline const VPRecipeBase &front() const { return Recipes.front(); }
front()30160b57cec5SDimitry Andric inline VPRecipeBase &front() { return Recipes.front(); }
back()30170b57cec5SDimitry Andric inline const VPRecipeBase &back() const { return Recipes.back(); }
back()30180b57cec5SDimitry Andric inline VPRecipeBase &back() { return Recipes.back(); }
30190b57cec5SDimitry Andric
30200b57cec5SDimitry Andric /// Returns a reference to the list of recipes.
getRecipeList()30210b57cec5SDimitry Andric RecipeListTy &getRecipeList() { return Recipes; }
30220b57cec5SDimitry Andric
30230b57cec5SDimitry Andric /// Returns a pointer to a member of the recipe list.
getSublistAccess(VPRecipeBase *)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.
classof(const VPBlockBase * V)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
insert(VPRecipeBase * Recipe,iterator InsertPt)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.
appendRecipe(VPRecipeBase * 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.
phis()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.
clone()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:
VPIRBasicBlock(BasicBlock * IRBB)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
~VPIRBasicBlock()3121*0fca6ea1SDimitry Andric ~VPIRBasicBlock() override {}
3122*0fca6ea1SDimitry Andric
classof(const VPBlockBase * V)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
clone()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
getIRBasicBlock()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)
VPBlockBase(VPRegionBlockSC,Name)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)
VPBlockBase(VPRegionBlockSC,Name)317281ad6265SDimitry Andric : VPBlockBase(VPRegionBlockSC, Name), Entry(nullptr), Exiting(nullptr),
31730b57cec5SDimitry Andric IsReplicator(IsReplicator) {}
31740b57cec5SDimitry Andric
~VPRegionBlock()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.
classof(const VPBlockBase * V)31840b57cec5SDimitry Andric static inline bool classof(const VPBlockBase *V) {
31850b57cec5SDimitry Andric return V->getVPBlockID() == VPBlockBase::VPRegionBlockSC;
31860b57cec5SDimitry Andric }
31870b57cec5SDimitry Andric
getEntry()31880b57cec5SDimitry Andric const VPBlockBase *getEntry() const { return Entry; }
getEntry()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.
setEntry(VPBlockBase * EntryBlock)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
getExiting()320081ad6265SDimitry Andric const VPBlockBase *getExiting() const { return Exiting; }
getExiting()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.
setExiting(VPBlockBase * ExitingBlock)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.
getPreheaderVPBB()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.
isReplicator()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.
VPlan(VPBasicBlock * Preheader,VPValue * TC,VPBasicBlock * Entry)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.
VPlan(VPBasicBlock * Preheader,VPBasicBlock * Entry)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
getEntry()335506c3fb27SDimitry Andric VPBasicBlock *getEntry() { return Entry; }
getEntry()335606c3fb27SDimitry Andric const VPBasicBlock *getEntry() const { return Entry; }
3357480093f4SDimitry Andric
335804eeddc0SDimitry Andric /// The trip count of the original loop.
getTripCount()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.
resetTripCount(VPValue * NewTripCount)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.
getOrCreateBackedgeTakenCount()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.
getVectorTripCount()338004eeddc0SDimitry Andric VPValue &getVectorTripCount() { return VectorTripCount; }
338104eeddc0SDimitry Andric
33825f757f3fSDimitry Andric /// Returns VF * UF of the vector loop region.
getVFxUF()33835f757f3fSDimitry Andric VPValue &getVFxUF() { return VFxUF; }
33845f757f3fSDimitry Andric
addVF(ElementCount VF)3385e8d8bef9SDimitry Andric void addVF(ElementCount VF) { VFs.insert(VF); }
3386480093f4SDimitry Andric
setVF(ElementCount VF)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
hasVF(ElementCount VF)3393e8d8bef9SDimitry Andric bool hasVF(ElementCount VF) { return VFs.count(VF); }
hasScalableVF()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>
vectorFactors()3400*0fca6ea1SDimitry Andric vectorFactors() const {
3401*0fca6ea1SDimitry Andric return {VFs.begin(), VFs.end()};
3402*0fca6ea1SDimitry Andric }
3403480093f4SDimitry Andric
hasScalarVFOnly()3404bdd1243dSDimitry Andric bool hasScalarVFOnly() const { return VFs.size() == 1 && VFs[0].isScalar(); }
3405bdd1243dSDimitry Andric
hasUF(unsigned UF)3406bdd1243dSDimitry Andric bool hasUF(unsigned UF) const { return UFs.empty() || UFs.contains(UF); }
3407bdd1243dSDimitry Andric
setUF(unsigned UF)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
setName(const Twine & newName)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.
getOrAddLiveIn(Value * 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.
getLiveIn(Value * V)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.
getVectorLoopRegion()345504eeddc0SDimitry Andric VPRegionBlock *getVectorLoopRegion() {
345681ad6265SDimitry Andric return cast<VPRegionBlock>(getEntry()->getSingleSuccessor());
345781ad6265SDimitry Andric }
getVectorLoopRegion()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.
getCanonicalIV()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
removeLiveOut(PHINode * PN)347481ad6265SDimitry Andric void removeLiveOut(PHINode *PN) {
347581ad6265SDimitry Andric delete LiveOuts[PN];
347681ad6265SDimitry Andric LiveOuts.erase(PN);
347781ad6265SDimitry Andric }
347881ad6265SDimitry Andric
getLiveOuts()347981ad6265SDimitry Andric const MapVector<PHINode *, VPLiveOut *> &getLiveOuts() const {
348081ad6265SDimitry Andric return LiveOuts;
348181ad6265SDimitry Andric }
348281ad6265SDimitry Andric
getSCEVExpansion(const SCEV * S)348306c3fb27SDimitry Andric VPValue *getSCEVExpansion(const SCEV *S) const {
348406c3fb27SDimitry Andric return SCEVToExpansion.lookup(S);
348506c3fb27SDimitry Andric }
348606c3fb27SDimitry Andric
addSCEVExpansion(const SCEV * S,VPValue * V)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.
getPreheader()349306c3fb27SDimitry Andric VPBasicBlock *getPreheader() { return Preheader; }
getPreheader()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.
bumpIndent(int b)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
getOrCreateBID(const VPBlockBase * Block)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:
VPlanPrinter(raw_ostream & O,const VPlan & P)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
VPlanIngredientVPlanIngredient3554e8d8bef9SDimitry 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.
insertBlockAfter(VPBlockBase * NewBlock,VPBlockBase * BlockPtr)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.
insertTwoBlocksAfter(VPBlockBase * IfTrue,VPBlockBase * IfFalse,VPBlockBase * BlockPtr)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.
connectBlocks(VPBlockBase * From,VPBlockBase * To)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.
disconnectBlocks(VPBlockBase * From,VPBlockBase * 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>
blocksOnly(const T & Range)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
~VPInterleavedAccessInfo()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> *
getInterleaveGroup(VPInstruction * Instr)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 {
getEmptyKeyBundleDenseMapInfo37040b57cec5SDimitry Andric static SmallVector<VPValue *, 4> getEmptyKey() {
37050b57cec5SDimitry Andric return {reinterpret_cast<VPValue *>(-1)};
37060b57cec5SDimitry Andric }
37070b57cec5SDimitry Andric
getTombstoneKeyBundleDenseMapInfo37080b57cec5SDimitry Andric static SmallVector<VPValue *, 4> getTombstoneKey() {
37090b57cec5SDimitry Andric return {reinterpret_cast<VPValue *>(-2)};
37100b57cec5SDimitry Andric }
37110b57cec5SDimitry Andric
getHashValueBundleDenseMapInfo37120b57cec5SDimitry 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
isEqualBundleDenseMapInfo37160b57cec5SDimitry 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:
VPlanSlp(VPInterleavedAccessInfo & IAI,VPBasicBlock & BB)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.
getWidestBundleBits()37850b57cec5SDimitry Andric unsigned getWidestBundleBits() const { return WidestBundleBits; }
37860b57cec5SDimitry Andric
37870b57cec5SDimitry Andric /// Return true if all visited instruction can be combined.
isCompletelySLP()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.
isUniformAfterVectorization(VPValue * VPV)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