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