blob: 51be1d1e918537458840f9b3859ad4a3a12532a8 [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
31//
32// Class methods.
33//
34
35HLoopOptimization::HLoopOptimization(HGraph* graph,
36 HInductionVarAnalysis* induction_analysis)
37 : HOptimization(graph, kLoopOptimizationPassName),
38 induction_range_(induction_analysis),
Aart Bik96202302016-10-04 17:33:56 -070039 loop_allocator_(nullptr),
Aart Bik281c6812016-08-26 11:31:48 -070040 top_loop_(nullptr),
Aart Bik8c4a8542016-10-06 11:36:57 -070041 last_loop_(nullptr),
Aart Bik482095d2016-10-10 15:39:10 -070042 iset_(nullptr),
43 induction_simplication_count_(0) {
Aart Bik281c6812016-08-26 11:31:48 -070044}
45
46void HLoopOptimization::Run() {
47 // Well-behaved loops only.
48 // TODO: make this less of a sledgehammer.
Aart Bik96202302016-10-04 17:33:56 -070049 if (graph_->HasTryCatch() || graph_->HasIrreducibleLoops()) {
Aart Bik281c6812016-08-26 11:31:48 -070050 return;
51 }
52
Aart Bik96202302016-10-04 17:33:56 -070053 // Phase-local allocator that draws from the global pool. Since the allocator
54 // itself resides on the stack, it is destructed on exiting Run(), which
55 // implies its underlying memory is released immediately.
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010056 ArenaAllocator allocator(graph_->GetArena()->GetArenaPool());
Aart Bik96202302016-10-04 17:33:56 -070057 loop_allocator_ = &allocator;
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010058
Aart Bik96202302016-10-04 17:33:56 -070059 // Perform loop optimizations.
60 LocalRun();
61
62 // Detach.
63 loop_allocator_ = nullptr;
64 last_loop_ = top_loop_ = nullptr;
65}
66
67void HLoopOptimization::LocalRun() {
68 // Build the linear order using the phase-local allocator. This step enables building
69 // a loop hierarchy that properly reflects the outer-inner and previous-next relation.
70 ArenaVector<HBasicBlock*> linear_order(loop_allocator_->Adapter(kArenaAllocLinearOrder));
71 LinearizeGraph(graph_, loop_allocator_, &linear_order);
72
Aart Bik281c6812016-08-26 11:31:48 -070073 // Build the loop hierarchy.
Aart Bik96202302016-10-04 17:33:56 -070074 for (HBasicBlock* block : linear_order) {
Aart Bik281c6812016-08-26 11:31:48 -070075 if (block->IsLoopHeader()) {
76 AddLoop(block->GetLoopInformation());
77 }
78 }
Aart Bik96202302016-10-04 17:33:56 -070079
Aart Bik8c4a8542016-10-06 11:36:57 -070080 // Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use
81 // a temporary set that stores instructions using the phase-local allocator.
82 if (top_loop_ != nullptr) {
83 ArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
84 iset_ = &iset;
85 TraverseLoopsInnerToOuter(top_loop_);
86 iset_ = nullptr; // detach
87 }
Aart Bik281c6812016-08-26 11:31:48 -070088}
89
90void HLoopOptimization::AddLoop(HLoopInformation* loop_info) {
91 DCHECK(loop_info != nullptr);
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010092 LoopNode* node = new (loop_allocator_) LoopNode(loop_info); // phase-local allocator
Aart Bik281c6812016-08-26 11:31:48 -070093 if (last_loop_ == nullptr) {
94 // First loop.
95 DCHECK(top_loop_ == nullptr);
96 last_loop_ = top_loop_ = node;
97 } else if (loop_info->IsIn(*last_loop_->loop_info)) {
98 // Inner loop.
99 node->outer = last_loop_;
100 DCHECK(last_loop_->inner == nullptr);
101 last_loop_ = last_loop_->inner = node;
102 } else {
103 // Subsequent loop.
104 while (last_loop_->outer != nullptr && !loop_info->IsIn(*last_loop_->outer->loop_info)) {
105 last_loop_ = last_loop_->outer;
106 }
107 node->outer = last_loop_->outer;
108 node->previous = last_loop_;
109 DCHECK(last_loop_->next == nullptr);
110 last_loop_ = last_loop_->next = node;
111 }
112}
113
114void HLoopOptimization::RemoveLoop(LoopNode* node) {
115 DCHECK(node != nullptr);
Aart Bik8c4a8542016-10-06 11:36:57 -0700116 DCHECK(node->inner == nullptr);
117 if (node->previous != nullptr) {
118 // Within sequence.
119 node->previous->next = node->next;
120 if (node->next != nullptr) {
121 node->next->previous = node->previous;
122 }
123 } else {
124 // First of sequence.
125 if (node->outer != nullptr) {
126 node->outer->inner = node->next;
127 } else {
128 top_loop_ = node->next;
129 }
130 if (node->next != nullptr) {
131 node->next->outer = node->outer;
132 node->next->previous = nullptr;
133 }
134 }
Aart Bik281c6812016-08-26 11:31:48 -0700135}
136
137void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) {
138 for ( ; node != nullptr; node = node->next) {
Aart Bik482095d2016-10-10 15:39:10 -0700139 int current_induction_simplification_count = induction_simplication_count_;
Aart Bik281c6812016-08-26 11:31:48 -0700140 if (node->inner != nullptr) {
141 TraverseLoopsInnerToOuter(node->inner);
142 }
Aart Bik482095d2016-10-10 15:39:10 -0700143 // Visit loop after its inner loops have been visited. If the induction of any inner
144 // loop has been simplified, recompute the induction information of this loop first.
145 if (current_induction_simplification_count != induction_simplication_count_) {
146 induction_range_.ReVisit(node->loop_info);
147 }
Aart Bik639cc8c2016-10-18 13:03:31 -0700148 SimplifyBlocks(node);
Aart Bik281c6812016-08-26 11:31:48 -0700149 SimplifyInduction(node);
Aart Bik482095d2016-10-10 15:39:10 -0700150 SimplifyBlocks(node);
Aart Bik9abf8942016-10-14 09:49:42 -0700151 if (node->inner == nullptr) {
152 RemoveIfEmptyInnerLoop(node);
153 }
Aart Bik281c6812016-08-26 11:31:48 -0700154 }
155}
156
157void HLoopOptimization::SimplifyInduction(LoopNode* node) {
158 HBasicBlock* header = node->loop_info->GetHeader();
159 HBasicBlock* preheader = node->loop_info->GetPreHeader();
Aart Bik8c4a8542016-10-06 11:36:57 -0700160 // Scan the phis in the header to find opportunities to simplify an induction
161 // cycle that is only used outside the loop. Replace these uses, if any, with
162 // the last value and remove the induction cycle.
163 // Examples: for (int i = 0; x != null; i++) { .... no i .... }
164 // for (int i = 0; i < 10; i++, k++) { .... no k .... } return k;
Aart Bik281c6812016-08-26 11:31:48 -0700165 for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) {
166 HPhi* phi = it.Current()->AsPhi();
Aart Bik8c4a8542016-10-06 11:36:57 -0700167 iset_->clear();
168 int32_t use_count = 0;
Aart Bikcc42be02016-10-20 16:14:16 -0700169 if (IsPhiInduction(phi) &&
Aart Bik482095d2016-10-10 15:39:10 -0700170 IsOnlyUsedAfterLoop(node->loop_info, phi, &use_count) &&
Aart Bik8c4a8542016-10-06 11:36:57 -0700171 TryReplaceWithLastValue(phi, use_count, preheader)) {
172 for (HInstruction* i : *iset_) {
173 RemoveFromCycle(i);
Aart Bik281c6812016-08-26 11:31:48 -0700174 }
Aart Bik482095d2016-10-10 15:39:10 -0700175 induction_simplication_count_++;
176 }
177 }
178}
179
180void HLoopOptimization::SimplifyBlocks(LoopNode* node) {
181 for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
182 HBasicBlock* block = it.Current();
Aart Bikcc42be02016-10-20 16:14:16 -0700183 // Remove instructions that are dead.
Aart Bik482095d2016-10-10 15:39:10 -0700184 for (HBackwardInstructionIterator i(block->GetInstructions()); !i.Done(); i.Advance()) {
185 HInstruction* instruction = i.Current();
186 if (instruction->IsDeadAndRemovable()) {
187 block->RemoveInstruction(instruction);
188 }
189 }
Aart Bikcc42be02016-10-20 16:14:16 -0700190 // Remove trivial control flow blocks from the loop-body.
Aart Bik482095d2016-10-10 15:39:10 -0700191 if (block->GetPredecessors().size() == 1 &&
192 block->GetSuccessors().size() == 1 &&
193 block->GetFirstInstruction()->IsGoto()) {
194 HBasicBlock* pred = block->GetSinglePredecessor();
195 HBasicBlock* succ = block->GetSingleSuccessor();
196 if (succ->GetPredecessors().size() == 1) {
197 pred->ReplaceSuccessor(block, succ);
198 block->ClearDominanceInformation();
199 block->SetDominator(pred); // needed by next disconnect.
200 block->DisconnectAndDelete();
201 pred->AddDominatedBlock(succ);
202 succ->SetDominator(pred);
203 }
Aart Bik281c6812016-08-26 11:31:48 -0700204 }
205 }
206}
207
Aart Bik9abf8942016-10-14 09:49:42 -0700208void HLoopOptimization::RemoveIfEmptyInnerLoop(LoopNode* node) {
Aart Bik281c6812016-08-26 11:31:48 -0700209 HBasicBlock* header = node->loop_info->GetHeader();
210 HBasicBlock* preheader = node->loop_info->GetPreHeader();
Aart Bik9abf8942016-10-14 09:49:42 -0700211 // Ensure loop header logic is finite.
212 if (!induction_range_.IsFinite(node->loop_info)) {
213 return;
214 }
Aart Bik281c6812016-08-26 11:31:48 -0700215 // Ensure there is only a single loop-body (besides the header).
216 HBasicBlock* body = nullptr;
217 for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
218 if (it.Current() != header) {
219 if (body != nullptr) {
220 return;
221 }
222 body = it.Current();
223 }
224 }
225 // Ensure there is only a single exit point.
226 if (header->GetSuccessors().size() != 2) {
227 return;
228 }
229 HBasicBlock* exit = (header->GetSuccessors()[0] == body)
230 ? header->GetSuccessors()[1]
231 : header->GetSuccessors()[0];
Aart Bik8c4a8542016-10-06 11:36:57 -0700232 // Ensure exit can only be reached by exiting loop.
Aart Bik281c6812016-08-26 11:31:48 -0700233 if (exit->GetPredecessors().size() != 1) {
234 return;
235 }
Aart Bik8c4a8542016-10-06 11:36:57 -0700236 // Detect an empty loop: no side effects other than plain iteration. Replace
237 // subsequent index uses, if any, with the last value and remove the loop.
238 iset_->clear();
239 int32_t use_count = 0;
Aart Bikcc42be02016-10-20 16:14:16 -0700240 if (IsEmptyHeader(header) &&
241 IsEmptyBody(body) &&
Aart Bik482095d2016-10-10 15:39:10 -0700242 IsOnlyUsedAfterLoop(node->loop_info, header->GetFirstPhi(), &use_count) &&
Aart Bik8c4a8542016-10-06 11:36:57 -0700243 TryReplaceWithLastValue(header->GetFirstPhi(), use_count, preheader)) {
Aart Bik281c6812016-08-26 11:31:48 -0700244 body->DisconnectAndDelete();
245 exit->RemovePredecessor(header);
246 header->RemoveSuccessor(exit);
247 header->ClearDominanceInformation();
248 header->SetDominator(preheader); // needed by next disconnect.
249 header->DisconnectAndDelete();
Aart Bik482095d2016-10-10 15:39:10 -0700250 preheader->AddSuccessor(exit);
251 preheader->AddInstruction(new (graph_->GetArena()) HGoto()); // global allocator
252 preheader->AddDominatedBlock(exit);
253 exit->SetDominator(preheader);
Aart Bik281c6812016-08-26 11:31:48 -0700254 // Update hierarchy.
255 RemoveLoop(node);
256 }
257}
258
Aart Bikcc42be02016-10-20 16:14:16 -0700259bool HLoopOptimization::IsPhiInduction(HPhi* phi) {
260 ArenaSet<HInstruction*>* set = induction_range_.LookupCycle(phi);
261 if (set != nullptr) {
262 for (HInstruction* i : *set) {
263 // Check that, other than phi, instruction are removable with uses contained in the cycle.
264 // TODO: investigate what cases are no longer in the graph.
265 if (i != phi) {
266 if (!i->IsInBlock() || !i->IsRemovable()) {
267 return false;
268 }
269 for (const HUseListNode<HInstruction*>& use : i->GetUses()) {
270 if (set->find(use.GetUser()) == set->end()) {
271 return false;
272 }
273 }
274 }
275 }
276 DCHECK(iset_->empty());
277 iset_->insert(set->begin(), set->end()); // copy
278 return true;
279 }
280 return false;
281}
282
283// Find: phi: Phi(init, addsub)
284// s: SuspendCheck
285// c: Condition(phi, bound)
286// i: If(c)
287// TODO: Find a less pattern matching approach?
288bool HLoopOptimization::IsEmptyHeader(HBasicBlock* block) {
289 DCHECK(iset_->empty());
290 HInstruction* phi = block->GetFirstPhi();
291 if (phi != nullptr && phi->GetNext() == nullptr && IsPhiInduction(phi->AsPhi())) {
292 HInstruction* s = block->GetFirstInstruction();
293 if (s != nullptr && s->IsSuspendCheck()) {
294 HInstruction* c = s->GetNext();
295 if (c != nullptr && c->IsCondition() && c->GetUses().HasExactlyOneElement()) {
296 HInstruction* i = c->GetNext();
297 if (i != nullptr && i->IsIf() && i->InputAt(0) == c) {
298 iset_->insert(c);
299 iset_->insert(s);
300 return true;
301 }
302 }
303 }
304 }
305 return false;
306}
307
308bool HLoopOptimization::IsEmptyBody(HBasicBlock* block) {
309 if (block->GetFirstPhi() == nullptr) {
310 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
311 HInstruction* instruction = it.Current();
312 if (!instruction->IsGoto() && iset_->find(instruction) == iset_->end()) {
313 return false;
314 }
315 }
316 return true;
317 }
318 return false;
319}
320
Aart Bik482095d2016-10-10 15:39:10 -0700321bool HLoopOptimization::IsOnlyUsedAfterLoop(HLoopInformation* loop_info,
Aart Bik8c4a8542016-10-06 11:36:57 -0700322 HInstruction* instruction,
323 /*out*/ int32_t* use_count) {
324 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
325 HInstruction* user = use.GetUser();
326 if (iset_->find(user) == iset_->end()) { // not excluded?
327 HLoopInformation* other_loop_info = user->GetBlock()->GetLoopInformation();
Aart Bik482095d2016-10-10 15:39:10 -0700328 if (other_loop_info != nullptr && other_loop_info->IsIn(*loop_info)) {
Aart Bik8c4a8542016-10-06 11:36:57 -0700329 return false;
330 }
331 ++*use_count;
332 }
333 }
334 return true;
335}
336
337void HLoopOptimization::ReplaceAllUses(HInstruction* instruction, HInstruction* replacement) {
Aart Bik281c6812016-08-26 11:31:48 -0700338 const HUseList<HInstruction*>& uses = instruction->GetUses();
339 for (auto it = uses.begin(), end = uses.end(); it != end;) {
340 HInstruction* user = it->GetUser();
341 size_t index = it->GetIndex();
342 ++it; // increment before replacing
Aart Bik8c4a8542016-10-06 11:36:57 -0700343 if (iset_->find(user) == iset_->end()) { // not excluded?
Aart Bik281c6812016-08-26 11:31:48 -0700344 user->ReplaceInput(replacement, index);
345 induction_range_.Replace(user, instruction, replacement); // update induction
346 }
347 }
348 const HUseList<HEnvironment*>& env_uses = instruction->GetEnvUses();
349 for (auto it = env_uses.begin(), end = env_uses.end(); it != end;) {
350 HEnvironment* user = it->GetUser();
351 size_t index = it->GetIndex();
352 ++it; // increment before replacing
Aart Bik8c4a8542016-10-06 11:36:57 -0700353 if (iset_->find(user->GetHolder()) == iset_->end()) { // not excluded?
Aart Bik281c6812016-08-26 11:31:48 -0700354 user->RemoveAsUserOfInput(index);
355 user->SetRawEnvAt(index, replacement);
356 replacement->AddEnvUseAt(user, index);
357 }
358 }
359}
360
Aart Bik8c4a8542016-10-06 11:36:57 -0700361bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction,
362 int32_t use_count,
363 HBasicBlock* block) {
364 // If true uses appear after the loop, replace these uses with the last value. Environment
365 // uses can consume this value too, since any first true use is outside the loop (although
366 // this may imply that de-opting may look "ahead" a bit on the phi value). If there are only
367 // environment uses, the value is dropped altogether, since the computations have no effect.
368 if (use_count > 0) {
369 if (!induction_range_.CanGenerateLastValue(instruction)) {
370 return false;
371 }
372 ReplaceAllUses(instruction, induction_range_.GenerateLastValue(instruction, graph_, block));
373 }
374 return true;
375}
376
Aart Bik281c6812016-08-26 11:31:48 -0700377} // namespace art