1*700637cbSDimitry Andric //===- VPlanUtils.h - VPlan-related utilities -------------------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric
9*700637cbSDimitry Andric #ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANUTILS_H
10*700637cbSDimitry Andric #define LLVM_TRANSFORMS_VECTORIZE_VPLANUTILS_H
11*700637cbSDimitry Andric
12*700637cbSDimitry Andric #include "VPlan.h"
13*700637cbSDimitry Andric
14*700637cbSDimitry Andric namespace llvm {
15*700637cbSDimitry Andric class ScalarEvolution;
16*700637cbSDimitry Andric class SCEV;
17*700637cbSDimitry Andric } // namespace llvm
18*700637cbSDimitry Andric
19*700637cbSDimitry Andric namespace llvm {
20*700637cbSDimitry Andric
21*700637cbSDimitry Andric namespace vputils {
22*700637cbSDimitry Andric /// Returns true if only the first lane of \p Def is used.
23*700637cbSDimitry Andric bool onlyFirstLaneUsed(const VPValue *Def);
24*700637cbSDimitry Andric
25*700637cbSDimitry Andric /// Returns true if only the first part of \p Def is used.
26*700637cbSDimitry Andric bool onlyFirstPartUsed(const VPValue *Def);
27*700637cbSDimitry Andric
28*700637cbSDimitry Andric /// Get or create a VPValue that corresponds to the expansion of \p Expr. If \p
29*700637cbSDimitry Andric /// Expr is a SCEVConstant or SCEVUnknown, return a VPValue wrapping the live-in
30*700637cbSDimitry Andric /// value. Otherwise return a VPExpandSCEVRecipe to expand \p Expr. If \p Plan's
31*700637cbSDimitry Andric /// pre-header already contains a recipe expanding \p Expr, return it. If not,
32*700637cbSDimitry Andric /// create a new one.
33*700637cbSDimitry Andric VPValue *getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr,
34*700637cbSDimitry Andric ScalarEvolution &SE);
35*700637cbSDimitry Andric
36*700637cbSDimitry Andric /// Return the SCEV expression for \p V. Returns SCEVCouldNotCompute if no
37*700637cbSDimitry Andric /// SCEV expression could be constructed.
38*700637cbSDimitry Andric const SCEV *getSCEVExprForVPValue(VPValue *V, ScalarEvolution &SE);
39*700637cbSDimitry Andric
40*700637cbSDimitry Andric /// Returns true if \p VPV is a single scalar, either because it produces the
41*700637cbSDimitry Andric /// same value for all lanes or only has its first lane used.
isSingleScalar(const VPValue * VPV)42*700637cbSDimitry Andric inline bool isSingleScalar(const VPValue *VPV) {
43*700637cbSDimitry Andric auto PreservesUniformity = [](unsigned Opcode) -> bool {
44*700637cbSDimitry Andric if (Instruction::isBinaryOp(Opcode) || Instruction::isCast(Opcode))
45*700637cbSDimitry Andric return true;
46*700637cbSDimitry Andric switch (Opcode) {
47*700637cbSDimitry Andric case Instruction::GetElementPtr:
48*700637cbSDimitry Andric case Instruction::ICmp:
49*700637cbSDimitry Andric case Instruction::FCmp:
50*700637cbSDimitry Andric case VPInstruction::Broadcast:
51*700637cbSDimitry Andric case VPInstruction::PtrAdd:
52*700637cbSDimitry Andric return true;
53*700637cbSDimitry Andric default:
54*700637cbSDimitry Andric return false;
55*700637cbSDimitry Andric }
56*700637cbSDimitry Andric };
57*700637cbSDimitry Andric
58*700637cbSDimitry Andric // A live-in must be uniform across the scope of VPlan.
59*700637cbSDimitry Andric if (VPV->isLiveIn())
60*700637cbSDimitry Andric return true;
61*700637cbSDimitry Andric
62*700637cbSDimitry Andric if (auto *Rep = dyn_cast<VPReplicateRecipe>(VPV)) {
63*700637cbSDimitry Andric const VPRegionBlock *RegionOfR = Rep->getParent()->getParent();
64*700637cbSDimitry Andric // Don't consider recipes in replicate regions as uniform yet; their first
65*700637cbSDimitry Andric // lane cannot be accessed when executing the replicate region for other
66*700637cbSDimitry Andric // lanes.
67*700637cbSDimitry Andric if (RegionOfR && RegionOfR->isReplicator())
68*700637cbSDimitry Andric return false;
69*700637cbSDimitry Andric return Rep->isSingleScalar() || (PreservesUniformity(Rep->getOpcode()) &&
70*700637cbSDimitry Andric all_of(Rep->operands(), isSingleScalar));
71*700637cbSDimitry Andric }
72*700637cbSDimitry Andric if (isa<VPWidenGEPRecipe, VPDerivedIVRecipe, VPBlendRecipe,
73*700637cbSDimitry Andric VPWidenSelectRecipe>(VPV))
74*700637cbSDimitry Andric return all_of(VPV->getDefiningRecipe()->operands(), isSingleScalar);
75*700637cbSDimitry Andric if (auto *WidenR = dyn_cast<VPWidenRecipe>(VPV)) {
76*700637cbSDimitry Andric return PreservesUniformity(WidenR->getOpcode()) &&
77*700637cbSDimitry Andric all_of(WidenR->operands(), isSingleScalar);
78*700637cbSDimitry Andric }
79*700637cbSDimitry Andric if (auto *VPI = dyn_cast<VPInstruction>(VPV))
80*700637cbSDimitry Andric return VPI->isSingleScalar() || VPI->isVectorToScalar() ||
81*700637cbSDimitry Andric (PreservesUniformity(VPI->getOpcode()) &&
82*700637cbSDimitry Andric all_of(VPI->operands(), isSingleScalar));
83*700637cbSDimitry Andric
84*700637cbSDimitry Andric // VPExpandSCEVRecipes must be placed in the entry and are alway uniform.
85*700637cbSDimitry Andric return isa<VPExpandSCEVRecipe>(VPV);
86*700637cbSDimitry Andric }
87*700637cbSDimitry Andric
88*700637cbSDimitry Andric /// Return true if \p V is a header mask in \p Plan.
89*700637cbSDimitry Andric bool isHeaderMask(const VPValue *V, VPlan &Plan);
90*700637cbSDimitry Andric
91*700637cbSDimitry Andric /// Checks if \p V is uniform across all VF lanes and UF parts. It is considered
92*700637cbSDimitry Andric /// as such if it is either loop invariant (defined outside the vector region)
93*700637cbSDimitry Andric /// or its operand is known to be uniform across all VFs and UFs (e.g.
94*700637cbSDimitry Andric /// VPDerivedIV or VPCanonicalIVPHI).
95*700637cbSDimitry Andric bool isUniformAcrossVFsAndUFs(VPValue *V);
96*700637cbSDimitry Andric
97*700637cbSDimitry Andric /// Returns the header block of the first, top-level loop, or null if none
98*700637cbSDimitry Andric /// exist.
99*700637cbSDimitry Andric VPBasicBlock *getFirstLoopHeader(VPlan &Plan, VPDominatorTree &VPDT);
100*700637cbSDimitry Andric } // namespace vputils
101*700637cbSDimitry Andric
102*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
103*700637cbSDimitry Andric // Utilities for modifying predecessors and successors of VPlan blocks.
104*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
105*700637cbSDimitry Andric
106*700637cbSDimitry Andric /// Class that provides utilities for VPBlockBases in VPlan.
107*700637cbSDimitry Andric class VPBlockUtils {
108*700637cbSDimitry Andric public:
109*700637cbSDimitry Andric VPBlockUtils() = delete;
110*700637cbSDimitry Andric
111*700637cbSDimitry Andric /// Insert disconnected VPBlockBase \p NewBlock after \p BlockPtr. Add \p
112*700637cbSDimitry Andric /// NewBlock as successor of \p BlockPtr and \p BlockPtr as predecessor of \p
113*700637cbSDimitry Andric /// NewBlock, and propagate \p BlockPtr parent to \p NewBlock. \p BlockPtr's
114*700637cbSDimitry Andric /// successors are moved from \p BlockPtr to \p NewBlock. \p NewBlock must
115*700637cbSDimitry Andric /// have neither successors nor predecessors.
insertBlockAfter(VPBlockBase * NewBlock,VPBlockBase * BlockPtr)116*700637cbSDimitry Andric static void insertBlockAfter(VPBlockBase *NewBlock, VPBlockBase *BlockPtr) {
117*700637cbSDimitry Andric assert(NewBlock->getSuccessors().empty() &&
118*700637cbSDimitry Andric NewBlock->getPredecessors().empty() &&
119*700637cbSDimitry Andric "Can't insert new block with predecessors or successors.");
120*700637cbSDimitry Andric NewBlock->setParent(BlockPtr->getParent());
121*700637cbSDimitry Andric SmallVector<VPBlockBase *> Succs(BlockPtr->successors());
122*700637cbSDimitry Andric for (VPBlockBase *Succ : Succs) {
123*700637cbSDimitry Andric Succ->replacePredecessor(BlockPtr, NewBlock);
124*700637cbSDimitry Andric NewBlock->appendSuccessor(Succ);
125*700637cbSDimitry Andric }
126*700637cbSDimitry Andric BlockPtr->clearSuccessors();
127*700637cbSDimitry Andric connectBlocks(BlockPtr, NewBlock);
128*700637cbSDimitry Andric }
129*700637cbSDimitry Andric
130*700637cbSDimitry Andric /// Insert disconnected block \p NewBlock before \p Blockptr. First
131*700637cbSDimitry Andric /// disconnects all predecessors of \p BlockPtr and connects them to \p
132*700637cbSDimitry Andric /// NewBlock. Add \p NewBlock as predecessor of \p BlockPtr and \p BlockPtr as
133*700637cbSDimitry Andric /// successor of \p NewBlock.
insertBlockBefore(VPBlockBase * NewBlock,VPBlockBase * BlockPtr)134*700637cbSDimitry Andric static void insertBlockBefore(VPBlockBase *NewBlock, VPBlockBase *BlockPtr) {
135*700637cbSDimitry Andric assert(NewBlock->getSuccessors().empty() &&
136*700637cbSDimitry Andric NewBlock->getPredecessors().empty() &&
137*700637cbSDimitry Andric "Can't insert new block with predecessors or successors.");
138*700637cbSDimitry Andric NewBlock->setParent(BlockPtr->getParent());
139*700637cbSDimitry Andric for (VPBlockBase *Pred : to_vector(BlockPtr->predecessors())) {
140*700637cbSDimitry Andric Pred->replaceSuccessor(BlockPtr, NewBlock);
141*700637cbSDimitry Andric NewBlock->appendPredecessor(Pred);
142*700637cbSDimitry Andric }
143*700637cbSDimitry Andric BlockPtr->clearPredecessors();
144*700637cbSDimitry Andric connectBlocks(NewBlock, BlockPtr);
145*700637cbSDimitry Andric }
146*700637cbSDimitry Andric
147*700637cbSDimitry Andric /// Insert disconnected VPBlockBases \p IfTrue and \p IfFalse after \p
148*700637cbSDimitry Andric /// BlockPtr. Add \p IfTrue and \p IfFalse as succesors of \p BlockPtr and \p
149*700637cbSDimitry Andric /// BlockPtr as predecessor of \p IfTrue and \p IfFalse. Propagate \p BlockPtr
150*700637cbSDimitry Andric /// parent to \p IfTrue and \p IfFalse. \p BlockPtr must have no successors
151*700637cbSDimitry Andric /// and \p IfTrue and \p IfFalse must have neither successors nor
152*700637cbSDimitry Andric /// predecessors.
insertTwoBlocksAfter(VPBlockBase * IfTrue,VPBlockBase * IfFalse,VPBlockBase * BlockPtr)153*700637cbSDimitry Andric static void insertTwoBlocksAfter(VPBlockBase *IfTrue, VPBlockBase *IfFalse,
154*700637cbSDimitry Andric VPBlockBase *BlockPtr) {
155*700637cbSDimitry Andric assert(IfTrue->getSuccessors().empty() &&
156*700637cbSDimitry Andric "Can't insert IfTrue with successors.");
157*700637cbSDimitry Andric assert(IfFalse->getSuccessors().empty() &&
158*700637cbSDimitry Andric "Can't insert IfFalse with successors.");
159*700637cbSDimitry Andric BlockPtr->setTwoSuccessors(IfTrue, IfFalse);
160*700637cbSDimitry Andric IfTrue->setPredecessors({BlockPtr});
161*700637cbSDimitry Andric IfFalse->setPredecessors({BlockPtr});
162*700637cbSDimitry Andric IfTrue->setParent(BlockPtr->getParent());
163*700637cbSDimitry Andric IfFalse->setParent(BlockPtr->getParent());
164*700637cbSDimitry Andric }
165*700637cbSDimitry Andric
166*700637cbSDimitry Andric /// Connect VPBlockBases \p From and \p To bi-directionally. If \p PredIdx is
167*700637cbSDimitry Andric /// -1, append \p From to the predecessors of \p To, otherwise set \p To's
168*700637cbSDimitry Andric /// predecessor at \p PredIdx to \p From. If \p SuccIdx is -1, append \p To to
169*700637cbSDimitry Andric /// the successors of \p From, otherwise set \p From's successor at \p SuccIdx
170*700637cbSDimitry Andric /// to \p To. Both VPBlockBases must have the same parent, which can be null.
171*700637cbSDimitry Andric /// Both VPBlockBases can be already connected to other VPBlockBases.
172*700637cbSDimitry Andric static void connectBlocks(VPBlockBase *From, VPBlockBase *To,
173*700637cbSDimitry Andric unsigned PredIdx = -1u, unsigned SuccIdx = -1u) {
174*700637cbSDimitry Andric assert((From->getParent() == To->getParent()) &&
175*700637cbSDimitry Andric "Can't connect two block with different parents");
176*700637cbSDimitry Andric assert((SuccIdx != -1u || From->getNumSuccessors() < 2) &&
177*700637cbSDimitry Andric "Blocks can't have more than two successors.");
178*700637cbSDimitry Andric if (SuccIdx == -1u)
179*700637cbSDimitry Andric From->appendSuccessor(To);
180*700637cbSDimitry Andric else
181*700637cbSDimitry Andric From->getSuccessors()[SuccIdx] = To;
182*700637cbSDimitry Andric
183*700637cbSDimitry Andric if (PredIdx == -1u)
184*700637cbSDimitry Andric To->appendPredecessor(From);
185*700637cbSDimitry Andric else
186*700637cbSDimitry Andric To->getPredecessors()[PredIdx] = From;
187*700637cbSDimitry Andric }
188*700637cbSDimitry Andric
189*700637cbSDimitry Andric /// Disconnect VPBlockBases \p From and \p To bi-directionally. Remove \p To
190*700637cbSDimitry Andric /// from the successors of \p From and \p From from the predecessors of \p To.
disconnectBlocks(VPBlockBase * From,VPBlockBase * To)191*700637cbSDimitry Andric static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To) {
192*700637cbSDimitry Andric assert(To && "Successor to disconnect is null.");
193*700637cbSDimitry Andric From->removeSuccessor(To);
194*700637cbSDimitry Andric To->removePredecessor(From);
195*700637cbSDimitry Andric }
196*700637cbSDimitry Andric
197*700637cbSDimitry Andric /// Reassociate all the blocks connected to \p Old so that they now point to
198*700637cbSDimitry Andric /// \p New.
reassociateBlocks(VPBlockBase * Old,VPBlockBase * New)199*700637cbSDimitry Andric static void reassociateBlocks(VPBlockBase *Old, VPBlockBase *New) {
200*700637cbSDimitry Andric for (auto *Pred : to_vector(Old->getPredecessors()))
201*700637cbSDimitry Andric Pred->replaceSuccessor(Old, New);
202*700637cbSDimitry Andric for (auto *Succ : to_vector(Old->getSuccessors()))
203*700637cbSDimitry Andric Succ->replacePredecessor(Old, New);
204*700637cbSDimitry Andric New->setPredecessors(Old->getPredecessors());
205*700637cbSDimitry Andric New->setSuccessors(Old->getSuccessors());
206*700637cbSDimitry Andric Old->clearPredecessors();
207*700637cbSDimitry Andric Old->clearSuccessors();
208*700637cbSDimitry Andric }
209*700637cbSDimitry Andric
210*700637cbSDimitry Andric /// Return an iterator range over \p Range which only includes \p BlockTy
211*700637cbSDimitry Andric /// blocks. The accesses are casted to \p BlockTy.
212*700637cbSDimitry Andric template <typename BlockTy, typename T>
blocksOnly(const T & Range)213*700637cbSDimitry Andric static auto blocksOnly(const T &Range) {
214*700637cbSDimitry Andric // Create BaseTy with correct const-ness based on BlockTy.
215*700637cbSDimitry Andric using BaseTy = std::conditional_t<std::is_const<BlockTy>::value,
216*700637cbSDimitry Andric const VPBlockBase, VPBlockBase>;
217*700637cbSDimitry Andric
218*700637cbSDimitry Andric // We need to first create an iterator range over (const) BlocktTy & instead
219*700637cbSDimitry Andric // of (const) BlockTy * for filter_range to work properly.
220*700637cbSDimitry Andric auto Mapped =
221*700637cbSDimitry Andric map_range(Range, [](BaseTy *Block) -> BaseTy & { return *Block; });
222*700637cbSDimitry Andric auto Filter = make_filter_range(
223*700637cbSDimitry Andric Mapped, [](BaseTy &Block) { return isa<BlockTy>(&Block); });
224*700637cbSDimitry Andric return map_range(Filter, [](BaseTy &Block) -> BlockTy * {
225*700637cbSDimitry Andric return cast<BlockTy>(&Block);
226*700637cbSDimitry Andric });
227*700637cbSDimitry Andric }
228*700637cbSDimitry Andric
229*700637cbSDimitry Andric /// Inserts \p BlockPtr on the edge between \p From and \p To. That is, update
230*700637cbSDimitry Andric /// \p From's successor to \p To to point to \p BlockPtr and \p To's
231*700637cbSDimitry Andric /// predecessor from \p From to \p BlockPtr. \p From and \p To are added to \p
232*700637cbSDimitry Andric /// BlockPtr's predecessors and successors respectively. There must be a
233*700637cbSDimitry Andric /// single edge between \p From and \p To.
insertOnEdge(VPBlockBase * From,VPBlockBase * To,VPBlockBase * BlockPtr)234*700637cbSDimitry Andric static void insertOnEdge(VPBlockBase *From, VPBlockBase *To,
235*700637cbSDimitry Andric VPBlockBase *BlockPtr) {
236*700637cbSDimitry Andric unsigned SuccIdx = From->getIndexForSuccessor(To);
237*700637cbSDimitry Andric unsigned PredIx = To->getIndexForPredecessor(From);
238*700637cbSDimitry Andric VPBlockUtils::connectBlocks(From, BlockPtr, -1, SuccIdx);
239*700637cbSDimitry Andric VPBlockUtils::connectBlocks(BlockPtr, To, PredIx, -1);
240*700637cbSDimitry Andric }
241*700637cbSDimitry Andric
242*700637cbSDimitry Andric /// Returns true if \p VPB is a loop header, based on regions or \p VPDT in
243*700637cbSDimitry Andric /// their absence.
244*700637cbSDimitry Andric static bool isHeader(const VPBlockBase *VPB, const VPDominatorTree &VPDT);
245*700637cbSDimitry Andric
246*700637cbSDimitry Andric /// Returns true if \p VPB is a loop latch, using isHeader().
247*700637cbSDimitry Andric static bool isLatch(const VPBlockBase *VPB, const VPDominatorTree &VPDT);
248*700637cbSDimitry Andric };
249*700637cbSDimitry Andric
250*700637cbSDimitry Andric } // namespace llvm
251*700637cbSDimitry Andric
252*700637cbSDimitry Andric #endif
253