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