1 | //===- ForwardOpTree.h ------------------------------------------*- 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 | // Move instructions between statements. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "polly/ForwardOpTree.h" |
14 | #include "polly/Options.h" |
15 | #include "polly/ScopBuilder.h" |
16 | #include "polly/ScopInfo.h" |
17 | #include "polly/ScopPass.h" |
18 | #include "polly/Support/GICHelper.h" |
19 | #include "polly/Support/ISLOStream.h" |
20 | #include "polly/Support/ISLTools.h" |
21 | #include "polly/Support/VirtualInstruction.h" |
22 | #include "polly/ZoneAlgo.h" |
23 | #include "llvm/ADT/STLExtras.h" |
24 | #include "llvm/ADT/SmallVector.h" |
25 | #include "llvm/ADT/Statistic.h" |
26 | #include "llvm/Analysis/LoopInfo.h" |
27 | #include "llvm/Analysis/ValueTracking.h" |
28 | #include "llvm/IR/Instruction.h" |
29 | #include "llvm/IR/Instructions.h" |
30 | #include "llvm/IR/Value.h" |
31 | #include "llvm/InitializePasses.h" |
32 | #include "llvm/Support/Casting.h" |
33 | #include "llvm/Support/CommandLine.h" |
34 | #include "llvm/Support/Compiler.h" |
35 | #include "llvm/Support/Debug.h" |
36 | #include "llvm/Support/ErrorHandling.h" |
37 | #include "llvm/Support/raw_ostream.h" |
38 | #include "isl/ctx.h" |
39 | #include "isl/isl-noexceptions.h" |
40 | #include <cassert> |
41 | #include <memory> |
42 | |
43 | #include "polly/Support/PollyDebug.h" |
44 | #define DEBUG_TYPE "polly-optree" |
45 | |
46 | using namespace llvm; |
47 | using namespace polly; |
48 | |
49 | static cl::opt<bool> |
50 | AnalyzeKnown("polly-optree-analyze-known" , |
51 | cl::desc("Analyze array contents for load forwarding" ), |
52 | cl::cat(PollyCategory), cl::init(Val: true), cl::Hidden); |
53 | |
54 | static cl::opt<bool> |
55 | NormalizePHIs("polly-optree-normalize-phi" , |
56 | cl::desc("Replace PHIs by their incoming values" ), |
57 | cl::cat(PollyCategory), cl::init(Val: false), cl::Hidden); |
58 | |
59 | static cl::opt<unsigned> |
60 | MaxOps("polly-optree-max-ops" , |
61 | cl::desc("Maximum number of ISL operations to invest for known " |
62 | "analysis; 0=no limit" ), |
63 | cl::init(Val: 1000000), cl::cat(PollyCategory), cl::Hidden); |
64 | |
65 | STATISTIC(KnownAnalyzed, "Number of successfully analyzed SCoPs" ); |
66 | STATISTIC(KnownOutOfQuota, |
67 | "Analyses aborted because max_operations was reached" ); |
68 | |
69 | STATISTIC(TotalInstructionsCopied, "Number of copied instructions" ); |
70 | STATISTIC(TotalKnownLoadsForwarded, |
71 | "Number of forwarded loads because their value was known" ); |
72 | STATISTIC(TotalReloads, "Number of reloaded values" ); |
73 | STATISTIC(TotalReadOnlyCopied, "Number of copied read-only accesses" ); |
74 | STATISTIC(TotalForwardedTrees, "Number of forwarded operand trees" ); |
75 | STATISTIC(TotalModifiedStmts, |
76 | "Number of statements with at least one forwarded tree" ); |
77 | |
78 | STATISTIC(ScopsModified, "Number of SCoPs with at least one forwarded tree" ); |
79 | |
80 | STATISTIC(NumValueWrites, "Number of scalar value writes after OpTree" ); |
81 | STATISTIC(NumValueWritesInLoops, |
82 | "Number of scalar value writes nested in affine loops after OpTree" ); |
83 | STATISTIC(NumPHIWrites, "Number of scalar phi writes after OpTree" ); |
84 | STATISTIC(NumPHIWritesInLoops, |
85 | "Number of scalar phi writes nested in affine loops after OpTree" ); |
86 | STATISTIC(NumSingletonWrites, "Number of singleton writes after OpTree" ); |
87 | STATISTIC(NumSingletonWritesInLoops, |
88 | "Number of singleton writes nested in affine loops after OpTree" ); |
89 | |
90 | namespace { |
91 | |
92 | /// The state of whether an operand tree was/can be forwarded. |
93 | /// |
94 | /// The items apply to an instructions and its operand tree with the instruction |
95 | /// as the root element. If the value in question is not an instruction in the |
96 | /// SCoP, it can be a leaf of an instruction's operand tree. |
97 | enum ForwardingDecision { |
98 | /// An uninitialized value. |
99 | FD_Unknown, |
100 | |
101 | /// The root instruction or value cannot be forwarded at all. |
102 | FD_CannotForward, |
103 | |
104 | /// The root instruction or value can be forwarded as a leaf of a larger |
105 | /// operand tree. |
106 | /// It does not make sense to move the value itself, it would just replace it |
107 | /// by a use of itself. For instance, a constant "5" used in a statement can |
108 | /// be forwarded, but it would just replace it by the same constant "5". |
109 | /// However, it makes sense to move as an operand of |
110 | /// |
111 | /// %add = add 5, 5 |
112 | /// |
113 | /// where "5" is moved as part of a larger operand tree. "5" would be placed |
114 | /// (disregarding for a moment that literal constants don't have a location |
115 | /// and can be used anywhere) into the same statement as %add would. |
116 | FD_CanForwardLeaf, |
117 | |
118 | /// The root instruction can be forwarded and doing so avoids a scalar |
119 | /// dependency. |
120 | /// |
121 | /// This can be either because the operand tree can be moved to the target |
122 | /// statement, or a memory access is redirected to read from a different |
123 | /// location. |
124 | FD_CanForwardProfitably, |
125 | |
126 | /// A forwarding method cannot be applied to the operand tree. |
127 | /// The difference to FD_CannotForward is that there might be other methods |
128 | /// that can handle it. |
129 | FD_NotApplicable |
130 | }; |
131 | |
132 | /// Represents the evaluation of and action to taken when forwarding a value |
133 | /// from an operand tree. |
134 | struct ForwardingAction { |
135 | using KeyTy = std::pair<Value *, ScopStmt *>; |
136 | |
137 | /// Evaluation of forwarding a value. |
138 | ForwardingDecision Decision = FD_Unknown; |
139 | |
140 | /// Callback to execute the forwarding. |
141 | /// Returning true allows deleting the polly::MemoryAccess if the value is the |
142 | /// root of the operand tree (and its elimination the reason why the |
143 | /// forwarding is done). Return false if the MemoryAccess is reused or there |
144 | /// might be other users of the read accesses. In the letter case the |
145 | /// polly::SimplifyPass can remove dead MemoryAccesses. |
146 | std::function<bool()> Execute = []() -> bool { |
147 | llvm_unreachable("unspecified how to forward" ); |
148 | }; |
149 | |
150 | /// Other values that need to be forwarded if this action is executed. Their |
151 | /// actions are executed after this one. |
152 | SmallVector<KeyTy, 4> Depends; |
153 | |
154 | /// Named ctor: The method creating this object does not apply to the kind of |
155 | /// value, but other methods may. |
156 | static ForwardingAction notApplicable() { |
157 | ForwardingAction Result; |
158 | Result.Decision = FD_NotApplicable; |
159 | return Result; |
160 | } |
161 | |
162 | /// Named ctor: The value cannot be forwarded. |
163 | static ForwardingAction cannotForward() { |
164 | ForwardingAction Result; |
165 | Result.Decision = FD_CannotForward; |
166 | return Result; |
167 | } |
168 | |
169 | /// Named ctor: The value can just be used without any preparation. |
170 | static ForwardingAction triviallyForwardable(bool IsProfitable, Value *Val) { |
171 | ForwardingAction Result; |
172 | Result.Decision = |
173 | IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf; |
174 | Result.Execute = [=]() { |
175 | POLLY_DEBUG(dbgs() << " trivially forwarded: " << *Val << "\n" ); |
176 | return true; |
177 | }; |
178 | return Result; |
179 | } |
180 | |
181 | /// Name ctor: The value can be forwarded by executing an action. |
182 | static ForwardingAction canForward(std::function<bool()> Execute, |
183 | ArrayRef<KeyTy> Depends, |
184 | bool IsProfitable) { |
185 | ForwardingAction Result; |
186 | Result.Decision = |
187 | IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf; |
188 | Result.Execute = std::move(Execute); |
189 | Result.Depends.append(in_start: Depends.begin(), in_end: Depends.end()); |
190 | return Result; |
191 | } |
192 | }; |
193 | |
194 | /// Implementation of operand tree forwarding for a specific SCoP. |
195 | /// |
196 | /// For a statement that requires a scalar value (through a value read |
197 | /// MemoryAccess), see if its operand can be moved into the statement. If so, |
198 | /// the MemoryAccess is removed and the all the operand tree instructions are |
199 | /// moved into the statement. All original instructions are left in the source |
200 | /// statements. The simplification pass can clean these up. |
201 | class ForwardOpTreeImpl final : ZoneAlgorithm { |
202 | private: |
203 | using MemoizationTy = DenseMap<ForwardingAction::KeyTy, ForwardingAction>; |
204 | |
205 | /// Scope guard to limit the number of isl operations for this pass. |
206 | IslMaxOperationsGuard &MaxOpGuard; |
207 | |
208 | /// How many instructions have been copied to other statements. |
209 | int NumInstructionsCopied = 0; |
210 | |
211 | /// Number of loads forwarded because their value was known. |
212 | int NumKnownLoadsForwarded = 0; |
213 | |
214 | /// Number of values reloaded from known array elements. |
215 | int NumReloads = 0; |
216 | |
217 | /// How many read-only accesses have been copied. |
218 | int NumReadOnlyCopied = 0; |
219 | |
220 | /// How many operand trees have been forwarded. |
221 | int NumForwardedTrees = 0; |
222 | |
223 | /// Number of statements with at least one forwarded operand tree. |
224 | int NumModifiedStmts = 0; |
225 | |
226 | /// Whether we carried out at least one change to the SCoP. |
227 | bool Modified = false; |
228 | |
229 | /// Cache of how to forward values. |
230 | /// The key of this map is the llvm::Value to be forwarded and the |
231 | /// polly::ScopStmt it is forwarded from. This is because the same llvm::Value |
232 | /// can evaluate differently depending on where it is evaluate. For instance, |
233 | /// a synthesizable Scev represents a recurrence with an loop but the loop's |
234 | /// exit value if evaluated after the loop. |
235 | /// The cached results are only valid for the current TargetStmt. |
236 | /// CHECKME: ScalarEvolution::getScevAtScope should take care for getting the |
237 | /// exit value when instantiated outside of the loop. The primary concern is |
238 | /// ambiguity when crossing PHI nodes, which currently is not supported. |
239 | MemoizationTy ForwardingActions; |
240 | |
241 | /// Contains the zones where array elements are known to contain a specific |
242 | /// value. |
243 | /// { [Element[] -> Zone[]] -> ValInst[] } |
244 | /// @see computeKnown() |
245 | isl::union_map Known; |
246 | |
247 | /// Translator for newly introduced ValInsts to already existing ValInsts such |
248 | /// that new introduced load instructions can reuse the Known analysis of its |
249 | /// original load. { ValInst[] -> ValInst[] } |
250 | isl::union_map Translator; |
251 | |
252 | /// Get list of array elements that do contain the same ValInst[] at Domain[]. |
253 | /// |
254 | /// @param ValInst { Domain[] -> ValInst[] } |
255 | /// The values for which we search for alternative locations, |
256 | /// per statement instance. |
257 | /// |
258 | /// @return { Domain[] -> Element[] } |
259 | /// For each statement instance, the array elements that contain the |
260 | /// same ValInst. |
261 | isl::union_map findSameContentElements(isl::union_map ValInst) { |
262 | assert(!ValInst.is_single_valued().is_false()); |
263 | |
264 | // { Domain[] } |
265 | isl::union_set Domain = ValInst.domain(); |
266 | |
267 | // { Domain[] -> Scatter[] } |
268 | isl::union_map Schedule = getScatterFor(Domain); |
269 | |
270 | // { Element[] -> [Scatter[] -> ValInst[]] } |
271 | isl::union_map MustKnownCurried = |
272 | convertZoneToTimepoints(Zone: Known, Dim: isl::dim::in, InclStart: false, InclEnd: true).curry(); |
273 | |
274 | // { [Domain[] -> ValInst[]] -> Scatter[] } |
275 | isl::union_map DomValSched = ValInst.domain_map().apply_range(umap2: Schedule); |
276 | |
277 | // { [Scatter[] -> ValInst[]] -> [Domain[] -> ValInst[]] } |
278 | isl::union_map SchedValDomVal = |
279 | DomValSched.range_product(umap2: ValInst.range_map()).reverse(); |
280 | |
281 | // { Element[] -> [Domain[] -> ValInst[]] } |
282 | isl::union_map MustKnownInst = MustKnownCurried.apply_range(umap2: SchedValDomVal); |
283 | |
284 | // { Domain[] -> Element[] } |
285 | isl::union_map MustKnownMap = |
286 | MustKnownInst.uncurry().domain().unwrap().reverse(); |
287 | simplify(UMap&: MustKnownMap); |
288 | |
289 | return MustKnownMap; |
290 | } |
291 | |
292 | /// Find a single array element for each statement instance, within a single |
293 | /// array. |
294 | /// |
295 | /// @param MustKnown { Domain[] -> Element[] } |
296 | /// Set of candidate array elements. |
297 | /// @param Domain { Domain[] } |
298 | /// The statement instance for which we need elements for. |
299 | /// |
300 | /// @return { Domain[] -> Element[] } |
301 | /// For each statement instance, an array element out of @p MustKnown. |
302 | /// All array elements must be in the same array (Polly does not yet |
303 | /// support reading from different accesses using the same |
304 | /// MemoryAccess). If no mapping for all of @p Domain exists, returns |
305 | /// null. |
306 | isl::map singleLocation(isl::union_map MustKnown, isl::set Domain) { |
307 | // { Domain[] -> Element[] } |
308 | isl::map Result; |
309 | |
310 | // Make irrelevant elements not interfere. |
311 | Domain = Domain.intersect_params(params: S->getContext()); |
312 | |
313 | // MemoryAccesses can read only elements from a single array |
314 | // (i.e. not: { Dom[0] -> A[0]; Dom[1] -> B[1] }). |
315 | // Look through all spaces until we find one that contains at least the |
316 | // wanted statement instance.s |
317 | for (isl::map Map : MustKnown.get_map_list()) { |
318 | // Get the array this is accessing. |
319 | isl::id ArrayId = Map.get_tuple_id(type: isl::dim::out); |
320 | ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(ArrayId.get_user()); |
321 | |
322 | // No support for generation of indirect array accesses. |
323 | if (SAI->getBasePtrOriginSAI()) |
324 | continue; |
325 | |
326 | // Determine whether this map contains all wanted values. |
327 | isl::set MapDom = Map.domain(); |
328 | if (!Domain.is_subset(set2: MapDom).is_true()) |
329 | continue; |
330 | |
331 | // There might be multiple array elements that contain the same value, but |
332 | // choose only one of them. lexmin is used because it returns a one-value |
333 | // mapping, we do not care about which one. |
334 | // TODO: Get the simplest access function. |
335 | Result = Map.lexmin(); |
336 | break; |
337 | } |
338 | |
339 | return Result; |
340 | } |
341 | |
342 | public: |
343 | ForwardOpTreeImpl(Scop *S, LoopInfo *LI, IslMaxOperationsGuard &MaxOpGuard) |
344 | : ZoneAlgorithm("polly-optree" , S, LI), MaxOpGuard(MaxOpGuard) {} |
345 | |
346 | /// Compute the zones of known array element contents. |
347 | /// |
348 | /// @return True if the computed #Known is usable. |
349 | bool computeKnownValues() { |
350 | isl::union_map MustKnown, KnownFromLoad, KnownFromInit; |
351 | |
352 | // Check that nothing strange occurs. |
353 | collectCompatibleElts(); |
354 | |
355 | { |
356 | IslQuotaScope QuotaScope = MaxOpGuard.enter(); |
357 | |
358 | computeCommon(); |
359 | if (NormalizePHIs) |
360 | computeNormalizedPHIs(); |
361 | Known = computeKnown(FromWrite: true, FromRead: true); |
362 | |
363 | // Preexisting ValInsts use the known content analysis of themselves. |
364 | Translator = makeIdentityMap(USet: Known.range(), RestrictDomain: false); |
365 | } |
366 | |
367 | if (Known.is_null() || Translator.is_null() || NormalizeMap.is_null()) { |
368 | assert(isl_ctx_last_error(IslCtx.get()) == isl_error_quota); |
369 | Known = {}; |
370 | Translator = {}; |
371 | NormalizeMap = {}; |
372 | POLLY_DEBUG(dbgs() << "Known analysis exceeded max_operations\n" ); |
373 | return false; |
374 | } |
375 | |
376 | KnownAnalyzed++; |
377 | POLLY_DEBUG(dbgs() << "All known: " << Known << "\n" ); |
378 | |
379 | return true; |
380 | } |
381 | |
382 | void printStatistics(raw_ostream &OS, int Indent = 0) { |
383 | OS.indent(NumSpaces: Indent) << "Statistics {\n" ; |
384 | OS.indent(NumSpaces: Indent + 4) << "Instructions copied: " << NumInstructionsCopied |
385 | << '\n'; |
386 | OS.indent(NumSpaces: Indent + 4) << "Known loads forwarded: " << NumKnownLoadsForwarded |
387 | << '\n'; |
388 | OS.indent(NumSpaces: Indent + 4) << "Reloads: " << NumReloads << '\n'; |
389 | OS.indent(NumSpaces: Indent + 4) << "Read-only accesses copied: " << NumReadOnlyCopied |
390 | << '\n'; |
391 | OS.indent(NumSpaces: Indent + 4) << "Operand trees forwarded: " << NumForwardedTrees |
392 | << '\n'; |
393 | OS.indent(NumSpaces: Indent + 4) << "Statements with forwarded operand trees: " |
394 | << NumModifiedStmts << '\n'; |
395 | OS.indent(NumSpaces: Indent) << "}\n" ; |
396 | } |
397 | |
398 | void printStatements(raw_ostream &OS, int Indent = 0) const { |
399 | OS.indent(NumSpaces: Indent) << "After statements {\n" ; |
400 | for (auto &Stmt : *S) { |
401 | OS.indent(NumSpaces: Indent + 4) << Stmt.getBaseName() << "\n" ; |
402 | for (auto *MA : Stmt) |
403 | MA->print(OS); |
404 | |
405 | OS.indent(NumSpaces: Indent + 12); |
406 | Stmt.printInstructions(OS); |
407 | } |
408 | OS.indent(NumSpaces: Indent) << "}\n" ; |
409 | } |
410 | |
411 | /// Create a new MemoryAccess of type read and MemoryKind::Array. |
412 | /// |
413 | /// @param Stmt The statement in which the access occurs. |
414 | /// @param LI The instruction that does the access. |
415 | /// @param AccessRelation The array element that each statement instance |
416 | /// accesses. |
417 | /// |
418 | /// @param The newly created access. |
419 | MemoryAccess *makeReadArrayAccess(ScopStmt *Stmt, LoadInst *LI, |
420 | isl::map AccessRelation) { |
421 | isl::id ArrayId = AccessRelation.get_tuple_id(type: isl::dim::out); |
422 | ScopArrayInfo *SAI = reinterpret_cast<ScopArrayInfo *>(ArrayId.get_user()); |
423 | |
424 | // Create a dummy SCEV access, to be replaced anyway. |
425 | SmallVector<const SCEV *, 4> Sizes; |
426 | Sizes.reserve(N: SAI->getNumberOfDimensions()); |
427 | SmallVector<const SCEV *, 4> Subscripts; |
428 | Subscripts.reserve(N: SAI->getNumberOfDimensions()); |
429 | for (unsigned i = 0; i < SAI->getNumberOfDimensions(); i += 1) { |
430 | Sizes.push_back(Elt: SAI->getDimensionSize(Dim: i)); |
431 | Subscripts.push_back(Elt: nullptr); |
432 | } |
433 | |
434 | MemoryAccess *Access = |
435 | new MemoryAccess(Stmt, LI, MemoryAccess::READ, SAI->getBasePtr(), |
436 | LI->getType(), true, {}, Sizes, LI, MemoryKind::Array); |
437 | S->addAccessFunction(Access); |
438 | Stmt->addAccess(Access, Preprend: true); |
439 | |
440 | Access->setNewAccessRelation(AccessRelation); |
441 | |
442 | return Access; |
443 | } |
444 | |
445 | /// Forward a load by reading from an array element that contains the same |
446 | /// value. Typically the location it was loaded from. |
447 | /// |
448 | /// @param TargetStmt The statement the operand tree will be copied to. |
449 | /// @param Inst The (possibly speculatable) instruction to forward. |
450 | /// @param UseStmt The statement that uses @p Inst. |
451 | /// @param UseLoop The loop @p Inst is used in. |
452 | /// @param DefStmt The statement @p Inst is defined in. |
453 | /// @param DefLoop The loop which contains @p Inst. |
454 | /// |
455 | /// @return A ForwardingAction object describing the feasibility and |
456 | /// profitability evaluation and the callback carrying-out the value |
457 | /// forwarding. |
458 | ForwardingAction forwardKnownLoad(ScopStmt *TargetStmt, Instruction *Inst, |
459 | ScopStmt *UseStmt, Loop *UseLoop, |
460 | ScopStmt *DefStmt, Loop *DefLoop) { |
461 | // Cannot do anything without successful known analysis. |
462 | if (Known.is_null() || Translator.is_null() || |
463 | MaxOpGuard.hasQuotaExceeded()) |
464 | return ForwardingAction::notApplicable(); |
465 | |
466 | LoadInst *LI = dyn_cast<LoadInst>(Val: Inst); |
467 | if (!LI) |
468 | return ForwardingAction::notApplicable(); |
469 | |
470 | ForwardingDecision OpDecision = |
471 | forwardTree(TargetStmt, UseVal: LI->getPointerOperand(), UseStmt: DefStmt, UseLoop: DefLoop); |
472 | switch (OpDecision) { |
473 | case FD_CanForwardProfitably: |
474 | case FD_CanForwardLeaf: |
475 | break; |
476 | case FD_CannotForward: |
477 | return ForwardingAction::cannotForward(); |
478 | default: |
479 | llvm_unreachable("Shouldn't return this" ); |
480 | } |
481 | |
482 | MemoryAccess *Access = TargetStmt->getArrayAccessOrNULLFor(Inst: LI); |
483 | if (Access) { |
484 | // If the load is already in the statement, no forwarding is necessary. |
485 | // However, it might happen that the LoadInst is already present in the |
486 | // statement's instruction list. In that case we do as follows: |
487 | // - For the evaluation, we can trivially forward it as it is |
488 | // benefit of forwarding an already present instruction. |
489 | // - For the execution, prepend the instruction (to make it |
490 | // available to all instructions following in the instruction list), but |
491 | // do not add another MemoryAccess. |
492 | auto ExecAction = [this, TargetStmt, LI, Access]() -> bool { |
493 | TargetStmt->prependInstruction(Inst: LI); |
494 | POLLY_DEBUG( |
495 | dbgs() << " forwarded known load with preexisting MemoryAccess" |
496 | << Access << "\n" ); |
497 | (void)Access; |
498 | |
499 | NumKnownLoadsForwarded++; |
500 | TotalKnownLoadsForwarded++; |
501 | return true; |
502 | }; |
503 | return ForwardingAction::canForward( |
504 | Execute: ExecAction, Depends: {{LI->getPointerOperand(), DefStmt}}, IsProfitable: true); |
505 | } |
506 | |
507 | // Allow the following Isl calculations (until we return the |
508 | // ForwardingAction, excluding the code inside the lambda that will be |
509 | // executed later) to fail. |
510 | IslQuotaScope QuotaScope = MaxOpGuard.enter(); |
511 | |
512 | // { DomainDef[] -> ValInst[] } |
513 | isl::map ExpectedVal = makeValInst(Val: Inst, UserStmt: UseStmt, Scope: UseLoop); |
514 | assert(!isNormalized(ExpectedVal).is_false() && |
515 | "LoadInsts are always normalized" ); |
516 | |
517 | // { DomainUse[] -> DomainTarget[] } |
518 | isl::map UseToTarget = getDefToTarget(DefStmt: UseStmt, TargetStmt); |
519 | |
520 | // { DomainTarget[] -> ValInst[] } |
521 | isl::map TargetExpectedVal = ExpectedVal.apply_domain(map2: UseToTarget); |
522 | isl::union_map TranslatedExpectedVal = |
523 | isl::union_map(TargetExpectedVal).apply_range(umap2: Translator); |
524 | |
525 | // { DomainTarget[] -> Element[] } |
526 | isl::union_map Candidates = findSameContentElements(ValInst: TranslatedExpectedVal); |
527 | |
528 | isl::map SameVal = singleLocation(MustKnown: Candidates, Domain: getDomainFor(Stmt: TargetStmt)); |
529 | if (SameVal.is_null()) |
530 | return ForwardingAction::notApplicable(); |
531 | |
532 | POLLY_DEBUG(dbgs() << " expected values where " << TargetExpectedVal |
533 | << "\n" ); |
534 | POLLY_DEBUG(dbgs() << " candidate elements where " << Candidates |
535 | << "\n" ); |
536 | |
537 | // { ValInst[] } |
538 | isl::space ValInstSpace = ExpectedVal.get_space().range(); |
539 | |
540 | // After adding a new load to the SCoP, also update the Known content |
541 | // about it. The new load will have a known ValInst of |
542 | // { [DomainTarget[] -> Value[]] } |
543 | // but which -- because it is a copy of it -- has same value as the |
544 | // { [DomainDef[] -> Value[]] } |
545 | // that it replicates. Instead of cloning the known content of |
546 | // [DomainDef[] -> Value[]] |
547 | // for DomainTarget[], we add a 'translator' that maps |
548 | // [DomainTarget[] -> Value[]] to [DomainDef[] -> Value[]] |
549 | // before comparing to the known content. |
550 | // TODO: 'Translator' could also be used to map PHINodes to their incoming |
551 | // ValInsts. |
552 | isl::map LocalTranslator; |
553 | if (!ValInstSpace.is_wrapping().is_false()) { |
554 | // { DefDomain[] -> Value[] } |
555 | isl::map ValInsts = ExpectedVal.range().unwrap(); |
556 | |
557 | // { DefDomain[] } |
558 | isl::set DefDomain = ValInsts.domain(); |
559 | |
560 | // { Value[] } |
561 | isl::space ValSpace = ValInstSpace.unwrap().range(); |
562 | |
563 | // { Value[] -> Value[] } |
564 | isl::map ValToVal = |
565 | isl::map::identity(space: ValSpace.map_from_domain_and_range(range: ValSpace)); |
566 | |
567 | // { DomainDef[] -> DomainTarget[] } |
568 | isl::map DefToTarget = getDefToTarget(DefStmt, TargetStmt); |
569 | |
570 | // { [TargetDomain[] -> Value[]] -> [DefDomain[] -> Value] } |
571 | LocalTranslator = DefToTarget.reverse().product(map2: ValToVal); |
572 | POLLY_DEBUG(dbgs() << " local translator is " << LocalTranslator |
573 | << "\n" ); |
574 | |
575 | if (LocalTranslator.is_null()) |
576 | return ForwardingAction::notApplicable(); |
577 | } |
578 | |
579 | auto ExecAction = [this, TargetStmt, LI, SameVal, |
580 | LocalTranslator]() -> bool { |
581 | TargetStmt->prependInstruction(Inst: LI); |
582 | MemoryAccess *Access = makeReadArrayAccess(Stmt: TargetStmt, LI, AccessRelation: SameVal); |
583 | POLLY_DEBUG(dbgs() << " forwarded known load with new MemoryAccess" |
584 | << Access << "\n" ); |
585 | (void)Access; |
586 | |
587 | if (!LocalTranslator.is_null()) |
588 | Translator = Translator.unite(umap2: LocalTranslator); |
589 | |
590 | NumKnownLoadsForwarded++; |
591 | TotalKnownLoadsForwarded++; |
592 | return true; |
593 | }; |
594 | return ForwardingAction::canForward( |
595 | Execute: ExecAction, Depends: {{LI->getPointerOperand(), DefStmt}}, IsProfitable: true); |
596 | } |
597 | |
598 | /// Forward a scalar by redirecting the access to an array element that stores |
599 | /// the same value. |
600 | /// |
601 | /// @param TargetStmt The statement the operand tree will be copied to. |
602 | /// @param Inst The scalar to forward. |
603 | /// @param UseStmt The statement that uses @p Inst. |
604 | /// @param UseLoop The loop @p Inst is used in. |
605 | /// @param DefStmt The statement @p Inst is defined in. |
606 | /// @param DefLoop The loop which contains @p Inst. |
607 | /// |
608 | /// @return A ForwardingAction object describing the feasibility and |
609 | /// profitability evaluation and the callback carrying-out the value |
610 | /// forwarding. |
611 | ForwardingAction reloadKnownContent(ScopStmt *TargetStmt, Instruction *Inst, |
612 | ScopStmt *UseStmt, Loop *UseLoop, |
613 | ScopStmt *DefStmt, Loop *DefLoop) { |
614 | // Cannot do anything without successful known analysis. |
615 | if (Known.is_null() || Translator.is_null() || |
616 | MaxOpGuard.hasQuotaExceeded()) |
617 | return ForwardingAction::notApplicable(); |
618 | |
619 | // Don't spend too much time analyzing whether it can be reloaded. |
620 | IslQuotaScope QuotaScope = MaxOpGuard.enter(); |
621 | |
622 | // { DomainDef[] -> ValInst[] } |
623 | isl::union_map ExpectedVal = makeNormalizedValInst(Val: Inst, UserStmt: UseStmt, Scope: UseLoop); |
624 | |
625 | // { DomainUse[] -> DomainTarget[] } |
626 | isl::map UseToTarget = getDefToTarget(DefStmt: UseStmt, TargetStmt); |
627 | |
628 | // { DomainTarget[] -> ValInst[] } |
629 | isl::union_map TargetExpectedVal = ExpectedVal.apply_domain(umap2: UseToTarget); |
630 | isl::union_map TranslatedExpectedVal = |
631 | TargetExpectedVal.apply_range(umap2: Translator); |
632 | |
633 | // { DomainTarget[] -> Element[] } |
634 | isl::union_map Candidates = findSameContentElements(ValInst: TranslatedExpectedVal); |
635 | |
636 | isl::map SameVal = singleLocation(MustKnown: Candidates, Domain: getDomainFor(Stmt: TargetStmt)); |
637 | simplify(Map&: SameVal); |
638 | if (SameVal.is_null()) |
639 | return ForwardingAction::notApplicable(); |
640 | |
641 | auto ExecAction = [this, TargetStmt, Inst, SameVal]() { |
642 | MemoryAccess *Access = TargetStmt->lookupInputAccessOf(Val: Inst); |
643 | if (!Access) |
644 | Access = TargetStmt->ensureValueRead(V: Inst); |
645 | Access->setNewAccessRelation(SameVal); |
646 | |
647 | POLLY_DEBUG(dbgs() << " forwarded known content of " << *Inst |
648 | << " which is " << SameVal << "\n" ); |
649 | TotalReloads++; |
650 | NumReloads++; |
651 | return false; |
652 | }; |
653 | |
654 | return ForwardingAction::canForward(Execute: ExecAction, Depends: {}, IsProfitable: true); |
655 | } |
656 | |
657 | /// Forwards a speculatively executable instruction. |
658 | /// |
659 | /// @param TargetStmt The statement the operand tree will be copied to. |
660 | /// @param UseInst The (possibly speculatable) instruction to forward. |
661 | /// @param DefStmt The statement @p UseInst is defined in. |
662 | /// @param DefLoop The loop which contains @p UseInst. |
663 | /// |
664 | /// @return A ForwardingAction object describing the feasibility and |
665 | /// profitability evaluation and the callback carrying-out the value |
666 | /// forwarding. |
667 | ForwardingAction forwardSpeculatable(ScopStmt *TargetStmt, |
668 | Instruction *UseInst, ScopStmt *DefStmt, |
669 | Loop *DefLoop) { |
670 | // PHIs, unless synthesizable, are not yet supported. |
671 | if (isa<PHINode>(Val: UseInst)) |
672 | return ForwardingAction::notApplicable(); |
673 | |
674 | // Compatible instructions must satisfy the following conditions: |
675 | // 1. Idempotent (instruction will be copied, not moved; although its |
676 | // original instance might be removed by simplification) |
677 | // 2. Not access memory (There might be memory writes between) |
678 | // 3. Not cause undefined behaviour (we might copy to a location when the |
679 | // original instruction was no executed; this is currently not possible |
680 | // because we do not forward PHINodes) |
681 | // 4. Not leak memory if executed multiple times (i.e. malloc) |
682 | // |
683 | // Instruction::mayHaveSideEffects is not sufficient because it considers |
684 | // malloc to not have side-effects. llvm::isSafeToSpeculativelyExecute is |
685 | // not sufficient because it allows memory accesses. |
686 | if (mayHaveNonDefUseDependency(I: *UseInst)) |
687 | return ForwardingAction::notApplicable(); |
688 | |
689 | SmallVector<ForwardingAction::KeyTy, 4> Depends; |
690 | Depends.reserve(N: UseInst->getNumOperands()); |
691 | for (Value *OpVal : UseInst->operand_values()) { |
692 | ForwardingDecision OpDecision = |
693 | forwardTree(TargetStmt, UseVal: OpVal, UseStmt: DefStmt, UseLoop: DefLoop); |
694 | switch (OpDecision) { |
695 | case FD_CannotForward: |
696 | return ForwardingAction::cannotForward(); |
697 | |
698 | case FD_CanForwardLeaf: |
699 | case FD_CanForwardProfitably: |
700 | Depends.emplace_back(Args&: OpVal, Args&: DefStmt); |
701 | break; |
702 | |
703 | case FD_NotApplicable: |
704 | case FD_Unknown: |
705 | llvm_unreachable( |
706 | "forwardTree should never return FD_NotApplicable/FD_Unknown" ); |
707 | } |
708 | } |
709 | |
710 | auto ExecAction = [this, TargetStmt, UseInst]() { |
711 | // To ensure the right order, prepend this instruction before its |
712 | // operands. This ensures that its operands are inserted before the |
713 | // instruction using them. |
714 | TargetStmt->prependInstruction(Inst: UseInst); |
715 | |
716 | POLLY_DEBUG(dbgs() << " forwarded speculable instruction: " << *UseInst |
717 | << "\n" ); |
718 | NumInstructionsCopied++; |
719 | TotalInstructionsCopied++; |
720 | return true; |
721 | }; |
722 | return ForwardingAction::canForward(Execute: ExecAction, Depends, IsProfitable: true); |
723 | } |
724 | |
725 | /// Determines whether an operand tree can be forwarded and returns |
726 | /// instructions how to do so in the form of a ForwardingAction object. |
727 | /// |
728 | /// @param TargetStmt The statement the operand tree will be copied to. |
729 | /// @param UseVal The value (usually an instruction) which is root of an |
730 | /// operand tree. |
731 | /// @param UseStmt The statement that uses @p UseVal. |
732 | /// @param UseLoop The loop @p UseVal is used in. |
733 | /// |
734 | /// @return A ForwardingAction object describing the feasibility and |
735 | /// profitability evaluation and the callback carrying-out the value |
736 | /// forwarding. |
737 | ForwardingAction forwardTreeImpl(ScopStmt *TargetStmt, Value *UseVal, |
738 | ScopStmt *UseStmt, Loop *UseLoop) { |
739 | ScopStmt *DefStmt = nullptr; |
740 | Loop *DefLoop = nullptr; |
741 | |
742 | // { DefDomain[] -> TargetDomain[] } |
743 | isl::map DefToTarget; |
744 | |
745 | VirtualUse VUse = VirtualUse::create(UserStmt: UseStmt, UserScope: UseLoop, Val: UseVal, Virtual: true); |
746 | switch (VUse.getKind()) { |
747 | case VirtualUse::Constant: |
748 | case VirtualUse::Block: |
749 | case VirtualUse::Hoisted: |
750 | // These can be used anywhere without special considerations. |
751 | return ForwardingAction::triviallyForwardable(IsProfitable: false, Val: UseVal); |
752 | |
753 | case VirtualUse::Synthesizable: { |
754 | // Check if the value is synthesizable at the new location as well. This |
755 | // might be possible when leaving a loop for which ScalarEvolution is |
756 | // unable to derive the exit value for. |
757 | // TODO: If there is a LCSSA PHI at the loop exit, use that one. |
758 | // If the SCEV contains a SCEVAddRecExpr, we currently depend on that we |
759 | // do not forward past its loop header. This would require us to use a |
760 | // previous loop induction variable instead the current one. We currently |
761 | // do not allow forwarding PHI nodes, thus this should never occur (the |
762 | // only exception where no phi is necessary being an unreachable loop |
763 | // without edge from the outside). |
764 | VirtualUse TargetUse = VirtualUse::create( |
765 | S, UserStmt: TargetStmt, UserScope: TargetStmt->getSurroundingLoop(), Val: UseVal, Virtual: true); |
766 | if (TargetUse.getKind() == VirtualUse::Synthesizable) |
767 | return ForwardingAction::triviallyForwardable(IsProfitable: false, Val: UseVal); |
768 | |
769 | POLLY_DEBUG( |
770 | dbgs() << " Synthesizable would not be synthesizable anymore: " |
771 | << *UseVal << "\n" ); |
772 | return ForwardingAction::cannotForward(); |
773 | } |
774 | |
775 | case VirtualUse::ReadOnly: { |
776 | if (!ModelReadOnlyScalars) |
777 | return ForwardingAction::triviallyForwardable(IsProfitable: false, Val: UseVal); |
778 | |
779 | // If we model read-only scalars, we need to create a MemoryAccess for it. |
780 | auto ExecAction = [this, TargetStmt, UseVal]() { |
781 | TargetStmt->ensureValueRead(V: UseVal); |
782 | |
783 | POLLY_DEBUG(dbgs() << " forwarded read-only value " << *UseVal |
784 | << "\n" ); |
785 | NumReadOnlyCopied++; |
786 | TotalReadOnlyCopied++; |
787 | |
788 | // Note that we cannot return true here. With a operand tree |
789 | // depth of 0, UseVal is the use in TargetStmt that we try to replace. |
790 | // With -polly-analyze-read-only-scalars=true we would ensure the |
791 | // existence of a MemoryAccess (which already exists for a leaf) and be |
792 | // removed again by tryForwardTree because it's goal is to remove this |
793 | // scalar MemoryAccess. It interprets FD_CanForwardTree as the |
794 | // permission to do so. |
795 | return false; |
796 | }; |
797 | return ForwardingAction::canForward(Execute: ExecAction, Depends: {}, IsProfitable: false); |
798 | } |
799 | |
800 | case VirtualUse::Intra: |
801 | // Knowing that UseStmt and DefStmt are the same statement instance, just |
802 | // reuse the information about UseStmt for DefStmt |
803 | DefStmt = UseStmt; |
804 | |
805 | [[fallthrough]]; |
806 | case VirtualUse::Inter: |
807 | Instruction *Inst = cast<Instruction>(Val: UseVal); |
808 | |
809 | if (!DefStmt) { |
810 | DefStmt = S->getStmtFor(Inst); |
811 | if (!DefStmt) |
812 | return ForwardingAction::cannotForward(); |
813 | } |
814 | |
815 | DefLoop = LI->getLoopFor(BB: Inst->getParent()); |
816 | |
817 | ForwardingAction SpeculativeResult = |
818 | forwardSpeculatable(TargetStmt, UseInst: Inst, DefStmt, DefLoop); |
819 | if (SpeculativeResult.Decision != FD_NotApplicable) |
820 | return SpeculativeResult; |
821 | |
822 | ForwardingAction KnownResult = forwardKnownLoad( |
823 | TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop); |
824 | if (KnownResult.Decision != FD_NotApplicable) |
825 | return KnownResult; |
826 | |
827 | ForwardingAction ReloadResult = reloadKnownContent( |
828 | TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop); |
829 | if (ReloadResult.Decision != FD_NotApplicable) |
830 | return ReloadResult; |
831 | |
832 | // When no method is found to forward the operand tree, we effectively |
833 | // cannot handle it. |
834 | POLLY_DEBUG(dbgs() << " Cannot forward instruction: " << *Inst |
835 | << "\n" ); |
836 | return ForwardingAction::cannotForward(); |
837 | } |
838 | |
839 | llvm_unreachable("Case unhandled" ); |
840 | } |
841 | |
842 | /// Determines whether an operand tree can be forwarded. Previous evaluations |
843 | /// are cached. |
844 | /// |
845 | /// @param TargetStmt The statement the operand tree will be copied to. |
846 | /// @param UseVal The value (usually an instruction) which is root of an |
847 | /// operand tree. |
848 | /// @param UseStmt The statement that uses @p UseVal. |
849 | /// @param UseLoop The loop @p UseVal is used in. |
850 | /// |
851 | /// @return FD_CannotForward if @p UseVal cannot be forwarded. |
852 | /// FD_CanForwardLeaf if @p UseVal is forwardable, but not |
853 | /// profitable. |
854 | /// FD_CanForwardProfitably if @p UseVal is forwardable and useful to |
855 | /// do. |
856 | ForwardingDecision forwardTree(ScopStmt *TargetStmt, Value *UseVal, |
857 | ScopStmt *UseStmt, Loop *UseLoop) { |
858 | // Lookup any cached evaluation. |
859 | auto It = ForwardingActions.find(Val: {UseVal, UseStmt}); |
860 | if (It != ForwardingActions.end()) |
861 | return It->second.Decision; |
862 | |
863 | // Make a new evaluation. |
864 | ForwardingAction Action = |
865 | forwardTreeImpl(TargetStmt, UseVal, UseStmt, UseLoop); |
866 | ForwardingDecision Result = Action.Decision; |
867 | |
868 | // Remember for the next time. |
869 | assert(!ForwardingActions.count({UseVal, UseStmt}) && |
870 | "circular dependency?" ); |
871 | ForwardingActions.insert(KV: {{UseVal, UseStmt}, std::move(Action)}); |
872 | |
873 | return Result; |
874 | } |
875 | |
876 | /// Forward an operand tree using cached actions. |
877 | /// |
878 | /// @param Stmt Statement the operand tree is moved into. |
879 | /// @param UseVal Root of the operand tree within @p Stmt. |
880 | /// @param RA The MemoryAccess for @p UseVal that the forwarding intends |
881 | /// to remove. |
882 | void applyForwardingActions(ScopStmt *Stmt, Value *UseVal, MemoryAccess *RA) { |
883 | using ChildItTy = |
884 | decltype(std::declval<ForwardingAction>().Depends.begin()); |
885 | using EdgeTy = std::pair<ForwardingAction *, ChildItTy>; |
886 | |
887 | DenseSet<ForwardingAction::KeyTy> Visited; |
888 | SmallVector<EdgeTy, 32> Stack; |
889 | SmallVector<ForwardingAction *, 32> Ordered; |
890 | |
891 | // Seed the tree search using the root value. |
892 | assert(ForwardingActions.count({UseVal, Stmt})); |
893 | ForwardingAction *RootAction = &ForwardingActions[{UseVal, Stmt}]; |
894 | Stack.emplace_back(Args&: RootAction, Args: RootAction->Depends.begin()); |
895 | |
896 | // Compute the postorder of the operand tree: all operands of an instruction |
897 | // must be visited before the instruction itself. As an additional |
898 | // requirement, the topological ordering must be 'compact': Any subtree node |
899 | // must not be interleaved with nodes from a non-shared subtree. This is |
900 | // because the same llvm::Instruction can be materialized multiple times as |
901 | // used at different ScopStmts which might be different values. Intersecting |
902 | // these lifetimes may result in miscompilations. |
903 | // FIXME: Intersecting lifetimes might still be possible for the roots |
904 | // themselves, since instructions are just prepended to a ScopStmt's |
905 | // instruction list. |
906 | while (!Stack.empty()) { |
907 | EdgeTy &Top = Stack.back(); |
908 | ForwardingAction *TopAction = Top.first; |
909 | ChildItTy &TopEdge = Top.second; |
910 | |
911 | if (TopEdge == TopAction->Depends.end()) { |
912 | // Postorder sorting |
913 | Ordered.push_back(Elt: TopAction); |
914 | Stack.pop_back(); |
915 | continue; |
916 | } |
917 | ForwardingAction::KeyTy Key = *TopEdge; |
918 | |
919 | // Next edge for this level |
920 | ++TopEdge; |
921 | |
922 | auto VisitIt = Visited.insert(V: Key); |
923 | if (!VisitIt.second) |
924 | continue; |
925 | |
926 | assert(ForwardingActions.count(Key) && |
927 | "Must not insert new actions during execution phase" ); |
928 | ForwardingAction *ChildAction = &ForwardingActions[Key]; |
929 | Stack.emplace_back(Args&: ChildAction, Args: ChildAction->Depends.begin()); |
930 | } |
931 | |
932 | // Actually, we need the reverse postorder because actions prepend new |
933 | // instructions. Therefore, the first one will always be the action for the |
934 | // operand tree's root. |
935 | assert(Ordered.back() == RootAction); |
936 | if (RootAction->Execute()) |
937 | Stmt->removeSingleMemoryAccess(MA: RA); |
938 | Ordered.pop_back(); |
939 | for (auto DepAction : reverse(C&: Ordered)) { |
940 | assert(DepAction->Decision != FD_Unknown && |
941 | DepAction->Decision != FD_CannotForward); |
942 | assert(DepAction != RootAction); |
943 | DepAction->Execute(); |
944 | } |
945 | } |
946 | |
947 | /// Try to forward an operand tree rooted in @p RA. |
948 | bool tryForwardTree(MemoryAccess *RA) { |
949 | assert(RA->isLatestScalarKind()); |
950 | POLLY_DEBUG(dbgs() << "Trying to forward operand tree " << RA << "...\n" ); |
951 | |
952 | ScopStmt *Stmt = RA->getStatement(); |
953 | Loop *InLoop = Stmt->getSurroundingLoop(); |
954 | |
955 | isl::map TargetToUse; |
956 | if (!Known.is_null()) { |
957 | isl::space DomSpace = Stmt->getDomainSpace(); |
958 | TargetToUse = |
959 | isl::map::identity(space: DomSpace.map_from_domain_and_range(range: DomSpace)); |
960 | } |
961 | |
962 | ForwardingDecision Assessment = |
963 | forwardTree(TargetStmt: Stmt, UseVal: RA->getAccessValue(), UseStmt: Stmt, UseLoop: InLoop); |
964 | |
965 | // If considered feasible and profitable, forward it. |
966 | bool Changed = false; |
967 | if (Assessment == FD_CanForwardProfitably) { |
968 | applyForwardingActions(Stmt, UseVal: RA->getAccessValue(), RA); |
969 | Changed = true; |
970 | } |
971 | |
972 | ForwardingActions.clear(); |
973 | return Changed; |
974 | } |
975 | |
976 | /// Return which SCoP this instance is processing. |
977 | Scop *getScop() const { return S; } |
978 | |
979 | /// Run the algorithm: Use value read accesses as operand tree roots and try |
980 | /// to forward them into the statement. |
981 | bool forwardOperandTrees() { |
982 | for (ScopStmt &Stmt : *S) { |
983 | bool StmtModified = false; |
984 | |
985 | // Because we are modifying the MemoryAccess list, collect them first to |
986 | // avoid iterator invalidation. |
987 | SmallVector<MemoryAccess *, 16> Accs(Stmt.begin(), Stmt.end()); |
988 | |
989 | for (MemoryAccess *RA : Accs) { |
990 | if (!RA->isRead()) |
991 | continue; |
992 | if (!RA->isLatestScalarKind()) |
993 | continue; |
994 | |
995 | if (tryForwardTree(RA)) { |
996 | Modified = true; |
997 | StmtModified = true; |
998 | NumForwardedTrees++; |
999 | TotalForwardedTrees++; |
1000 | } |
1001 | } |
1002 | |
1003 | if (StmtModified) { |
1004 | NumModifiedStmts++; |
1005 | TotalModifiedStmts++; |
1006 | } |
1007 | } |
1008 | |
1009 | if (Modified) { |
1010 | ScopsModified++; |
1011 | S->realignParams(); |
1012 | } |
1013 | return Modified; |
1014 | } |
1015 | |
1016 | /// Print the pass result, performed transformations and the SCoP after the |
1017 | /// transformation. |
1018 | void print(raw_ostream &OS, int Indent = 0) { |
1019 | printStatistics(OS, Indent); |
1020 | |
1021 | if (!Modified) { |
1022 | // This line can easily be checked in regression tests. |
1023 | OS << "ForwardOpTree executed, but did not modify anything\n" ; |
1024 | return; |
1025 | } |
1026 | |
1027 | printStatements(OS, Indent); |
1028 | } |
1029 | |
1030 | bool isModified() const { return Modified; } |
1031 | }; |
1032 | |
1033 | static std::unique_ptr<ForwardOpTreeImpl> runForwardOpTree(Scop &S, |
1034 | LoopInfo &LI) { |
1035 | std::unique_ptr<ForwardOpTreeImpl> Impl; |
1036 | { |
1037 | IslMaxOperationsGuard MaxOpGuard(S.getIslCtx().get(), MaxOps, false); |
1038 | Impl = std::make_unique<ForwardOpTreeImpl>(args: &S, args: &LI, args&: MaxOpGuard); |
1039 | |
1040 | if (AnalyzeKnown) { |
1041 | POLLY_DEBUG(dbgs() << "Prepare forwarders...\n" ); |
1042 | Impl->computeKnownValues(); |
1043 | } |
1044 | |
1045 | POLLY_DEBUG(dbgs() << "Forwarding operand trees...\n" ); |
1046 | Impl->forwardOperandTrees(); |
1047 | |
1048 | if (MaxOpGuard.hasQuotaExceeded()) { |
1049 | POLLY_DEBUG(dbgs() << "Not all operations completed because of " |
1050 | "max_operations exceeded\n" ); |
1051 | KnownOutOfQuota++; |
1052 | } |
1053 | } |
1054 | |
1055 | POLLY_DEBUG(dbgs() << "\nFinal Scop:\n" ); |
1056 | POLLY_DEBUG(dbgs() << S); |
1057 | |
1058 | // Update statistics |
1059 | Scop::ScopStatistics ScopStats = S.getStatistics(); |
1060 | NumValueWrites += ScopStats.NumValueWrites; |
1061 | NumValueWritesInLoops += ScopStats.NumValueWritesInLoops; |
1062 | NumPHIWrites += ScopStats.NumPHIWrites; |
1063 | NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops; |
1064 | NumSingletonWrites += ScopStats.NumSingletonWrites; |
1065 | NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops; |
1066 | |
1067 | return Impl; |
1068 | } |
1069 | |
1070 | static PreservedAnalyses |
1071 | runForwardOpTreeUsingNPM(Scop &S, ScopAnalysisManager &SAM, |
1072 | ScopStandardAnalysisResults &SAR, SPMUpdater &U, |
1073 | raw_ostream *OS) { |
1074 | LoopInfo &LI = SAR.LI; |
1075 | |
1076 | std::unique_ptr<ForwardOpTreeImpl> Impl = runForwardOpTree(S, LI); |
1077 | if (OS) { |
1078 | *OS << "Printing analysis 'Polly - Forward operand tree' for region: '" |
1079 | << S.getName() << "' in function '" << S.getFunction().getName() |
1080 | << "':\n" ; |
1081 | if (Impl) { |
1082 | assert(Impl->getScop() == &S); |
1083 | |
1084 | Impl->print(OS&: *OS); |
1085 | } |
1086 | } |
1087 | |
1088 | if (!Impl->isModified()) |
1089 | return PreservedAnalyses::all(); |
1090 | |
1091 | PreservedAnalyses PA; |
1092 | PA.preserveSet<AllAnalysesOn<Module>>(); |
1093 | PA.preserveSet<AllAnalysesOn<Function>>(); |
1094 | PA.preserveSet<AllAnalysesOn<Loop>>(); |
1095 | return PA; |
1096 | } |
1097 | |
1098 | /// Pass that redirects scalar reads to array elements that are known to contain |
1099 | /// the same value. |
1100 | /// |
1101 | /// This reduces the number of scalar accesses and therefore potentially |
1102 | /// increases the freedom of the scheduler. In the ideal case, all reads of a |
1103 | /// scalar definition are redirected (We currently do not care about removing |
1104 | /// the write in this case). This is also useful for the main DeLICM pass as |
1105 | /// there are less scalars to be mapped. |
1106 | class ForwardOpTreeWrapperPass final : public ScopPass { |
1107 | private: |
1108 | /// The pass implementation, also holding per-scop data. |
1109 | std::unique_ptr<ForwardOpTreeImpl> Impl; |
1110 | |
1111 | public: |
1112 | static char ID; |
1113 | |
1114 | explicit ForwardOpTreeWrapperPass() : ScopPass(ID) {} |
1115 | ForwardOpTreeWrapperPass(const ForwardOpTreeWrapperPass &) = delete; |
1116 | ForwardOpTreeWrapperPass & |
1117 | operator=(const ForwardOpTreeWrapperPass &) = delete; |
1118 | |
1119 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
1120 | AU.addRequiredTransitive<ScopInfoRegionPass>(); |
1121 | AU.addRequired<LoopInfoWrapperPass>(); |
1122 | AU.setPreservesAll(); |
1123 | } |
1124 | |
1125 | bool runOnScop(Scop &S) override { |
1126 | // Free resources for previous SCoP's computation, if not yet done. |
1127 | releaseMemory(); |
1128 | |
1129 | LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); |
1130 | |
1131 | Impl = runForwardOpTree(S, LI); |
1132 | |
1133 | return false; |
1134 | } |
1135 | |
1136 | void printScop(raw_ostream &OS, Scop &S) const override { |
1137 | if (!Impl) |
1138 | return; |
1139 | |
1140 | assert(Impl->getScop() == &S); |
1141 | Impl->print(OS); |
1142 | } |
1143 | |
1144 | void releaseMemory() override { Impl.reset(); } |
1145 | }; // class ForwardOpTree |
1146 | |
1147 | char ForwardOpTreeWrapperPass::ID; |
1148 | |
1149 | /// Print result from ForwardOpTreeWrapperPass. |
1150 | class ForwardOpTreePrinterLegacyPass final : public ScopPass { |
1151 | public: |
1152 | static char ID; |
1153 | |
1154 | ForwardOpTreePrinterLegacyPass() : ForwardOpTreePrinterLegacyPass(outs()) {} |
1155 | explicit ForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS) |
1156 | : ScopPass(ID), OS(OS) {} |
1157 | |
1158 | bool runOnScop(Scop &S) override { |
1159 | ForwardOpTreeWrapperPass &P = getAnalysis<ForwardOpTreeWrapperPass>(); |
1160 | |
1161 | OS << "Printing analysis '" << P.getPassName() << "' for region: '" |
1162 | << S.getRegion().getNameStr() << "' in function '" |
1163 | << S.getFunction().getName() << "':\n" ; |
1164 | P.printScop(OS, S); |
1165 | |
1166 | return false; |
1167 | } |
1168 | |
1169 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
1170 | ScopPass::getAnalysisUsage(AU); |
1171 | AU.addRequired<ForwardOpTreeWrapperPass>(); |
1172 | AU.setPreservesAll(); |
1173 | } |
1174 | |
1175 | private: |
1176 | llvm::raw_ostream &OS; |
1177 | }; |
1178 | |
1179 | char ForwardOpTreePrinterLegacyPass::ID = 0; |
1180 | } // namespace |
1181 | |
1182 | Pass *polly::createForwardOpTreeWrapperPass() { |
1183 | return new ForwardOpTreeWrapperPass(); |
1184 | } |
1185 | |
1186 | Pass *polly::createForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS) { |
1187 | return new ForwardOpTreePrinterLegacyPass(OS); |
1188 | } |
1189 | |
1190 | llvm::PreservedAnalyses ForwardOpTreePass::run(Scop &S, |
1191 | ScopAnalysisManager &SAM, |
1192 | ScopStandardAnalysisResults &SAR, |
1193 | SPMUpdater &U) { |
1194 | return runForwardOpTreeUsingNPM(S, SAM, SAR, U, OS: nullptr); |
1195 | } |
1196 | |
1197 | llvm::PreservedAnalyses |
1198 | ForwardOpTreePrinterPass::run(Scop &S, ScopAnalysisManager &SAM, |
1199 | ScopStandardAnalysisResults &SAR, SPMUpdater &U) { |
1200 | return runForwardOpTreeUsingNPM(S, SAM, SAR, U, OS: &OS); |
1201 | } |
1202 | |
1203 | INITIALIZE_PASS_BEGIN(ForwardOpTreeWrapperPass, "polly-optree" , |
1204 | "Polly - Forward operand tree" , false, false) |
1205 | INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) |
1206 | INITIALIZE_PASS_END(ForwardOpTreeWrapperPass, "polly-optree" , |
1207 | "Polly - Forward operand tree" , false, false) |
1208 | |
1209 | INITIALIZE_PASS_BEGIN(ForwardOpTreePrinterLegacyPass, "polly-print-optree" , |
1210 | "Polly - Print forward operand tree result" , false, false) |
1211 | INITIALIZE_PASS_DEPENDENCY(ForwardOpTreeWrapperPass) |
1212 | INITIALIZE_PASS_END(ForwardOpTreePrinterLegacyPass, "polly-print-optree" , |
1213 | "Polly - Print forward operand tree result" , false, false) |
1214 | |