blob: fe5a6311af8399a979f9e3bef3dbf28aab03f97a [file] [log] [blame]
Michael Krusea6b2de32017-07-22 14:02:47 +00001//===------ ForwardOpTree.h -------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Move instructions between statements.
11//
12//===----------------------------------------------------------------------===//
13
14#include "polly/ForwardOpTree.h"
15
Michael Kruse07e8c362017-07-24 12:43:27 +000016#include "polly/ScopBuilder.h"
Michael Krusea6b2de32017-07-22 14:02:47 +000017#include "polly/ScopInfo.h"
18#include "polly/ScopPass.h"
19#include "polly/Support/GICHelper.h"
20#include "polly/Support/VirtualInstruction.h"
21#include "llvm/Analysis/ValueTracking.h"
22
23#define DEBUG_TYPE "polly-delicm"
24
25using namespace polly;
26using namespace llvm;
27
28STATISTIC(TotalInstructionsCopied, "Number of copied instructions");
Michael Kruse07e8c362017-07-24 12:43:27 +000029STATISTIC(TotalReadOnlyCopied, "Number of copied read-only accesses");
Michael Krusea6b2de32017-07-22 14:02:47 +000030STATISTIC(TotalForwardedTrees, "Number of forwarded operand trees");
31STATISTIC(TotalModifiedStmts,
32 "Number of statements with at least one forwarded tree");
33
34STATISTIC(ScopsModified, "Number of SCoPs with at least one forwarded tree");
35
36namespace {
37
38/// The state of whether an operand tree was/can be forwarded.
39enum ForwardingDecision {
40 FD_CannotForward,
41 FD_CanForward,
Michael Kruse07e8c362017-07-24 12:43:27 +000042 FD_CanForwardTree,
Michael Krusea6b2de32017-07-22 14:02:47 +000043 FD_DidForward,
44};
45
46/// Implementation of operand tree forwarding for a specific SCoP.
47///
48/// For a statement that requires a scalar value (through a value read
49/// MemoryAccess), see if its operand can be moved into the statement. If so,
50/// the MemoryAccess is removed and the all the operand tree instructions are
51/// moved into the statement. All original instructions are left in the source
52/// statements. The simplification pass can clean these up.
53class ForwardOpTreeImpl {
54private:
55 /// The SCoP we are currently processing.
56 Scop *S;
57
58 /// LoopInfo is required for VirtualUse.
59 LoopInfo *LI;
60
61 /// How many instructions have been copied to other statements.
62 int NumInstructionsCopied = 0;
63
Michael Kruse07e8c362017-07-24 12:43:27 +000064 /// How many read-only accesses have been copied.
65 int NumReadOnlyCopied = 0;
66
Michael Krusea6b2de32017-07-22 14:02:47 +000067 /// How many operand trees have been forwarded.
68 int NumForwardedTrees = 0;
69
70 /// Number of statements with at least one forwarded operand tree.
71 int NumModifiedStmts = 0;
72
73 /// Whether we carried out at least one change to the SCoP.
74 bool Modified = false;
75
76 void printStatistics(raw_ostream &OS, int Indent = 0) {
77 OS.indent(Indent) << "Statistics {\n";
78 OS.indent(Indent + 4) << "Instructions copied: " << NumInstructionsCopied
79 << '\n';
Michael Kruse07e8c362017-07-24 12:43:27 +000080 OS.indent(Indent + 4) << "Read-only accesses copied: " << NumReadOnlyCopied
81 << '\n';
Michael Krusea6b2de32017-07-22 14:02:47 +000082 OS.indent(Indent + 4) << "Operand trees forwarded: " << NumForwardedTrees
83 << '\n';
84 OS.indent(Indent + 4) << "Statements with forwarded operand trees: "
85 << NumModifiedStmts << '\n';
86 OS.indent(Indent) << "}\n";
87 }
88
89 void printStatements(llvm::raw_ostream &OS, int Indent = 0) const {
90 OS.indent(Indent) << "After statements {\n";
91 for (auto &Stmt : *S) {
92 OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
93 for (auto *MA : Stmt)
94 MA->print(OS);
95
96 OS.indent(Indent + 12);
97 Stmt.printInstructions(OS);
98 }
99 OS.indent(Indent) << "}\n";
100 }
101
102 /// Determines whether an operand tree can be forwarded or carries out a
103 /// forwarding, depending on the @p DoIt flag.
104 ///
105 /// @param TargetStmt The statement the operand tree will be copied to.
106 /// @param UseVal The value (usually an instruction) which is root of an
107 /// operand tree.
108 /// @param UseStmt The statement that uses @p UseVal.
109 /// @param UseLoop The loop @p UseVal is used in.
110 /// @param DoIt If false, only determine whether an operand tree can be
111 /// forwarded. If true, carry out the forwarding. Do not use
112 /// DoIt==true if an operand tree is not known to be
113 /// forwardable.
114 ///
Michael Kruse5b8a9092017-07-24 12:39:46 +0000115 /// @return If DoIt==false, return whether the operand tree can be forwarded.
116 /// If DoIt==true, return FD_DidForward.
Michael Krusea6b2de32017-07-22 14:02:47 +0000117 ForwardingDecision canForwardTree(ScopStmt *TargetStmt, Value *UseVal,
118 ScopStmt *UseStmt, Loop *UseLoop,
119 bool DoIt) {
120
121 // PHis are not yet supported.
122 if (isa<PHINode>(UseVal)) {
123 DEBUG(dbgs() << " Cannot forward PHI: " << *UseVal << "\n");
124 return FD_CannotForward;
125 }
126
127 VirtualUse VUse = VirtualUse::create(UseStmt, UseLoop, UseVal, true);
128 switch (VUse.getKind()) {
129 case VirtualUse::Constant:
130 case VirtualUse::Block:
Michael Krusee5f47062017-07-22 14:30:02 +0000131 case VirtualUse::Hoisted:
Michael Krusea6b2de32017-07-22 14:02:47 +0000132 // These can be used anywhere without special considerations.
133 if (DoIt)
134 return FD_DidForward;
135 return FD_CanForward;
136
137 case VirtualUse::Synthesizable:
138 // Not supported yet.
139 DEBUG(dbgs() << " Cannot forward synthesizable: " << *UseVal << "\n");
140 return FD_CannotForward;
141
Michael Krusea6b2de32017-07-22 14:02:47 +0000142 case VirtualUse::ReadOnly:
Michael Kruse07e8c362017-07-24 12:43:27 +0000143 if (!DoIt)
144 return FD_CanForward;
145
146 // If we model read-only scalars, we need to create a MemoryAccess for it.
147 if (ModelReadOnlyScalars)
148 TargetStmt->ensureValueRead(UseVal);
149
150 NumReadOnlyCopied++;
151 TotalReadOnlyCopied++;
152 return FD_DidForward;
Michael Krusea6b2de32017-07-22 14:02:47 +0000153
154 case VirtualUse::Intra:
155 case VirtualUse::Inter:
156 auto Inst = cast<Instruction>(UseVal);
157
158 // Compatible instructions must satisfy the following conditions:
159 // 1. Idempotent (instruction will be copied, not moved; although its
160 // original instance might be removed by simplification)
161 // 2. Not access memory (There might be memory writes between)
162 // 3. Not cause undefined behaviour (we might copy to a location when the
163 // original instruction was no executed; this is currently not possible
164 // because we do not forward PHINodes)
165 // 4. Not leak memory if executed multiple times (I am looking at you,
166 // malloc!)
167 //
168 // Instruction::mayHaveSideEffects is not sufficient because it considers
169 // malloc to not have side-effects. llvm::isSafeToSpeculativelyExecute is
170 // not sufficient because it allows memory accesses.
171 if (mayBeMemoryDependent(*Inst)) {
172 DEBUG(dbgs() << " Cannot forward side-effect instruction: " << *Inst
173 << "\n");
174 return FD_CannotForward;
175 }
176
177 Loop *DefLoop = LI->getLoopFor(Inst->getParent());
178 ScopStmt *DefStmt = S->getStmtFor(Inst);
179 assert(DefStmt && "Value must be defined somewhere");
180
181 if (DoIt) {
182 // To ensure the right order, prepend this instruction before its
183 // operands. This ensures that its operands are inserted before the
184 // instruction using them.
185 // TODO: The operand tree is not really a tree, but a DAG. We should be
186 // able to handle DAGs without duplication.
Michael Kruse25a68812017-07-24 12:39:41 +0000187 TargetStmt->prependInstruction(Inst);
Michael Krusea6b2de32017-07-22 14:02:47 +0000188 NumInstructionsCopied++;
189 TotalInstructionsCopied++;
190 }
191
192 for (Value *OpVal : Inst->operand_values()) {
193 ForwardingDecision OpDecision =
194 canForwardTree(TargetStmt, OpVal, DefStmt, DefLoop, DoIt);
195 switch (OpDecision) {
196 case FD_CannotForward:
197 assert(!DoIt);
198 return FD_CannotForward;
199
200 case FD_CanForward:
Michael Kruse07e8c362017-07-24 12:43:27 +0000201 case FD_CanForwardTree:
Michael Krusea6b2de32017-07-22 14:02:47 +0000202 assert(!DoIt);
203 break;
204
205 case FD_DidForward:
206 assert(DoIt);
207 break;
208 }
209 }
210
211 if (DoIt)
212 return FD_DidForward;
Michael Kruse07e8c362017-07-24 12:43:27 +0000213 return FD_CanForwardTree;
Michael Krusea6b2de32017-07-22 14:02:47 +0000214 }
215
216 llvm_unreachable("Case unhandled");
217 }
218
219 /// Try to forward an operand tree rooted in @p RA.
220 bool tryForwardTree(MemoryAccess *RA) {
221 assert(RA->isLatestScalarKind());
222 DEBUG(dbgs() << "Trying to forward operand tree " << RA << "...\n");
223
224 ScopStmt *Stmt = RA->getStatement();
225 Loop *InLoop = Stmt->getSurroundingLoop();
226
227 ForwardingDecision Assessment =
228 canForwardTree(Stmt, RA->getAccessValue(), Stmt, InLoop, false);
229 assert(Assessment != FD_DidForward);
Michael Kruse07e8c362017-07-24 12:43:27 +0000230 if (Assessment != FD_CanForwardTree)
Michael Krusea6b2de32017-07-22 14:02:47 +0000231 return false;
232
233 ForwardingDecision Execution =
234 canForwardTree(Stmt, RA->getAccessValue(), Stmt, InLoop, true);
235 assert(Execution == FD_DidForward);
236
237 Stmt->removeSingleMemoryAccess(RA);
238 return true;
239 }
240
241public:
242 ForwardOpTreeImpl(Scop *S, LoopInfo *LI) : S(S), LI(LI) {}
243
244 /// Return which SCoP this instance is processing.
245 Scop *getScop() const { return S; }
246
247 /// Run the algorithm: Use value read accesses as operand tree roots and try
248 /// to forward them into the statement.
249 bool forwardOperandTrees() {
250 for (ScopStmt &Stmt : *S) {
251 // Currently we cannot modify the instruction list of region statements.
252 if (!Stmt.isBlockStmt())
253 continue;
254
255 bool StmtModified = false;
256
257 // Because we are modifying the MemoryAccess list, collect them first to
258 // avoid iterator invalidation.
259 SmallVector<MemoryAccess *, 16> Accs;
260 for (MemoryAccess *RA : Stmt) {
261 if (!RA->isRead())
262 continue;
263 if (!RA->isLatestScalarKind())
264 continue;
265
266 Accs.push_back(RA);
267 }
268
269 for (MemoryAccess *RA : Accs) {
270 if (tryForwardTree(RA)) {
271 Modified = true;
272 StmtModified = true;
273 NumForwardedTrees++;
274 TotalForwardedTrees++;
275 }
276 }
277
278 if (StmtModified) {
279 NumModifiedStmts++;
280 TotalModifiedStmts++;
281 }
282 }
283
284 if (Modified)
285 ScopsModified++;
286 return Modified;
287 }
288
289 /// Print the pass result, performed transformations and the SCoP after the
290 /// transformation.
291 void print(llvm::raw_ostream &OS, int Indent = 0) {
292 printStatistics(OS, Indent);
293
294 if (!Modified) {
295 // This line can easily be checked in regression tests.
296 OS << "ForwardOpTree executed, but did not modify anything\n";
297 return;
298 }
299
300 printStatements(OS, Indent);
301 }
302};
303
304/// Pass that redirects scalar reads to array elements that are known to contain
305/// the same value.
306///
307/// This reduces the number of scalar accesses and therefore potentially
308/// increases the freedom of the scheduler. In the ideal case, all reads of a
309/// scalar definition are redirected (We currently do not care about removing
310/// the write in this case). This is also useful for the main DeLICM pass as
311/// there are less scalars to be mapped.
312class ForwardOpTree : public ScopPass {
313private:
314 ForwardOpTree(const ForwardOpTree &) = delete;
315 const ForwardOpTree &operator=(const ForwardOpTree &) = delete;
316
317 /// The pass implementation, also holding per-scop data.
318 std::unique_ptr<ForwardOpTreeImpl> Impl;
319
320public:
321 static char ID;
322
323 explicit ForwardOpTree() : ScopPass(ID) {}
324
325 virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
326 AU.addRequiredTransitive<ScopInfoRegionPass>();
327 AU.addRequired<LoopInfoWrapperPass>();
328 AU.setPreservesAll();
329 }
330
331 virtual bool runOnScop(Scop &S) override {
332 // Free resources for previous SCoP's computation, if not yet done.
333 releaseMemory();
334
335 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
336 Impl = make_unique<ForwardOpTreeImpl>(&S, &LI);
337
338 DEBUG(dbgs() << "Forwarding operand trees...\n");
339 Impl->forwardOperandTrees();
340
341 DEBUG(dbgs() << "\nFinal Scop:\n");
342 DEBUG(dbgs() << S);
343
344 return false;
345 }
346
347 virtual void printScop(raw_ostream &OS, Scop &S) const override {
348 if (!Impl)
349 return;
350
351 assert(Impl->getScop() == &S);
352 Impl->print(OS);
353 }
354
355 virtual void releaseMemory() override { Impl.reset(); }
356
357}; // class ForwardOpTree
358
359char ForwardOpTree::ID;
360} // anonymous namespace
361
362ScopPass *polly::createForwardOpTreePass() { return new ForwardOpTree(); }
363
364INITIALIZE_PASS_BEGIN(ForwardOpTree, "polly-optree",
365 "Polly - Forward operand tree", false, false)
366INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
367INITIALIZE_PASS_END(ForwardOpTree, "polly-optree",
368 "Polly - Forward operand tree", false, false)