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