Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/LICM.h"
9 #include <stdio.h>
11 #include "jit/IonSpewer.h"
12 #include "jit/MIR.h"
13 #include "jit/MIRGenerator.h"
14 #include "jit/MIRGraph.h"
16 using namespace js;
17 using namespace js::jit;
19 namespace {
21 typedef Vector<MInstruction*, 1, IonAllocPolicy> InstructionQueue;
23 class Loop
24 {
25 MIRGenerator *mir;
27 public:
28 // Loop code may return three values:
29 enum LoopReturn {
30 LoopReturn_Success,
31 LoopReturn_Error, // Compilation failure.
32 LoopReturn_Skip // The loop is not suitable for LICM, but there is no error.
33 };
35 public:
36 // A loop is constructed on a backedge found in the control flow graph.
37 Loop(MIRGenerator *mir, MBasicBlock *footer);
39 // Initializes the loop, finds all blocks and instructions contained in the loop.
40 LoopReturn init();
42 // Identifies hoistable loop invariant instructions and moves them out of the loop.
43 bool optimize();
45 private:
46 // These blocks define the loop. header_ points to the loop header
47 MBasicBlock *header_;
49 // The pre-loop block is the first predecessor of the loop header. It is where
50 // the loop is first entered and where hoisted instructions will be placed.
51 MBasicBlock* preLoop_;
53 // This indicates whether the loop contains calls or other things which
54 // clobber most or all floating-point registers. In such loops,
55 // floating-point constants should not be hoisted unless it enables further
56 // hoisting.
57 bool containsPossibleCall_;
59 TempAllocator &alloc() const {
60 return mir->alloc();
61 }
63 bool hoistInstructions(InstructionQueue &toHoist);
65 // Utility methods for invariance testing and instruction hoisting.
66 bool isInLoop(MDefinition *ins);
67 bool isBeforeLoop(MDefinition *ins);
68 bool isLoopInvariant(MInstruction *ins);
70 // This method determines if this block hot within a loop. That is, if it's
71 // always or usually run when the loop executes
72 bool checkHotness(MBasicBlock *block);
74 // Worklist and worklist usage methods
75 InstructionQueue worklist_;
76 bool insertInWorklist(MInstruction *ins);
77 MInstruction* popFromWorklist();
79 inline bool isHoistable(const MDefinition *ins) const {
80 return ins->isMovable() && !ins->isEffectful() && !ins->neverHoist();
81 }
83 bool requiresHoistedUse(const MDefinition *ins) const;
84 };
86 } /* namespace anonymous */
88 LICM::LICM(MIRGenerator *mir, MIRGraph &graph)
89 : mir(mir), graph(graph)
90 {
91 }
93 bool
94 LICM::analyze()
95 {
96 IonSpew(IonSpew_LICM, "Beginning LICM pass.");
98 // Iterate in RPO to visit outer loops before inner loops.
99 for (ReversePostorderIterator i(graph.rpoBegin()); i != graph.rpoEnd(); i++) {
100 MBasicBlock *header = *i;
102 // Skip non-headers and self-loops.
103 if (!header->isLoopHeader() || header->numPredecessors() < 2)
104 continue;
106 // Attempt to optimize loop.
107 Loop loop(mir, header);
109 Loop::LoopReturn lr = loop.init();
110 if (lr == Loop::LoopReturn_Error)
111 return false;
112 if (lr == Loop::LoopReturn_Skip) {
113 graph.unmarkBlocks();
114 continue;
115 }
117 if (!loop.optimize())
118 return false;
120 graph.unmarkBlocks();
121 }
123 return true;
124 }
126 Loop::Loop(MIRGenerator *mir, MBasicBlock *header)
127 : mir(mir),
128 header_(header),
129 containsPossibleCall_(false),
130 worklist_(mir->alloc())
131 {
132 preLoop_ = header_->getPredecessor(0);
133 }
135 Loop::LoopReturn
136 Loop::init()
137 {
138 IonSpew(IonSpew_LICM, "Loop identified, headed by block %d", header_->id());
139 IonSpew(IonSpew_LICM, "footer is block %d", header_->backedge()->id());
141 // The first predecessor of the loop header must dominate the header.
142 JS_ASSERT(header_->id() > header_->getPredecessor(0)->id());
144 // Loops from backedge to header and marks all visited blocks
145 // as part of the loop. At the same time add all hoistable instructions
146 // (in RPO order) to the instruction worklist.
147 Vector<MBasicBlock *, 1, IonAllocPolicy> inlooplist(alloc());
148 if (!inlooplist.append(header_->backedge()))
149 return LoopReturn_Error;
150 header_->backedge()->mark();
152 while (!inlooplist.empty()) {
153 MBasicBlock *block = inlooplist.back();
155 // Hoisting requires more finesse if the loop contains a block that
156 // self-dominates: there exists control flow that may enter the loop
157 // without passing through the loop preheader.
158 //
159 // Rather than perform a complicated analysis of the dominance graph,
160 // just return a soft error to ignore this loop.
161 if (block->immediateDominator() == block) {
162 while (!worklist_.empty())
163 popFromWorklist();
164 return LoopReturn_Skip;
165 }
167 // Add not yet visited predecessors to the inlooplist.
168 if (block != header_) {
169 for (size_t i = 0; i < block->numPredecessors(); i++) {
170 MBasicBlock *pred = block->getPredecessor(i);
171 if (pred->isMarked())
172 continue;
174 if (!inlooplist.append(pred))
175 return LoopReturn_Error;
176 pred->mark();
177 }
178 }
180 // If any block was added, process them first.
181 if (block != inlooplist.back())
182 continue;
184 // Add all instructions in this block (but the control instruction) to the worklist
185 for (MInstructionIterator i = block->begin(); i != block->end(); i++) {
186 MInstruction *ins = *i;
188 // Remember whether this loop contains anything which clobbers most
189 // or all floating-point registers. This is just a rough heuristic.
190 if (ins->possiblyCalls())
191 containsPossibleCall_ = true;
193 if (isHoistable(ins)) {
194 if (!insertInWorklist(ins))
195 return LoopReturn_Error;
196 }
197 }
199 // All successors of this block are visited.
200 inlooplist.popBack();
201 }
203 return LoopReturn_Success;
204 }
206 bool
207 Loop::optimize()
208 {
209 InstructionQueue invariantInstructions(alloc());
211 IonSpew(IonSpew_LICM, "These instructions are in the loop: ");
213 while (!worklist_.empty()) {
214 if (mir->shouldCancel("LICM (worklist)"))
215 return false;
217 MInstruction *ins = popFromWorklist();
219 IonSpewHeader(IonSpew_LICM);
221 if (IonSpewEnabled(IonSpew_LICM)) {
222 ins->printName(IonSpewFile);
223 fprintf(IonSpewFile, " <- ");
224 ins->printOpcode(IonSpewFile);
225 fprintf(IonSpewFile, ": ");
226 }
228 if (isLoopInvariant(ins)) {
229 // Flag this instruction as loop invariant.
230 ins->setLoopInvariant();
231 if (!invariantInstructions.append(ins))
232 return false;
234 if (IonSpewEnabled(IonSpew_LICM))
235 fprintf(IonSpewFile, " Loop Invariant!\n");
236 }
237 }
239 if (!hoistInstructions(invariantInstructions))
240 return false;
241 return true;
242 }
244 bool
245 Loop::requiresHoistedUse(const MDefinition *ins) const
246 {
247 if (ins->isConstantElements() || ins->isBox())
248 return true;
250 // Integer constants can often be folded as immediates and aren't worth
251 // hoisting on their own, in general. Floating-point constants typically
252 // are worth hoisting, unless they'll end up being spilled (eg. due to a
253 // call).
254 if (ins->isConstant() && (IsFloatingPointType(ins->type()) || containsPossibleCall_))
255 return true;
257 return false;
258 }
260 bool
261 Loop::hoistInstructions(InstructionQueue &toHoist)
262 {
263 // Iterate in post-order (uses before definitions)
264 for (int32_t i = toHoist.length() - 1; i >= 0; i--) {
265 MInstruction *ins = toHoist[i];
267 // Don't hoist a cheap constant if it doesn't enable us to hoist one of
268 // its uses. We want those instructions as close as possible to their
269 // use, to facilitate folding and minimize register pressure.
270 if (requiresHoistedUse(ins)) {
271 bool loopInvariantUse = false;
272 for (MUseDefIterator use(ins); use; use++) {
273 if (use.def()->isLoopInvariant()) {
274 loopInvariantUse = true;
275 break;
276 }
277 }
279 if (!loopInvariantUse)
280 ins->setNotLoopInvariant();
281 }
282 }
284 // Move all instructions to the preLoop_ block just before the control instruction.
285 for (size_t i = 0; i < toHoist.length(); i++) {
286 MInstruction *ins = toHoist[i];
288 // Loads may have an implicit dependency on either stores (effectful instructions) or
289 // control instructions so we should never move these.
290 JS_ASSERT(!ins->isControlInstruction());
291 JS_ASSERT(!ins->isEffectful());
292 JS_ASSERT(ins->isMovable());
294 if (!ins->isLoopInvariant())
295 continue;
297 if (checkHotness(ins->block())) {
298 ins->block()->moveBefore(preLoop_->lastIns(), ins);
299 ins->setNotLoopInvariant();
300 }
301 }
303 return true;
304 }
306 bool
307 Loop::isInLoop(MDefinition *ins)
308 {
309 return ins->block()->isMarked();
310 }
312 bool
313 Loop::isBeforeLoop(MDefinition *ins)
314 {
315 return ins->block()->id() < header_->id();
316 }
318 bool
319 Loop::isLoopInvariant(MInstruction *ins)
320 {
321 if (!isHoistable(ins)) {
322 if (IonSpewEnabled(IonSpew_LICM))
323 fprintf(IonSpewFile, "not hoistable\n");
324 return false;
325 }
327 // Don't hoist if this instruction depends on a store inside or after the loop.
328 // Note: "after the loop" can sound strange, but Alias Analysis doesn't look
329 // at the control flow. Therefore it doesn't match the definition here, that a block
330 // is in the loop when there is a (directed) path from the block to the loop header.
331 if (ins->dependency() && !isBeforeLoop(ins->dependency())) {
332 if (IonSpewEnabled(IonSpew_LICM)) {
333 fprintf(IonSpewFile, "depends on store inside or after loop: ");
334 ins->dependency()->printName(IonSpewFile);
335 fprintf(IonSpewFile, "\n");
336 }
337 return false;
338 }
340 // An instruction is only loop invariant if it and all of its operands can
341 // be safely hoisted into the loop preheader.
342 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
343 if (isInLoop(ins->getOperand(i)) &&
344 !ins->getOperand(i)->isLoopInvariant()) {
346 if (IonSpewEnabled(IonSpew_LICM)) {
347 ins->getOperand(i)->printName(IonSpewFile);
348 fprintf(IonSpewFile, " is in the loop.\n");
349 }
351 return false;
352 }
353 }
355 return true;
356 }
358 bool
359 Loop::checkHotness(MBasicBlock *block)
360 {
361 // TODO: determine if instructions within this block are worth hoisting.
362 // They might not be if the block is cold enough within the loop.
363 // BUG 669517
364 return true;
365 }
367 bool
368 Loop::insertInWorklist(MInstruction *ins)
369 {
370 if (!worklist_.insert(worklist_.begin(), ins))
371 return false;
372 ins->setInWorklist();
373 return true;
374 }
376 MInstruction*
377 Loop::popFromWorklist()
378 {
379 MInstruction* toReturn = worklist_.popCopy();
380 toReturn->setNotInWorklist();
381 return toReturn;
382 }