Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //=- IslNodeBuilder.cpp - Translate an isl AST into a LLVM-IR AST -*- 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 | // This file contains the IslNodeBuilder, a class to translate an isl AST into |
||
10 | // a LLVM-IR AST. |
||
11 | // |
||
12 | //===----------------------------------------------------------------------===// |
||
13 | |||
14 | #ifndef POLLY_ISLNODEBUILDER_H |
||
15 | #define POLLY_ISLNODEBUILDER_H |
||
16 | |||
17 | #include "polly/CodeGen/BlockGenerators.h" |
||
18 | #include "polly/CodeGen/IslExprBuilder.h" |
||
19 | #include "polly/ScopDetectionDiagnostic.h" |
||
20 | #include "llvm/ADT/ArrayRef.h" |
||
21 | #include "llvm/ADT/SmallSet.h" |
||
22 | #include "llvm/IR/InstrTypes.h" |
||
23 | #include "isl/ctx.h" |
||
24 | #include "isl/isl-noexceptions.h" |
||
25 | |||
26 | namespace polly { |
||
27 | using llvm::LoopInfo; |
||
28 | using llvm::SmallSet; |
||
29 | |||
30 | struct InvariantEquivClassTy; |
||
31 | |||
32 | struct SubtreeReferences { |
||
33 | LoopInfo &LI; |
||
34 | ScalarEvolution &SE; |
||
35 | Scop &S; |
||
36 | ValueMapT &GlobalMap; |
||
37 | SetVector<Value *> &Values; |
||
38 | SetVector<const SCEV *> &SCEVs; |
||
39 | BlockGenerator &BlockGen; |
||
40 | // In case an (optional) parameter space location is provided, parameter space |
||
41 | // information is collected as well. |
||
42 | isl::space *ParamSpace; |
||
43 | }; |
||
44 | |||
45 | /// Extract the out-of-scop values and SCEVs referenced from a ScopStmt. |
||
46 | /// |
||
47 | /// This includes the SCEVUnknowns referenced by the SCEVs used in the |
||
48 | /// statement and the base pointers of the memory accesses. For scalar |
||
49 | /// statements we force the generation of alloca memory locations and list |
||
50 | /// these locations in the set of out-of-scop values as well. |
||
51 | /// |
||
52 | /// We also collect an isl::space that includes all parameter dimensions |
||
53 | /// used in the statement's memory accesses, in case the ParamSpace pointer |
||
54 | /// is non-null. |
||
55 | /// |
||
56 | /// @param Stmt The statement for which to extract the information. |
||
57 | /// @param UserPtr A void pointer that can be casted to a |
||
58 | /// SubtreeReferences structure. |
||
59 | /// @param CreateScalarRefs Should the result include allocas of scalar |
||
60 | /// references? |
||
61 | void addReferencesFromStmt(ScopStmt *Stmt, void *UserPtr, |
||
62 | bool CreateScalarRefs = true); |
||
63 | |||
64 | class IslNodeBuilder { |
||
65 | public: |
||
66 | IslNodeBuilder(PollyIRBuilder &Builder, ScopAnnotator &Annotator, |
||
67 | const DataLayout &DL, LoopInfo &LI, ScalarEvolution &SE, |
||
68 | DominatorTree &DT, Scop &S, BasicBlock *StartBlock) |
||
69 | : S(S), Builder(Builder), Annotator(Annotator), |
||
70 | ExprBuilder(S, Builder, IDToValue, ValueMap, DL, SE, DT, LI, |
||
71 | StartBlock), |
||
72 | BlockGen(Builder, LI, SE, DT, ScalarMap, EscapeMap, ValueMap, |
||
73 | &ExprBuilder, StartBlock), |
||
74 | RegionGen(BlockGen), DL(DL), LI(LI), SE(SE), DT(DT), |
||
75 | StartBlock(StartBlock) {} |
||
76 | |||
77 | virtual ~IslNodeBuilder() = default; |
||
78 | |||
79 | void addParameters(__isl_take isl_set *Context); |
||
80 | |||
81 | /// Generate code that evaluates @p Condition at run-time. |
||
82 | /// |
||
83 | /// This function is typically called to generate the LLVM-IR for the |
||
84 | /// run-time condition of the scop, that verifies that all the optimistic |
||
85 | /// assumptions we have taken during scop modeling and transformation |
||
86 | /// hold at run-time. |
||
87 | /// |
||
88 | /// @param Condition The condition to evaluate |
||
89 | /// |
||
90 | /// @result An llvm::Value that is true if the condition holds and false |
||
91 | /// otherwise. |
||
92 | Value *createRTC(isl_ast_expr *Condition); |
||
93 | |||
94 | void create(__isl_take isl_ast_node *Node); |
||
95 | |||
96 | /// Allocate memory for all new arrays created by Polly. |
||
97 | void allocateNewArrays(BBPair StartExitBlocks); |
||
98 | |||
99 | /// Preload all memory loads that are invariant. |
||
100 | bool preloadInvariantLoads(); |
||
101 | |||
102 | /// Finalize code generation. |
||
103 | /// |
||
104 | /// @see BlockGenerator::finalizeSCoP(Scop &S) |
||
105 | virtual void finalize() { BlockGen.finalizeSCoP(S); } |
||
106 | |||
107 | IslExprBuilder &getExprBuilder() { return ExprBuilder; } |
||
108 | |||
109 | /// Get the associated block generator. |
||
110 | /// |
||
111 | /// @return A reference to the associated block generator. |
||
112 | BlockGenerator &getBlockGenerator() { return BlockGen; } |
||
113 | |||
114 | /// Return the parallel subfunctions that have been created. |
||
115 | const ArrayRef<Function *> getParallelSubfunctions() const { |
||
116 | return ParallelSubfunctions; |
||
117 | } |
||
118 | |||
119 | protected: |
||
120 | Scop &S; |
||
121 | PollyIRBuilder &Builder; |
||
122 | ScopAnnotator &Annotator; |
||
123 | |||
124 | IslExprBuilder ExprBuilder; |
||
125 | |||
126 | /// Maps used by the block and region generator to demote scalars. |
||
127 | /// |
||
128 | ///@{ |
||
129 | |||
130 | /// See BlockGenerator::ScalarMap. |
||
131 | BlockGenerator::AllocaMapTy ScalarMap; |
||
132 | |||
133 | /// See BlockGenerator::EscapeMap. |
||
134 | BlockGenerator::EscapeUsersAllocaMapTy EscapeMap; |
||
135 | |||
136 | ///@} |
||
137 | |||
138 | /// The generator used to copy a basic block. |
||
139 | BlockGenerator BlockGen; |
||
140 | |||
141 | /// The generator used to copy a non-affine region. |
||
142 | RegionGenerator RegionGen; |
||
143 | |||
144 | const DataLayout &DL; |
||
145 | LoopInfo &LI; |
||
146 | ScalarEvolution &SE; |
||
147 | DominatorTree &DT; |
||
148 | BasicBlock *StartBlock; |
||
149 | |||
150 | /// The current iteration of out-of-scop loops |
||
151 | /// |
||
152 | /// This map provides for a given loop a llvm::Value that contains the current |
||
153 | /// loop iteration. |
||
154 | MapVector<const Loop *, const SCEV *> OutsideLoopIterations; |
||
155 | |||
156 | // This maps an isl_id* to the Value* it has in the generated program. For now |
||
157 | // on, the only isl_ids that are stored here are the newly calculated loop |
||
158 | // ivs. |
||
159 | IslExprBuilder::IDToValueTy IDToValue; |
||
160 | |||
161 | /// A collection of all parallel subfunctions that have been created. |
||
162 | SmallVector<Function *, 8> ParallelSubfunctions; |
||
163 | |||
164 | /// Generate code for a given SCEV* |
||
165 | /// |
||
166 | /// This function generates code for a given SCEV expression. It generated |
||
167 | /// code is emitted at the end of the basic block our Builder currently |
||
168 | /// points to and the resulting value is returned. |
||
169 | /// |
||
170 | /// @param Expr The expression to code generate. |
||
171 | Value *generateSCEV(const SCEV *Expr); |
||
172 | |||
173 | /// A set of Value -> Value remappings to apply when generating new code. |
||
174 | /// |
||
175 | /// When generating new code for a ScopStmt this map is used to map certain |
||
176 | /// llvm::Values to new llvm::Values. |
||
177 | ValueMapT ValueMap; |
||
178 | |||
179 | /// Materialize code for @p Id if it was not done before. |
||
180 | /// |
||
181 | /// @returns False, iff a problem occurred and the value was not materialized. |
||
182 | bool materializeValue(__isl_take isl_id *Id); |
||
183 | |||
184 | /// Materialize parameters of @p Set. |
||
185 | /// |
||
186 | /// @returns False, iff a problem occurred and the value was not materialized. |
||
187 | bool materializeParameters(__isl_take isl_set *Set); |
||
188 | |||
189 | /// Materialize all parameters in the current scop. |
||
190 | /// |
||
191 | /// @returns False, iff a problem occurred and the value was not materialized. |
||
192 | bool materializeParameters(); |
||
193 | |||
194 | // Extract the upper bound of this loop |
||
195 | // |
||
196 | // The isl code generation can generate arbitrary expressions to check if the |
||
197 | // upper bound of a loop is reached, but it provides an option to enforce |
||
198 | // 'atomic' upper bounds. An 'atomic upper bound is always of the form |
||
199 | // iv <= expr, where expr is an (arbitrary) expression not containing iv. |
||
200 | // |
||
201 | // This function extracts 'atomic' upper bounds. Polly, in general, requires |
||
202 | // atomic upper bounds for the following reasons: |
||
203 | // |
||
204 | // 1. An atomic upper bound is loop invariant |
||
205 | // |
||
206 | // It must not be calculated at each loop iteration and can often even be |
||
207 | // hoisted out further by the loop invariant code motion. |
||
208 | // |
||
209 | // 2. OpenMP needs a loop invariant upper bound to calculate the number |
||
210 | // of loop iterations. |
||
211 | // |
||
212 | // 3. With the existing code, upper bounds have been easier to implement. |
||
213 | isl::ast_expr getUpperBound(isl::ast_node_for For, |
||
214 | CmpInst::Predicate &Predicate); |
||
215 | |||
216 | /// Return non-negative number of iterations in case of the following form |
||
217 | /// of a loop and -1 otherwise. |
||
218 | /// |
||
219 | /// for (i = 0; i <= NumIter; i++) { |
||
220 | /// loop body; |
||
221 | /// } |
||
222 | /// |
||
223 | /// NumIter is a non-negative integer value. Condition can have |
||
224 | /// isl_ast_op_lt type. |
||
225 | int getNumberOfIterations(isl::ast_node_for For); |
||
226 | |||
227 | /// Compute the values and loops referenced in this subtree. |
||
228 | /// |
||
229 | /// This function looks at all ScopStmts scheduled below the provided For node |
||
230 | /// and finds the llvm::Value[s] and llvm::Loops[s] which are referenced but |
||
231 | /// not locally defined. |
||
232 | /// |
||
233 | /// Values that can be synthesized or that are available as globals are |
||
234 | /// considered locally defined. |
||
235 | /// |
||
236 | /// Loops that contain the scop or that are part of the scop are considered |
||
237 | /// locally defined. Loops that are before the scop, but do not contain the |
||
238 | /// scop itself are considered not locally defined. |
||
239 | /// |
||
240 | /// @param For The node defining the subtree. |
||
241 | /// @param Values A vector that will be filled with the Values referenced in |
||
242 | /// this subtree. |
||
243 | /// @param Loops A vector that will be filled with the Loops referenced in |
||
244 | /// this subtree. |
||
245 | void getReferencesInSubtree(const isl::ast_node &For, |
||
246 | SetVector<Value *> &Values, |
||
247 | SetVector<const Loop *> &Loops); |
||
248 | |||
249 | /// Change the llvm::Value(s) used for code generation. |
||
250 | /// |
||
251 | /// When generating code certain values (e.g., references to induction |
||
252 | /// variables or array base pointers) in the original code may be replaced by |
||
253 | /// new values. This function allows to (partially) update the set of values |
||
254 | /// used. A typical use case for this function is the case when we continue |
||
255 | /// code generation in a subfunction/kernel function and need to explicitly |
||
256 | /// pass down certain values. |
||
257 | /// |
||
258 | /// @param NewValues A map that maps certain llvm::Values to new llvm::Values. |
||
259 | void updateValues(ValueMapT &NewValues); |
||
260 | |||
261 | /// Return the most up-to-date version of the llvm::Value for code generation. |
||
262 | /// @param Original The Value to check for an up to date version. |
||
263 | /// @returns A remapped `Value` from ValueMap, or `Original` if no mapping |
||
264 | /// exists. |
||
265 | /// @see IslNodeBuilder::updateValues |
||
266 | /// @see IslNodeBuilder::ValueMap |
||
267 | Value *getLatestValue(Value *Original) const; |
||
268 | |||
269 | /// Generate code for a marker now. |
||
270 | /// |
||
271 | /// For mark nodes with an unknown name, we just forward the code generation |
||
272 | /// to its child. This is currently the only behavior implemented, as there is |
||
273 | /// currently not special handling for marker nodes implemented. |
||
274 | /// |
||
275 | /// @param Mark The node we generate code for. |
||
276 | virtual void createMark(__isl_take isl_ast_node *Marker); |
||
277 | |||
278 | virtual void createFor(__isl_take isl_ast_node *For); |
||
279 | |||
280 | /// Set to remember materialized invariant loads. |
||
281 | /// |
||
282 | /// An invariant load is identified by its pointer (the SCEV) and its type. |
||
283 | SmallSet<std::pair<const SCEV *, Type *>, 16> PreloadedPtrs; |
||
284 | |||
285 | /// Preload the memory access at @p AccessRange with @p Build. |
||
286 | /// |
||
287 | /// @returns The preloaded value casted to type @p Ty |
||
288 | Value *preloadUnconditionally(__isl_take isl_set *AccessRange, |
||
289 | isl_ast_build *Build, Instruction *AccInst); |
||
290 | |||
291 | /// Preload the memory load access @p MA. |
||
292 | /// |
||
293 | /// If @p MA is not always executed it will be conditionally loaded and |
||
294 | /// merged with undef from the same type. Hence, if @p MA is executed only |
||
295 | /// under condition C then the preload code will look like this: |
||
296 | /// |
||
297 | /// MA_preload = undef; |
||
298 | /// if (C) |
||
299 | /// MA_preload = load MA; |
||
300 | /// use MA_preload |
||
301 | Value *preloadInvariantLoad(const MemoryAccess &MA, |
||
302 | __isl_take isl_set *Domain); |
||
303 | |||
304 | /// Preload the invariant access equivalence class @p IAClass |
||
305 | /// |
||
306 | /// This function will preload the representing load from @p IAClass and |
||
307 | /// map all members of @p IAClass to that preloaded value, potentially casted |
||
308 | /// to the required type. |
||
309 | /// |
||
310 | /// @returns False, iff a problem occurred and the load was not preloaded. |
||
311 | bool preloadInvariantEquivClass(InvariantEquivClassTy &IAClass); |
||
312 | |||
313 | void createForVector(__isl_take isl_ast_node *For, int VectorWidth); |
||
314 | void createForSequential(isl::ast_node_for For, bool MarkParallel); |
||
315 | |||
316 | /// Create LLVM-IR that executes a for node thread parallel. |
||
317 | /// |
||
318 | /// @param For The FOR isl_ast_node for which code is generated. |
||
319 | void createForParallel(__isl_take isl_ast_node *For); |
||
320 | |||
321 | /// Create new access functions for modified memory accesses. |
||
322 | /// |
||
323 | /// In case the access function of one of the memory references in the Stmt |
||
324 | /// has been modified, we generate a new isl_ast_expr that reflects the |
||
325 | /// newly modified access function and return a map that maps from the |
||
326 | /// individual memory references in the statement (identified by their id) |
||
327 | /// to these newly generated ast expressions. |
||
328 | /// |
||
329 | /// @param Stmt The statement for which to (possibly) generate new access |
||
330 | /// functions. |
||
331 | /// @param Node The ast node corresponding to the statement for us to extract |
||
332 | /// the local schedule from. |
||
333 | /// @return A new hash table that contains remappings from memory ids to new |
||
334 | /// access expressions. |
||
335 | __isl_give isl_id_to_ast_expr * |
||
336 | createNewAccesses(ScopStmt *Stmt, __isl_keep isl_ast_node *Node); |
||
337 | |||
338 | /// Generate LLVM-IR that computes the values of the original induction |
||
339 | /// variables in function of the newly generated loop induction variables. |
||
340 | /// |
||
341 | /// Example: |
||
342 | /// |
||
343 | /// // Original |
||
344 | /// for i |
||
345 | /// for j |
||
346 | /// S(i) |
||
347 | /// |
||
348 | /// Schedule: [i,j] -> [i+j, j] |
||
349 | /// |
||
350 | /// // New |
||
351 | /// for c0 |
||
352 | /// for c1 |
||
353 | /// S(c0 - c1, c1) |
||
354 | /// |
||
355 | /// Assuming the original code consists of two loops which are |
||
356 | /// transformed according to a schedule [i,j] -> [c0=i+j,c1=j]. The resulting |
||
357 | /// ast models the original statement as a call expression where each argument |
||
358 | /// is an expression that computes the old induction variables from the new |
||
359 | /// ones, ordered such that the first argument computes the value of induction |
||
360 | /// variable that was outermost in the original code. |
||
361 | /// |
||
362 | /// @param Expr The call expression that represents the statement. |
||
363 | /// @param Stmt The statement that is called. |
||
364 | /// @param LTS The loop to SCEV map in which the mapping from the original |
||
365 | /// loop to a SCEV representing the new loop iv is added. This |
||
366 | /// mapping does not require an explicit induction variable. |
||
367 | /// Instead, we think in terms of an implicit induction variable |
||
368 | /// that counts the number of times a loop is executed. For each |
||
369 | /// original loop this count, expressed in function of the new |
||
370 | /// induction variables, is added to the LTS map. |
||
371 | void createSubstitutions(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt, |
||
372 | LoopToScevMapT <S); |
||
373 | void createSubstitutionsVector(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt, |
||
374 | std::vector<LoopToScevMapT> &VLTS, |
||
375 | std::vector<Value *> &IVS, |
||
376 | __isl_take isl_id *IteratorID); |
||
377 | virtual void createIf(__isl_take isl_ast_node *If); |
||
378 | void createUserVector(__isl_take isl_ast_node *User, |
||
379 | std::vector<Value *> &IVS, |
||
380 | __isl_take isl_id *IteratorID, |
||
381 | __isl_take isl_union_map *Schedule); |
||
382 | virtual void createUser(__isl_take isl_ast_node *User); |
||
383 | virtual void createBlock(__isl_take isl_ast_node *Block); |
||
384 | |||
385 | /// Get the schedule for a given AST node. |
||
386 | /// |
||
387 | /// This information is used to reason about parallelism of loops or the |
||
388 | /// locality of memory accesses under a given schedule. |
||
389 | /// |
||
390 | /// @param Node The node we want to obtain the schedule for. |
||
391 | /// @return Return an isl_union_map that maps from the statements executed |
||
392 | /// below this ast node to the scheduling vectors used to enumerate |
||
393 | /// them. |
||
394 | /// |
||
395 | virtual isl::union_map getScheduleForAstNode(const isl::ast_node &Node); |
||
396 | |||
397 | private: |
||
398 | /// Create code for a copy statement. |
||
399 | /// |
||
400 | /// A copy statement is expected to have one read memory access and one write |
||
401 | /// memory access (in this very order). Data is loaded from the location |
||
402 | /// described by the read memory access and written to the location described |
||
403 | /// by the write memory access. @p NewAccesses contains for each access |
||
404 | /// the isl ast expression that describes the location accessed. |
||
405 | /// |
||
406 | /// @param Stmt The copy statement that contains the accesses. |
||
407 | /// @param NewAccesses The hash table that contains remappings from memory |
||
408 | /// ids to new access expressions. |
||
409 | void generateCopyStmt(ScopStmt *Stmt, |
||
410 | __isl_keep isl_id_to_ast_expr *NewAccesses); |
||
411 | |||
412 | /// Materialize a canonical loop induction variable for `L`, which is a loop |
||
413 | /// that is *not* present in the Scop. |
||
414 | /// |
||
415 | /// Note that this is materialized at the point where the `Builder` is |
||
416 | /// currently pointing. |
||
417 | /// We also populate the `OutsideLoopIterations` map with `L`s SCEV to keep |
||
418 | /// track of the induction variable. |
||
419 | /// See [Code generation of induction variables of loops outside Scops] |
||
420 | Value *materializeNonScopLoopInductionVariable(const Loop *L); |
||
421 | }; |
||
422 | |||
423 | } // namespace polly |
||
424 | |||
425 | #endif // POLLY_ISLNODEBUILDER_H |