blob: 8df513f4108e1498d27c35efaf1bcb82174b3727 [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 Bik92685a82017-03-06 11:13:43 -080019#include "driver/compiler_driver.h"
Aart Bik96202302016-10-04 17:33:56 -070020#include "linear_order.h"
Aart Bik281c6812016-08-26 11:31:48 -070021
22namespace art {
23
Aart Bik9abf8942016-10-14 09:49:42 -070024// Remove the instruction from the graph. A bit more elaborate than the usual
25// instruction removal, since there may be a cycle in the use structure.
Aart Bik281c6812016-08-26 11:31:48 -070026static void RemoveFromCycle(HInstruction* instruction) {
Aart Bik281c6812016-08-26 11:31:48 -070027 instruction->RemoveAsUserOfAllInputs();
28 instruction->RemoveEnvironmentUsers();
29 instruction->GetBlock()->RemoveInstructionOrPhi(instruction, /*ensure_safety=*/ false);
30}
31
Aart Bik807868e2016-11-03 17:51:43 -070032// Detect a goto block and sets succ to the single successor.
Aart Bike3dedc52016-11-02 17:50:27 -070033static bool IsGotoBlock(HBasicBlock* block, /*out*/ HBasicBlock** succ) {
34 if (block->GetPredecessors().size() == 1 &&
35 block->GetSuccessors().size() == 1 &&
36 block->IsSingleGoto()) {
37 *succ = block->GetSingleSuccessor();
38 return true;
39 }
40 return false;
41}
42
Aart Bik807868e2016-11-03 17:51:43 -070043// Detect an early exit loop.
44static bool IsEarlyExit(HLoopInformation* loop_info) {
45 HBlocksInLoopReversePostOrderIterator it_loop(*loop_info);
46 for (it_loop.Advance(); !it_loop.Done(); it_loop.Advance()) {
47 for (HBasicBlock* successor : it_loop.Current()->GetSuccessors()) {
48 if (!loop_info->Contains(*successor)) {
49 return true;
50 }
51 }
52 }
53 return false;
54}
55
Aart Bik281c6812016-08-26 11:31:48 -070056//
57// Class methods.
58//
59
60HLoopOptimization::HLoopOptimization(HGraph* graph,
Aart Bik92685a82017-03-06 11:13:43 -080061 CompilerDriver* compiler_driver,
Aart Bik281c6812016-08-26 11:31:48 -070062 HInductionVarAnalysis* induction_analysis)
63 : HOptimization(graph, kLoopOptimizationPassName),
Aart Bik92685a82017-03-06 11:13:43 -080064 compiler_driver_(compiler_driver),
Aart Bik281c6812016-08-26 11:31:48 -070065 induction_range_(induction_analysis),
Aart Bik96202302016-10-04 17:33:56 -070066 loop_allocator_(nullptr),
Aart Bik281c6812016-08-26 11:31:48 -070067 top_loop_(nullptr),
Aart Bik8c4a8542016-10-06 11:36:57 -070068 last_loop_(nullptr),
Aart Bik482095d2016-10-10 15:39:10 -070069 iset_(nullptr),
Aart Bikdf7822e2016-12-06 10:05:30 -080070 induction_simplication_count_(0),
71 simplified_(false) {
Aart Bik281c6812016-08-26 11:31:48 -070072}
73
74void HLoopOptimization::Run() {
Mingyao Yang01b47b02017-02-03 12:09:57 -080075 // Skip if there is no loop or the graph has try-catch/irreducible loops.
Aart Bik281c6812016-08-26 11:31:48 -070076 // TODO: make this less of a sledgehammer.
Mingyao Yang69d75ff2017-02-07 13:06:06 -080077 if (!graph_->HasLoops() || graph_->HasTryCatch() || graph_->HasIrreducibleLoops()) {
Aart Bik281c6812016-08-26 11:31:48 -070078 return;
79 }
80
Aart Bik96202302016-10-04 17:33:56 -070081 // Phase-local allocator that draws from the global pool. Since the allocator
82 // itself resides on the stack, it is destructed on exiting Run(), which
83 // implies its underlying memory is released immediately.
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010084 ArenaAllocator allocator(graph_->GetArena()->GetArenaPool());
Aart Bik96202302016-10-04 17:33:56 -070085 loop_allocator_ = &allocator;
Nicolas Geoffrayebe16742016-10-05 09:55:42 +010086
Aart Bik96202302016-10-04 17:33:56 -070087 // Perform loop optimizations.
88 LocalRun();
89
Mingyao Yang69d75ff2017-02-07 13:06:06 -080090 if (top_loop_ == nullptr) {
Mingyao Yang01b47b02017-02-03 12:09:57 -080091 // All loops have been eliminated.
Mingyao Yang69d75ff2017-02-07 13:06:06 -080092 graph_->SetHasLoops(false);
93 }
94
Aart Bik96202302016-10-04 17:33:56 -070095 // Detach.
96 loop_allocator_ = nullptr;
97 last_loop_ = top_loop_ = nullptr;
98}
99
100void HLoopOptimization::LocalRun() {
101 // Build the linear order using the phase-local allocator. This step enables building
102 // a loop hierarchy that properly reflects the outer-inner and previous-next relation.
103 ArenaVector<HBasicBlock*> linear_order(loop_allocator_->Adapter(kArenaAllocLinearOrder));
104 LinearizeGraph(graph_, loop_allocator_, &linear_order);
105
Aart Bik281c6812016-08-26 11:31:48 -0700106 // Build the loop hierarchy.
Aart Bik96202302016-10-04 17:33:56 -0700107 for (HBasicBlock* block : linear_order) {
Aart Bik281c6812016-08-26 11:31:48 -0700108 if (block->IsLoopHeader()) {
109 AddLoop(block->GetLoopInformation());
110 }
111 }
Aart Bik96202302016-10-04 17:33:56 -0700112
Aart Bik8c4a8542016-10-06 11:36:57 -0700113 // Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use
114 // a temporary set that stores instructions using the phase-local allocator.
115 if (top_loop_ != nullptr) {
116 ArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
117 iset_ = &iset;
118 TraverseLoopsInnerToOuter(top_loop_);
119 iset_ = nullptr; // detach
120 }
Aart Bik281c6812016-08-26 11:31:48 -0700121}
122
123void HLoopOptimization::AddLoop(HLoopInformation* loop_info) {
124 DCHECK(loop_info != nullptr);
Nicolas Geoffrayebe16742016-10-05 09:55:42 +0100125 LoopNode* node = new (loop_allocator_) LoopNode(loop_info); // phase-local allocator
Aart Bik281c6812016-08-26 11:31:48 -0700126 if (last_loop_ == nullptr) {
127 // First loop.
128 DCHECK(top_loop_ == nullptr);
129 last_loop_ = top_loop_ = node;
130 } else if (loop_info->IsIn(*last_loop_->loop_info)) {
131 // Inner loop.
132 node->outer = last_loop_;
133 DCHECK(last_loop_->inner == nullptr);
134 last_loop_ = last_loop_->inner = node;
135 } else {
136 // Subsequent loop.
137 while (last_loop_->outer != nullptr && !loop_info->IsIn(*last_loop_->outer->loop_info)) {
138 last_loop_ = last_loop_->outer;
139 }
140 node->outer = last_loop_->outer;
141 node->previous = last_loop_;
142 DCHECK(last_loop_->next == nullptr);
143 last_loop_ = last_loop_->next = node;
144 }
145}
146
147void HLoopOptimization::RemoveLoop(LoopNode* node) {
148 DCHECK(node != nullptr);
Aart Bik8c4a8542016-10-06 11:36:57 -0700149 DCHECK(node->inner == nullptr);
150 if (node->previous != nullptr) {
151 // Within sequence.
152 node->previous->next = node->next;
153 if (node->next != nullptr) {
154 node->next->previous = node->previous;
155 }
156 } else {
157 // First of sequence.
158 if (node->outer != nullptr) {
159 node->outer->inner = node->next;
160 } else {
161 top_loop_ = node->next;
162 }
163 if (node->next != nullptr) {
164 node->next->outer = node->outer;
165 node->next->previous = nullptr;
166 }
167 }
Aart Bik281c6812016-08-26 11:31:48 -0700168}
169
170void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) {
171 for ( ; node != nullptr; node = node->next) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800172 // Visit inner loops first.
Aart Bik482095d2016-10-10 15:39:10 -0700173 int current_induction_simplification_count = induction_simplication_count_;
Aart Bik281c6812016-08-26 11:31:48 -0700174 if (node->inner != nullptr) {
175 TraverseLoopsInnerToOuter(node->inner);
176 }
Aart Bik6b69e0a2017-01-11 10:20:43 -0800177 // Recompute induction information of this loop if the induction
178 // of any inner loop has been simplified.
Aart Bik482095d2016-10-10 15:39:10 -0700179 if (current_induction_simplification_count != induction_simplication_count_) {
180 induction_range_.ReVisit(node->loop_info);
181 }
Aart Bik6b69e0a2017-01-11 10:20:43 -0800182 // Repeat simplifications in the body of this loop until no more changes occur.
183 // Note that since each simplification consists of eliminating code (without
184 // introducing new code), this process is always finite.
Aart Bikdf7822e2016-12-06 10:05:30 -0800185 do {
186 simplified_ = false;
Aart Bikdf7822e2016-12-06 10:05:30 -0800187 SimplifyInduction(node);
Aart Bik6b69e0a2017-01-11 10:20:43 -0800188 SimplifyBlocks(node);
Aart Bikdf7822e2016-12-06 10:05:30 -0800189 } while (simplified_);
Aart Bik6b69e0a2017-01-11 10:20:43 -0800190 // Simplify inner loop.
Aart Bik9abf8942016-10-14 09:49:42 -0700191 if (node->inner == nullptr) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800192 SimplifyInnerLoop(node);
Aart Bik9abf8942016-10-14 09:49:42 -0700193 }
Aart Bik281c6812016-08-26 11:31:48 -0700194 }
195}
196
197void HLoopOptimization::SimplifyInduction(LoopNode* node) {
198 HBasicBlock* header = node->loop_info->GetHeader();
199 HBasicBlock* preheader = node->loop_info->GetPreHeader();
Aart Bik8c4a8542016-10-06 11:36:57 -0700200 // Scan the phis in the header to find opportunities to simplify an induction
201 // cycle that is only used outside the loop. Replace these uses, if any, with
202 // the last value and remove the induction cycle.
203 // Examples: for (int i = 0; x != null; i++) { .... no i .... }
204 // for (int i = 0; i < 10; i++, k++) { .... no k .... } return k;
Aart Bik281c6812016-08-26 11:31:48 -0700205 for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) {
206 HPhi* phi = it.Current()->AsPhi();
Aart Bik8c4a8542016-10-06 11:36:57 -0700207 iset_->clear();
208 int32_t use_count = 0;
Aart Bikcc42be02016-10-20 16:14:16 -0700209 if (IsPhiInduction(phi) &&
Aart Bik6b69e0a2017-01-11 10:20:43 -0800210 IsOnlyUsedAfterLoop(node->loop_info, phi, /*collect_loop_uses*/ false, &use_count) &&
Aart Bik807868e2016-11-03 17:51:43 -0700211 // No uses, or no early-exit with proper replacement.
212 (use_count == 0 ||
213 (!IsEarlyExit(node->loop_info) && TryReplaceWithLastValue(phi, preheader)))) {
Aart Bik8c4a8542016-10-06 11:36:57 -0700214 for (HInstruction* i : *iset_) {
215 RemoveFromCycle(i);
Aart Bik281c6812016-08-26 11:31:48 -0700216 }
Aart Bikdf7822e2016-12-06 10:05:30 -0800217 simplified_ = true;
Aart Bik482095d2016-10-10 15:39:10 -0700218 }
219 }
220}
221
222void HLoopOptimization::SimplifyBlocks(LoopNode* node) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800223 // Iterate over all basic blocks in the loop-body.
224 for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
225 HBasicBlock* block = it.Current();
226 // Remove dead instructions from the loop-body.
Aart Bik6b69e0a2017-01-11 10:20:43 -0800227 RemoveDeadInstructions(block->GetPhis());
228 RemoveDeadInstructions(block->GetInstructions());
Aart Bikdf7822e2016-12-06 10:05:30 -0800229 // Remove trivial control flow blocks from the loop-body.
Aart Bik6b69e0a2017-01-11 10:20:43 -0800230 if (block->GetPredecessors().size() == 1 &&
231 block->GetSuccessors().size() == 1 &&
232 block->GetSingleSuccessor()->GetPredecessors().size() == 1) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800233 simplified_ = true;
Aart Bik6b69e0a2017-01-11 10:20:43 -0800234 block->MergeWith(block->GetSingleSuccessor());
Aart Bikdf7822e2016-12-06 10:05:30 -0800235 } else if (block->GetSuccessors().size() == 2) {
236 // Trivial if block can be bypassed to either branch.
237 HBasicBlock* succ0 = block->GetSuccessors()[0];
238 HBasicBlock* succ1 = block->GetSuccessors()[1];
239 HBasicBlock* meet0 = nullptr;
240 HBasicBlock* meet1 = nullptr;
241 if (succ0 != succ1 &&
242 IsGotoBlock(succ0, &meet0) &&
243 IsGotoBlock(succ1, &meet1) &&
244 meet0 == meet1 && // meets again
245 meet0 != block && // no self-loop
246 meet0->GetPhis().IsEmpty()) { // not used for merging
247 simplified_ = true;
248 succ0->DisconnectAndDelete();
249 if (block->Dominates(meet0)) {
250 block->RemoveDominatedBlock(meet0);
251 succ1->AddDominatedBlock(meet0);
252 meet0->SetDominator(succ1);
Aart Bike3dedc52016-11-02 17:50:27 -0700253 }
Aart Bik482095d2016-10-10 15:39:10 -0700254 }
Aart Bik281c6812016-08-26 11:31:48 -0700255 }
Aart Bikdf7822e2016-12-06 10:05:30 -0800256 }
Aart Bik281c6812016-08-26 11:31:48 -0700257}
258
Aart Bik6b69e0a2017-01-11 10:20:43 -0800259bool HLoopOptimization::SimplifyInnerLoop(LoopNode* node) {
Aart Bik281c6812016-08-26 11:31:48 -0700260 HBasicBlock* header = node->loop_info->GetHeader();
261 HBasicBlock* preheader = node->loop_info->GetPreHeader();
Aart Bik9abf8942016-10-14 09:49:42 -0700262 // Ensure loop header logic is finite.
Aart Bik6b69e0a2017-01-11 10:20:43 -0800263 int64_t tc = 0;
264 if (!induction_range_.IsFinite(node->loop_info, &tc)) {
265 return false;
Aart Bik9abf8942016-10-14 09:49:42 -0700266 }
Aart Bik281c6812016-08-26 11:31:48 -0700267 // Ensure there is only a single loop-body (besides the header).
268 HBasicBlock* body = nullptr;
269 for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
270 if (it.Current() != header) {
271 if (body != nullptr) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800272 return false;
Aart Bik281c6812016-08-26 11:31:48 -0700273 }
274 body = it.Current();
275 }
276 }
277 // Ensure there is only a single exit point.
278 if (header->GetSuccessors().size() != 2) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800279 return false;
Aart Bik281c6812016-08-26 11:31:48 -0700280 }
281 HBasicBlock* exit = (header->GetSuccessors()[0] == body)
282 ? header->GetSuccessors()[1]
283 : header->GetSuccessors()[0];
Aart Bik8c4a8542016-10-06 11:36:57 -0700284 // Ensure exit can only be reached by exiting loop.
Aart Bik281c6812016-08-26 11:31:48 -0700285 if (exit->GetPredecessors().size() != 1) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800286 return false;
Aart Bik281c6812016-08-26 11:31:48 -0700287 }
Aart Bik6b69e0a2017-01-11 10:20:43 -0800288 // Detect either an empty loop (no side effects other than plain iteration) or
289 // a trivial loop (just iterating once). Replace subsequent index uses, if any,
290 // with the last value and remove the loop, possibly after unrolling its body.
291 HInstruction* phi = header->GetFirstPhi();
Aart Bik8c4a8542016-10-06 11:36:57 -0700292 iset_->clear();
293 int32_t use_count = 0;
Aart Bik6b69e0a2017-01-11 10:20:43 -0800294 if (IsEmptyHeader(header)) {
295 bool is_empty = IsEmptyBody(body);
296 if ((is_empty || tc == 1) &&
297 IsOnlyUsedAfterLoop(node->loop_info, phi, /*collect_loop_uses*/ true, &use_count) &&
298 // No uses, or proper replacement.
299 (use_count == 0 || TryReplaceWithLastValue(phi, preheader))) {
300 if (!is_empty) {
301 // Unroll the loop body, which sees initial value of the index.
302 phi->ReplaceWith(phi->InputAt(0));
303 preheader->MergeInstructionsWith(body);
304 }
305 body->DisconnectAndDelete();
306 exit->RemovePredecessor(header);
307 header->RemoveSuccessor(exit);
308 header->RemoveDominatedBlock(exit);
309 header->DisconnectAndDelete();
310 preheader->AddSuccessor(exit);
311 preheader->AddInstruction(new (graph_->GetArena()) HGoto()); // global allocator
312 preheader->AddDominatedBlock(exit);
313 exit->SetDominator(preheader);
314 RemoveLoop(node); // update hierarchy
315 return true;
316 }
Aart Bik281c6812016-08-26 11:31:48 -0700317 }
Aart Bik6b69e0a2017-01-11 10:20:43 -0800318 return false;
Aart Bik281c6812016-08-26 11:31:48 -0700319}
320
Aart Bikcc42be02016-10-20 16:14:16 -0700321bool HLoopOptimization::IsPhiInduction(HPhi* phi) {
322 ArenaSet<HInstruction*>* set = induction_range_.LookupCycle(phi);
323 if (set != nullptr) {
Aart Bike3dedc52016-11-02 17:50:27 -0700324 DCHECK(iset_->empty());
Aart Bikcc42be02016-10-20 16:14:16 -0700325 for (HInstruction* i : *set) {
Aart Bike3dedc52016-11-02 17:50:27 -0700326 // Check that, other than instructions that are no longer in the graph (removed earlier)
327 // each instruction is removable and, other than the phi, uses are contained in the cycle.
328 if (!i->IsInBlock()) {
329 continue;
330 } else if (!i->IsRemovable()) {
331 return false;
332 } else if (i != phi) {
Aart Bikcc42be02016-10-20 16:14:16 -0700333 for (const HUseListNode<HInstruction*>& use : i->GetUses()) {
334 if (set->find(use.GetUser()) == set->end()) {
335 return false;
336 }
337 }
338 }
Aart Bike3dedc52016-11-02 17:50:27 -0700339 iset_->insert(i); // copy
Aart Bikcc42be02016-10-20 16:14:16 -0700340 }
Aart Bikcc42be02016-10-20 16:14:16 -0700341 return true;
342 }
343 return false;
344}
345
346// Find: phi: Phi(init, addsub)
347// s: SuspendCheck
348// c: Condition(phi, bound)
349// i: If(c)
350// TODO: Find a less pattern matching approach?
351bool HLoopOptimization::IsEmptyHeader(HBasicBlock* block) {
352 DCHECK(iset_->empty());
353 HInstruction* phi = block->GetFirstPhi();
354 if (phi != nullptr && phi->GetNext() == nullptr && IsPhiInduction(phi->AsPhi())) {
355 HInstruction* s = block->GetFirstInstruction();
356 if (s != nullptr && s->IsSuspendCheck()) {
357 HInstruction* c = s->GetNext();
358 if (c != nullptr && c->IsCondition() && c->GetUses().HasExactlyOneElement()) {
359 HInstruction* i = c->GetNext();
360 if (i != nullptr && i->IsIf() && i->InputAt(0) == c) {
361 iset_->insert(c);
362 iset_->insert(s);
363 return true;
364 }
365 }
366 }
367 }
368 return false;
369}
370
371bool HLoopOptimization::IsEmptyBody(HBasicBlock* block) {
372 if (block->GetFirstPhi() == nullptr) {
373 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
374 HInstruction* instruction = it.Current();
375 if (!instruction->IsGoto() && iset_->find(instruction) == iset_->end()) {
376 return false;
377 }
378 }
379 return true;
380 }
381 return false;
382}
383
Aart Bik482095d2016-10-10 15:39:10 -0700384bool HLoopOptimization::IsOnlyUsedAfterLoop(HLoopInformation* loop_info,
Aart Bik8c4a8542016-10-06 11:36:57 -0700385 HInstruction* instruction,
Aart Bik6b69e0a2017-01-11 10:20:43 -0800386 bool collect_loop_uses,
Aart Bik8c4a8542016-10-06 11:36:57 -0700387 /*out*/ int32_t* use_count) {
388 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
389 HInstruction* user = use.GetUser();
390 if (iset_->find(user) == iset_->end()) { // not excluded?
391 HLoopInformation* other_loop_info = user->GetBlock()->GetLoopInformation();
Aart Bik482095d2016-10-10 15:39:10 -0700392 if (other_loop_info != nullptr && other_loop_info->IsIn(*loop_info)) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800393 // If collect_loop_uses is set, simply keep adding those uses to the set.
394 // Otherwise, reject uses inside the loop that were not already in the set.
395 if (collect_loop_uses) {
396 iset_->insert(user);
397 continue;
398 }
Aart Bik8c4a8542016-10-06 11:36:57 -0700399 return false;
400 }
401 ++*use_count;
402 }
403 }
404 return true;
405}
406
Aart Bik807868e2016-11-03 17:51:43 -0700407bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction, HBasicBlock* block) {
408 // Try to replace outside uses with the last value. Environment uses can consume this
409 // value too, since any first true use is outside the loop (although this may imply
410 // that de-opting may look "ahead" a bit on the phi value). If there are only environment
411 // uses, the value is dropped altogether, since the computations have no effect.
412 if (induction_range_.CanGenerateLastValue(instruction)) {
Aart Bik6b69e0a2017-01-11 10:20:43 -0800413 HInstruction* replacement = induction_range_.GenerateLastValue(instruction, graph_, block);
414 const HUseList<HInstruction*>& uses = instruction->GetUses();
415 for (auto it = uses.begin(), end = uses.end(); it != end;) {
416 HInstruction* user = it->GetUser();
417 size_t index = it->GetIndex();
418 ++it; // increment before replacing
419 if (iset_->find(user) == iset_->end()) { // not excluded?
420 user->ReplaceInput(replacement, index);
421 induction_range_.Replace(user, instruction, replacement); // update induction
422 }
423 }
424 const HUseList<HEnvironment*>& env_uses = instruction->GetEnvUses();
425 for (auto it = env_uses.begin(), end = env_uses.end(); it != end;) {
426 HEnvironment* user = it->GetUser();
427 size_t index = it->GetIndex();
428 ++it; // increment before replacing
429 if (iset_->find(user->GetHolder()) == iset_->end()) { // not excluded?
430 user->RemoveAsUserOfInput(index);
431 user->SetRawEnvAt(index, replacement);
432 replacement->AddEnvUseAt(user, index);
433 }
434 }
435 induction_simplication_count_++;
Aart Bik807868e2016-11-03 17:51:43 -0700436 return true;
Aart Bik8c4a8542016-10-06 11:36:57 -0700437 }
Aart Bik807868e2016-11-03 17:51:43 -0700438 return false;
Aart Bik8c4a8542016-10-06 11:36:57 -0700439}
440
Aart Bik6b69e0a2017-01-11 10:20:43 -0800441void HLoopOptimization::RemoveDeadInstructions(const HInstructionList& list) {
442 for (HBackwardInstructionIterator i(list); !i.Done(); i.Advance()) {
443 HInstruction* instruction = i.Current();
444 if (instruction->IsDeadAndRemovable()) {
445 simplified_ = true;
446 instruction->GetBlock()->RemoveInstructionOrPhi(instruction);
447 }
448 }
449}
450
Aart Bik281c6812016-08-26 11:31:48 -0700451} // namespace art