blob: 55e1a2c4090bc7c608c1ed6d33edef4e7baf2ca2 [file] [log] [blame]
Aart Bik281c6812016-08-26 11:31:48 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "loop_optimization.h"
18
Aart Bik96202302016-10-04 17:33:56 -070019#include "linear_order.h"
Aart Bik281c6812016-08-26 11:31:48 -070020
21namespace art {
22
Aart Bik9abf8942016-10-14 09:49:42 -070023// Remove the instruction from the graph. A bit more elaborate than the usual
24// instruction removal, since there may be a cycle in the use structure.
Aart Bik281c6812016-08-26 11:31:48 -070025static void RemoveFromCycle(HInstruction* instruction) {
Aart Bik281c6812016-08-26 11:31:48 -070026 instruction->RemoveAsUserOfAllInputs();
27 instruction->RemoveEnvironmentUsers();
28 instruction->GetBlock()->RemoveInstructionOrPhi(instruction, /*ensure_safety=*/ false);
29}
30
Aart Bike3dedc52016-11-02 17:50:27 -070031// Detects a goto block and sets succ to the single successor.
32static bool IsGotoBlock(HBasicBlock* block, /*out*/ HBasicBlock** succ) {
33 if (block->GetPredecessors().size() == 1 &&
34 block->GetSuccessors().size() == 1 &&
35 block->IsSingleGoto()) {
36 *succ = block->GetSingleSuccessor();
37 return true;
38 }
39 return false;
40}
41
Aart Bik281c6812016-08-26 11:31:48 -070042//
43// Class methods.
44//
45
46HLoopOptimization::HLoopOptimization(HGraph* graph,
47 HInductionVarAnalysis* induction_analysis)
48 : HOptimization(graph, kLoopOptimizationPassName),
49 induction_range_(induction_analysis),
Aart Bik96202302016-10-04 17:33:56 -070050 loop_allocator_(nullptr),
Aart Bik281c6812016-08-26 11:31:48 -070051 top_loop_(nullptr),
Aart Bik8c4a8542016-10-06 11:36:57 -070052 last_loop_(nullptr),
Aart Bik482095d2016-10-10 15:39:10 -070053 iset_(nullptr),
54 induction_simplication_count_(0) {
Aart Bik281c6812016-08-26 11:31:48 -070055}
56
57void HLoopOptimization::Run() {
58 // Well-behaved loops only.
59 // TODO: make this less of a sledgehammer.
Aart Bik96202302016-10-04 17:33:56 -070060 if (graph_->HasTryCatch() || graph_->HasIrreducibleLoops()) {
Aart Bik281c6812016-08-26 11:31:48 -070061 return;
62 }
63
Aart Bik96202302016-10-04 17:33:56 -070064 // Phase-local allocator that draws from the global pool. Since the allocator
65 // itself resides on the stack, it is destructed on exiting Run(), which
66 // implies its underlying memory is released immediately.
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010067 ArenaAllocator allocator(graph_->GetArena()->GetArenaPool());
Aart Bik96202302016-10-04 17:33:56 -070068 loop_allocator_ = &allocator;
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010069
Aart Bik96202302016-10-04 17:33:56 -070070 // Perform loop optimizations.
71 LocalRun();
72
73 // Detach.
74 loop_allocator_ = nullptr;
75 last_loop_ = top_loop_ = nullptr;
76}
77
78void HLoopOptimization::LocalRun() {
79 // Build the linear order using the phase-local allocator. This step enables building
80 // a loop hierarchy that properly reflects the outer-inner and previous-next relation.
81 ArenaVector<HBasicBlock*> linear_order(loop_allocator_->Adapter(kArenaAllocLinearOrder));
82 LinearizeGraph(graph_, loop_allocator_, &linear_order);
83
Aart Bik281c6812016-08-26 11:31:48 -070084 // Build the loop hierarchy.
Aart Bik96202302016-10-04 17:33:56 -070085 for (HBasicBlock* block : linear_order) {
Aart Bik281c6812016-08-26 11:31:48 -070086 if (block->IsLoopHeader()) {
87 AddLoop(block->GetLoopInformation());
88 }
89 }
Aart Bik96202302016-10-04 17:33:56 -070090
Aart Bik8c4a8542016-10-06 11:36:57 -070091 // Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use
92 // a temporary set that stores instructions using the phase-local allocator.
93 if (top_loop_ != nullptr) {
94 ArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
95 iset_ = &iset;
96 TraverseLoopsInnerToOuter(top_loop_);
97 iset_ = nullptr; // detach
98 }
Aart Bik281c6812016-08-26 11:31:48 -070099}
100
101void HLoopOptimization::AddLoop(HLoopInformation* loop_info) {
102 DCHECK(loop_info != nullptr);
Nicolas Geoffrayebe16742016-10-05 09:55:42 +0100103 LoopNode* node = new (loop_allocator_) LoopNode(loop_info); // phase-local allocator
Aart Bik281c6812016-08-26 11:31:48 -0700104 if (last_loop_ == nullptr) {
105 // First loop.
106 DCHECK(top_loop_ == nullptr);
107 last_loop_ = top_loop_ = node;
108 } else if (loop_info->IsIn(*last_loop_->loop_info)) {
109 // Inner loop.
110 node->outer = last_loop_;
111 DCHECK(last_loop_->inner == nullptr);
112 last_loop_ = last_loop_->inner = node;
113 } else {
114 // Subsequent loop.
115 while (last_loop_->outer != nullptr && !loop_info->IsIn(*last_loop_->outer->loop_info)) {
116 last_loop_ = last_loop_->outer;
117 }
118 node->outer = last_loop_->outer;
119 node->previous = last_loop_;
120 DCHECK(last_loop_->next == nullptr);
121 last_loop_ = last_loop_->next = node;
122 }
123}
124
125void HLoopOptimization::RemoveLoop(LoopNode* node) {
126 DCHECK(node != nullptr);
Aart Bik8c4a8542016-10-06 11:36:57 -0700127 DCHECK(node->inner == nullptr);
128 if (node->previous != nullptr) {
129 // Within sequence.
130 node->previous->next = node->next;
131 if (node->next != nullptr) {
132 node->next->previous = node->previous;
133 }
134 } else {
135 // First of sequence.
136 if (node->outer != nullptr) {
137 node->outer->inner = node->next;
138 } else {
139 top_loop_ = node->next;
140 }
141 if (node->next != nullptr) {
142 node->next->outer = node->outer;
143 node->next->previous = nullptr;
144 }
145 }
Aart Bik281c6812016-08-26 11:31:48 -0700146}
147
148void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) {
149 for ( ; node != nullptr; node = node->next) {
Aart Bik482095d2016-10-10 15:39:10 -0700150 int current_induction_simplification_count = induction_simplication_count_;
Aart Bik281c6812016-08-26 11:31:48 -0700151 if (node->inner != nullptr) {
152 TraverseLoopsInnerToOuter(node->inner);
153 }
Aart Bik482095d2016-10-10 15:39:10 -0700154 // Visit loop after its inner loops have been visited. If the induction of any inner
155 // loop has been simplified, recompute the induction information of this loop first.
156 if (current_induction_simplification_count != induction_simplication_count_) {
157 induction_range_.ReVisit(node->loop_info);
158 }
Aart Bik639cc8c2016-10-18 13:03:31 -0700159 SimplifyBlocks(node);
Aart Bik281c6812016-08-26 11:31:48 -0700160 SimplifyInduction(node);
Aart Bik482095d2016-10-10 15:39:10 -0700161 SimplifyBlocks(node);
Aart Bik9abf8942016-10-14 09:49:42 -0700162 if (node->inner == nullptr) {
163 RemoveIfEmptyInnerLoop(node);
164 }
Aart Bik281c6812016-08-26 11:31:48 -0700165 }
166}
167
168void HLoopOptimization::SimplifyInduction(LoopNode* node) {
169 HBasicBlock* header = node->loop_info->GetHeader();
170 HBasicBlock* preheader = node->loop_info->GetPreHeader();
Aart Bik8c4a8542016-10-06 11:36:57 -0700171 // Scan the phis in the header to find opportunities to simplify an induction
172 // cycle that is only used outside the loop. Replace these uses, if any, with
173 // the last value and remove the induction cycle.
174 // Examples: for (int i = 0; x != null; i++) { .... no i .... }
175 // for (int i = 0; i < 10; i++, k++) { .... no k .... } return k;
Aart Bik281c6812016-08-26 11:31:48 -0700176 for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) {
177 HPhi* phi = it.Current()->AsPhi();
Aart Bik8c4a8542016-10-06 11:36:57 -0700178 iset_->clear();
179 int32_t use_count = 0;
Aart Bikcc42be02016-10-20 16:14:16 -0700180 if (IsPhiInduction(phi) &&
Aart Bik482095d2016-10-10 15:39:10 -0700181 IsOnlyUsedAfterLoop(node->loop_info, phi, &use_count) &&
Aart Bik8c4a8542016-10-06 11:36:57 -0700182 TryReplaceWithLastValue(phi, use_count, preheader)) {
183 for (HInstruction* i : *iset_) {
184 RemoveFromCycle(i);
Aart Bik281c6812016-08-26 11:31:48 -0700185 }
Aart Bik482095d2016-10-10 15:39:10 -0700186 induction_simplication_count_++;
187 }
188 }
189}
190
191void HLoopOptimization::SimplifyBlocks(LoopNode* node) {
Aart Bike3dedc52016-11-02 17:50:27 -0700192 // Repeat the block simplifications until no more changes occur. Note that since
193 // each simplification consists of eliminating code (without introducing new code),
194 // this process is always finite.
195 bool changed;
196 do {
197 changed = false;
198 // Iterate over all basic blocks in the loop-body.
199 for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
200 HBasicBlock* block = it.Current();
201 // Remove dead instructions from the loop-body.
202 for (HBackwardInstructionIterator i(block->GetInstructions()); !i.Done(); i.Advance()) {
203 HInstruction* instruction = i.Current();
204 if (instruction->IsDeadAndRemovable()) {
205 changed = true;
206 block->RemoveInstruction(instruction);
207 }
Aart Bik482095d2016-10-10 15:39:10 -0700208 }
Aart Bike3dedc52016-11-02 17:50:27 -0700209 // Remove trivial control flow blocks from the loop-body.
210 HBasicBlock* succ = nullptr;
211 if (IsGotoBlock(block, &succ) && succ->GetPredecessors().size() == 1) {
212 // Trivial goto block can be removed.
213 HBasicBlock* pred = block->GetSinglePredecessor();
214 changed = true;
Aart Bik482095d2016-10-10 15:39:10 -0700215 pred->ReplaceSuccessor(block, succ);
Aart Bike3dedc52016-11-02 17:50:27 -0700216 block->RemoveDominatedBlock(succ);
Aart Bik482095d2016-10-10 15:39:10 -0700217 block->DisconnectAndDelete();
218 pred->AddDominatedBlock(succ);
219 succ->SetDominator(pred);
Aart Bike3dedc52016-11-02 17:50:27 -0700220 } else if (block->GetSuccessors().size() == 2) {
221 // Trivial if block can be bypassed to either branch.
222 HBasicBlock* succ0 = block->GetSuccessors()[0];
223 HBasicBlock* succ1 = block->GetSuccessors()[1];
224 HBasicBlock* meet0 = nullptr;
225 HBasicBlock* meet1 = nullptr;
226 if (succ0 != succ1 &&
227 IsGotoBlock(succ0, &meet0) &&
228 IsGotoBlock(succ1, &meet1) &&
229 meet0 == meet1 && // meets again
230 meet0 != block && // no self-loop
231 meet0->GetPhis().IsEmpty()) { // not used for merging
232 changed = true;
233 succ0->DisconnectAndDelete();
234 if (block->Dominates(meet0)) {
235 block->RemoveDominatedBlock(meet0);
236 succ1->AddDominatedBlock(meet0);
237 meet0->SetDominator(succ1);
238 }
239 }
Aart Bik482095d2016-10-10 15:39:10 -0700240 }
Aart Bik281c6812016-08-26 11:31:48 -0700241 }
Aart Bike3dedc52016-11-02 17:50:27 -0700242 } while (changed);
Aart Bik281c6812016-08-26 11:31:48 -0700243}
244
Aart Bik9abf8942016-10-14 09:49:42 -0700245void HLoopOptimization::RemoveIfEmptyInnerLoop(LoopNode* node) {
Aart Bik281c6812016-08-26 11:31:48 -0700246 HBasicBlock* header = node->loop_info->GetHeader();
247 HBasicBlock* preheader = node->loop_info->GetPreHeader();
Aart Bik9abf8942016-10-14 09:49:42 -0700248 // Ensure loop header logic is finite.
249 if (!induction_range_.IsFinite(node->loop_info)) {
250 return;
251 }
Aart Bik281c6812016-08-26 11:31:48 -0700252 // Ensure there is only a single loop-body (besides the header).
253 HBasicBlock* body = nullptr;
254 for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
255 if (it.Current() != header) {
256 if (body != nullptr) {
257 return;
258 }
259 body = it.Current();
260 }
261 }
262 // Ensure there is only a single exit point.
263 if (header->GetSuccessors().size() != 2) {
264 return;
265 }
266 HBasicBlock* exit = (header->GetSuccessors()[0] == body)
267 ? header->GetSuccessors()[1]
268 : header->GetSuccessors()[0];
Aart Bik8c4a8542016-10-06 11:36:57 -0700269 // Ensure exit can only be reached by exiting loop.
Aart Bik281c6812016-08-26 11:31:48 -0700270 if (exit->GetPredecessors().size() != 1) {
271 return;
272 }
Aart Bik8c4a8542016-10-06 11:36:57 -0700273 // Detect an empty loop: no side effects other than plain iteration. Replace
274 // subsequent index uses, if any, with the last value and remove the loop.
275 iset_->clear();
276 int32_t use_count = 0;
Aart Bikcc42be02016-10-20 16:14:16 -0700277 if (IsEmptyHeader(header) &&
278 IsEmptyBody(body) &&
Aart Bik482095d2016-10-10 15:39:10 -0700279 IsOnlyUsedAfterLoop(node->loop_info, header->GetFirstPhi(), &use_count) &&
Aart Bik8c4a8542016-10-06 11:36:57 -0700280 TryReplaceWithLastValue(header->GetFirstPhi(), use_count, preheader)) {
Aart Bik281c6812016-08-26 11:31:48 -0700281 body->DisconnectAndDelete();
282 exit->RemovePredecessor(header);
283 header->RemoveSuccessor(exit);
Aart Bike3dedc52016-11-02 17:50:27 -0700284 header->RemoveDominatedBlock(exit);
Aart Bik281c6812016-08-26 11:31:48 -0700285 header->DisconnectAndDelete();
Aart Bik482095d2016-10-10 15:39:10 -0700286 preheader->AddSuccessor(exit);
287 preheader->AddInstruction(new (graph_->GetArena()) HGoto()); // global allocator
288 preheader->AddDominatedBlock(exit);
289 exit->SetDominator(preheader);
Aart Bik281c6812016-08-26 11:31:48 -0700290 // Update hierarchy.
291 RemoveLoop(node);
292 }
293}
294
Aart Bikcc42be02016-10-20 16:14:16 -0700295bool HLoopOptimization::IsPhiInduction(HPhi* phi) {
296 ArenaSet<HInstruction*>* set = induction_range_.LookupCycle(phi);
297 if (set != nullptr) {
Aart Bike3dedc52016-11-02 17:50:27 -0700298 DCHECK(iset_->empty());
Aart Bikcc42be02016-10-20 16:14:16 -0700299 for (HInstruction* i : *set) {
Aart Bike3dedc52016-11-02 17:50:27 -0700300 // Check that, other than instructions that are no longer in the graph (removed earlier)
301 // each instruction is removable and, other than the phi, uses are contained in the cycle.
302 if (!i->IsInBlock()) {
303 continue;
304 } else if (!i->IsRemovable()) {
305 return false;
306 } else if (i != phi) {
Aart Bikcc42be02016-10-20 16:14:16 -0700307 for (const HUseListNode<HInstruction*>& use : i->GetUses()) {
308 if (set->find(use.GetUser()) == set->end()) {
309 return false;
310 }
311 }
312 }
Aart Bike3dedc52016-11-02 17:50:27 -0700313 iset_->insert(i); // copy
Aart Bikcc42be02016-10-20 16:14:16 -0700314 }
Aart Bikcc42be02016-10-20 16:14:16 -0700315 return true;
316 }
317 return false;
318}
319
320// Find: phi: Phi(init, addsub)
321// s: SuspendCheck
322// c: Condition(phi, bound)
323// i: If(c)
324// TODO: Find a less pattern matching approach?
325bool HLoopOptimization::IsEmptyHeader(HBasicBlock* block) {
326 DCHECK(iset_->empty());
327 HInstruction* phi = block->GetFirstPhi();
328 if (phi != nullptr && phi->GetNext() == nullptr && IsPhiInduction(phi->AsPhi())) {
329 HInstruction* s = block->GetFirstInstruction();
330 if (s != nullptr && s->IsSuspendCheck()) {
331 HInstruction* c = s->GetNext();
332 if (c != nullptr && c->IsCondition() && c->GetUses().HasExactlyOneElement()) {
333 HInstruction* i = c->GetNext();
334 if (i != nullptr && i->IsIf() && i->InputAt(0) == c) {
335 iset_->insert(c);
336 iset_->insert(s);
337 return true;
338 }
339 }
340 }
341 }
342 return false;
343}
344
345bool HLoopOptimization::IsEmptyBody(HBasicBlock* block) {
346 if (block->GetFirstPhi() == nullptr) {
347 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
348 HInstruction* instruction = it.Current();
349 if (!instruction->IsGoto() && iset_->find(instruction) == iset_->end()) {
350 return false;
351 }
352 }
353 return true;
354 }
355 return false;
356}
357
Aart Bik482095d2016-10-10 15:39:10 -0700358bool HLoopOptimization::IsOnlyUsedAfterLoop(HLoopInformation* loop_info,
Aart Bik8c4a8542016-10-06 11:36:57 -0700359 HInstruction* instruction,
360 /*out*/ int32_t* use_count) {
361 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
362 HInstruction* user = use.GetUser();
363 if (iset_->find(user) == iset_->end()) { // not excluded?
364 HLoopInformation* other_loop_info = user->GetBlock()->GetLoopInformation();
Aart Bik482095d2016-10-10 15:39:10 -0700365 if (other_loop_info != nullptr && other_loop_info->IsIn(*loop_info)) {
Aart Bik8c4a8542016-10-06 11:36:57 -0700366 return false;
367 }
368 ++*use_count;
369 }
370 }
371 return true;
372}
373
374void HLoopOptimization::ReplaceAllUses(HInstruction* instruction, HInstruction* replacement) {
Aart Bik281c6812016-08-26 11:31:48 -0700375 const HUseList<HInstruction*>& uses = instruction->GetUses();
376 for (auto it = uses.begin(), end = uses.end(); it != end;) {
377 HInstruction* user = it->GetUser();
378 size_t index = it->GetIndex();
379 ++it; // increment before replacing
Aart Bik8c4a8542016-10-06 11:36:57 -0700380 if (iset_->find(user) == iset_->end()) { // not excluded?
Aart Bik281c6812016-08-26 11:31:48 -0700381 user->ReplaceInput(replacement, index);
382 induction_range_.Replace(user, instruction, replacement); // update induction
383 }
384 }
385 const HUseList<HEnvironment*>& env_uses = instruction->GetEnvUses();
386 for (auto it = env_uses.begin(), end = env_uses.end(); it != end;) {
387 HEnvironment* user = it->GetUser();
388 size_t index = it->GetIndex();
389 ++it; // increment before replacing
Aart Bik8c4a8542016-10-06 11:36:57 -0700390 if (iset_->find(user->GetHolder()) == iset_->end()) { // not excluded?
Aart Bik281c6812016-08-26 11:31:48 -0700391 user->RemoveAsUserOfInput(index);
392 user->SetRawEnvAt(index, replacement);
393 replacement->AddEnvUseAt(user, index);
394 }
395 }
396}
397
Aart Bik8c4a8542016-10-06 11:36:57 -0700398bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction,
399 int32_t use_count,
400 HBasicBlock* block) {
401 // If true uses appear after the loop, replace these uses with the last value. Environment
402 // uses can consume this value too, since any first true use is outside the loop (although
403 // this may imply that de-opting may look "ahead" a bit on the phi value). If there are only
404 // environment uses, the value is dropped altogether, since the computations have no effect.
405 if (use_count > 0) {
406 if (!induction_range_.CanGenerateLastValue(instruction)) {
407 return false;
408 }
409 ReplaceAllUses(instruction, induction_range_.GenerateLastValue(instruction, graph_, block));
410 }
411 return true;
412}
413
Aart Bik281c6812016-08-26 11:31:48 -0700414} // namespace art