Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 1 | /* |
| 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 Bik | 92685a8 | 2017-03-06 11:13:43 -0800 | [diff] [blame^] | 19 | #include "driver/compiler_driver.h" |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 20 | #include "linear_order.h" |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 21 | |
| 22 | namespace art { |
| 23 | |
Aart Bik | 9abf894 | 2016-10-14 09:49:42 -0700 | [diff] [blame] | 24 | // 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 Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 26 | static void RemoveFromCycle(HInstruction* instruction) { |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 27 | instruction->RemoveAsUserOfAllInputs(); |
| 28 | instruction->RemoveEnvironmentUsers(); |
| 29 | instruction->GetBlock()->RemoveInstructionOrPhi(instruction, /*ensure_safety=*/ false); |
| 30 | } |
| 31 | |
Aart Bik | 807868e | 2016-11-03 17:51:43 -0700 | [diff] [blame] | 32 | // Detect a goto block and sets succ to the single successor. |
Aart Bik | e3dedc5 | 2016-11-02 17:50:27 -0700 | [diff] [blame] | 33 | static 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 Bik | 807868e | 2016-11-03 17:51:43 -0700 | [diff] [blame] | 43 | // Detect an early exit loop. |
| 44 | static 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 Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 56 | // |
| 57 | // Class methods. |
| 58 | // |
| 59 | |
| 60 | HLoopOptimization::HLoopOptimization(HGraph* graph, |
Aart Bik | 92685a8 | 2017-03-06 11:13:43 -0800 | [diff] [blame^] | 61 | CompilerDriver* compiler_driver, |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 62 | HInductionVarAnalysis* induction_analysis) |
| 63 | : HOptimization(graph, kLoopOptimizationPassName), |
Aart Bik | 92685a8 | 2017-03-06 11:13:43 -0800 | [diff] [blame^] | 64 | compiler_driver_(compiler_driver), |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 65 | induction_range_(induction_analysis), |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 66 | loop_allocator_(nullptr), |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 67 | top_loop_(nullptr), |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 68 | last_loop_(nullptr), |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 69 | iset_(nullptr), |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 70 | induction_simplication_count_(0), |
| 71 | simplified_(false) { |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | void HLoopOptimization::Run() { |
| 75 | // Well-behaved loops only. |
| 76 | // TODO: make this less of a sledgehammer. |
Mingyao Yang | 69d75ff | 2017-02-07 13:06:06 -0800 | [diff] [blame] | 77 | if (!graph_->HasLoops() || graph_->HasTryCatch() || graph_->HasIrreducibleLoops()) { |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 78 | return; |
| 79 | } |
| 80 | |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 81 | // 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 Geoffray | ebe1674 | 2016-10-05 09:55:42 +0100 | [diff] [blame] | 84 | ArenaAllocator allocator(graph_->GetArena()->GetArenaPool()); |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 85 | loop_allocator_ = &allocator; |
Nicolas Geoffray | ebe1674 | 2016-10-05 09:55:42 +0100 | [diff] [blame] | 86 | |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 87 | // Perform loop optimizations. |
| 88 | LocalRun(); |
| 89 | |
Mingyao Yang | 69d75ff | 2017-02-07 13:06:06 -0800 | [diff] [blame] | 90 | if (top_loop_ == nullptr) { |
| 91 | graph_->SetHasLoops(false); |
| 92 | } |
| 93 | |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 94 | // Detach. |
| 95 | loop_allocator_ = nullptr; |
| 96 | last_loop_ = top_loop_ = nullptr; |
| 97 | } |
| 98 | |
| 99 | void HLoopOptimization::LocalRun() { |
| 100 | // Build the linear order using the phase-local allocator. This step enables building |
| 101 | // a loop hierarchy that properly reflects the outer-inner and previous-next relation. |
| 102 | ArenaVector<HBasicBlock*> linear_order(loop_allocator_->Adapter(kArenaAllocLinearOrder)); |
| 103 | LinearizeGraph(graph_, loop_allocator_, &linear_order); |
| 104 | |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 105 | // Build the loop hierarchy. |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 106 | for (HBasicBlock* block : linear_order) { |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 107 | if (block->IsLoopHeader()) { |
| 108 | AddLoop(block->GetLoopInformation()); |
| 109 | } |
| 110 | } |
Aart Bik | 9620230 | 2016-10-04 17:33:56 -0700 | [diff] [blame] | 111 | |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 112 | // Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use |
| 113 | // a temporary set that stores instructions using the phase-local allocator. |
| 114 | if (top_loop_ != nullptr) { |
| 115 | ArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization)); |
| 116 | iset_ = &iset; |
| 117 | TraverseLoopsInnerToOuter(top_loop_); |
| 118 | iset_ = nullptr; // detach |
| 119 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | void HLoopOptimization::AddLoop(HLoopInformation* loop_info) { |
| 123 | DCHECK(loop_info != nullptr); |
Nicolas Geoffray | ebe1674 | 2016-10-05 09:55:42 +0100 | [diff] [blame] | 124 | LoopNode* node = new (loop_allocator_) LoopNode(loop_info); // phase-local allocator |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 125 | if (last_loop_ == nullptr) { |
| 126 | // First loop. |
| 127 | DCHECK(top_loop_ == nullptr); |
| 128 | last_loop_ = top_loop_ = node; |
| 129 | } else if (loop_info->IsIn(*last_loop_->loop_info)) { |
| 130 | // Inner loop. |
| 131 | node->outer = last_loop_; |
| 132 | DCHECK(last_loop_->inner == nullptr); |
| 133 | last_loop_ = last_loop_->inner = node; |
| 134 | } else { |
| 135 | // Subsequent loop. |
| 136 | while (last_loop_->outer != nullptr && !loop_info->IsIn(*last_loop_->outer->loop_info)) { |
| 137 | last_loop_ = last_loop_->outer; |
| 138 | } |
| 139 | node->outer = last_loop_->outer; |
| 140 | node->previous = last_loop_; |
| 141 | DCHECK(last_loop_->next == nullptr); |
| 142 | last_loop_ = last_loop_->next = node; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | void HLoopOptimization::RemoveLoop(LoopNode* node) { |
| 147 | DCHECK(node != nullptr); |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 148 | DCHECK(node->inner == nullptr); |
| 149 | if (node->previous != nullptr) { |
| 150 | // Within sequence. |
| 151 | node->previous->next = node->next; |
| 152 | if (node->next != nullptr) { |
| 153 | node->next->previous = node->previous; |
| 154 | } |
| 155 | } else { |
| 156 | // First of sequence. |
| 157 | if (node->outer != nullptr) { |
| 158 | node->outer->inner = node->next; |
| 159 | } else { |
| 160 | top_loop_ = node->next; |
| 161 | } |
| 162 | if (node->next != nullptr) { |
| 163 | node->next->outer = node->outer; |
| 164 | node->next->previous = nullptr; |
| 165 | } |
| 166 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) { |
| 170 | for ( ; node != nullptr; node = node->next) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 171 | // Visit inner loops first. |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 172 | int current_induction_simplification_count = induction_simplication_count_; |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 173 | if (node->inner != nullptr) { |
| 174 | TraverseLoopsInnerToOuter(node->inner); |
| 175 | } |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 176 | // Recompute induction information of this loop if the induction |
| 177 | // of any inner loop has been simplified. |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 178 | if (current_induction_simplification_count != induction_simplication_count_) { |
| 179 | induction_range_.ReVisit(node->loop_info); |
| 180 | } |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 181 | // Repeat simplifications in the body of this loop until no more changes occur. |
| 182 | // Note that since each simplification consists of eliminating code (without |
| 183 | // introducing new code), this process is always finite. |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 184 | do { |
| 185 | simplified_ = false; |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 186 | SimplifyInduction(node); |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 187 | SimplifyBlocks(node); |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 188 | } while (simplified_); |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 189 | // Simplify inner loop. |
Aart Bik | 9abf894 | 2016-10-14 09:49:42 -0700 | [diff] [blame] | 190 | if (node->inner == nullptr) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 191 | SimplifyInnerLoop(node); |
Aart Bik | 9abf894 | 2016-10-14 09:49:42 -0700 | [diff] [blame] | 192 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 193 | } |
| 194 | } |
| 195 | |
| 196 | void HLoopOptimization::SimplifyInduction(LoopNode* node) { |
| 197 | HBasicBlock* header = node->loop_info->GetHeader(); |
| 198 | HBasicBlock* preheader = node->loop_info->GetPreHeader(); |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 199 | // Scan the phis in the header to find opportunities to simplify an induction |
| 200 | // cycle that is only used outside the loop. Replace these uses, if any, with |
| 201 | // the last value and remove the induction cycle. |
| 202 | // Examples: for (int i = 0; x != null; i++) { .... no i .... } |
| 203 | // for (int i = 0; i < 10; i++, k++) { .... no k .... } return k; |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 204 | for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) { |
| 205 | HPhi* phi = it.Current()->AsPhi(); |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 206 | iset_->clear(); |
| 207 | int32_t use_count = 0; |
Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 208 | if (IsPhiInduction(phi) && |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 209 | IsOnlyUsedAfterLoop(node->loop_info, phi, /*collect_loop_uses*/ false, &use_count) && |
Aart Bik | 807868e | 2016-11-03 17:51:43 -0700 | [diff] [blame] | 210 | // No uses, or no early-exit with proper replacement. |
| 211 | (use_count == 0 || |
| 212 | (!IsEarlyExit(node->loop_info) && TryReplaceWithLastValue(phi, preheader)))) { |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 213 | for (HInstruction* i : *iset_) { |
| 214 | RemoveFromCycle(i); |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 215 | } |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 216 | simplified_ = true; |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | void HLoopOptimization::SimplifyBlocks(LoopNode* node) { |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 222 | // Iterate over all basic blocks in the loop-body. |
| 223 | for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) { |
| 224 | HBasicBlock* block = it.Current(); |
| 225 | // Remove dead instructions from the loop-body. |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 226 | RemoveDeadInstructions(block->GetPhis()); |
| 227 | RemoveDeadInstructions(block->GetInstructions()); |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 228 | // Remove trivial control flow blocks from the loop-body. |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 229 | if (block->GetPredecessors().size() == 1 && |
| 230 | block->GetSuccessors().size() == 1 && |
| 231 | block->GetSingleSuccessor()->GetPredecessors().size() == 1) { |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 232 | simplified_ = true; |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 233 | block->MergeWith(block->GetSingleSuccessor()); |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 234 | } else if (block->GetSuccessors().size() == 2) { |
| 235 | // Trivial if block can be bypassed to either branch. |
| 236 | HBasicBlock* succ0 = block->GetSuccessors()[0]; |
| 237 | HBasicBlock* succ1 = block->GetSuccessors()[1]; |
| 238 | HBasicBlock* meet0 = nullptr; |
| 239 | HBasicBlock* meet1 = nullptr; |
| 240 | if (succ0 != succ1 && |
| 241 | IsGotoBlock(succ0, &meet0) && |
| 242 | IsGotoBlock(succ1, &meet1) && |
| 243 | meet0 == meet1 && // meets again |
| 244 | meet0 != block && // no self-loop |
| 245 | meet0->GetPhis().IsEmpty()) { // not used for merging |
| 246 | simplified_ = true; |
| 247 | succ0->DisconnectAndDelete(); |
| 248 | if (block->Dominates(meet0)) { |
| 249 | block->RemoveDominatedBlock(meet0); |
| 250 | succ1->AddDominatedBlock(meet0); |
| 251 | meet0->SetDominator(succ1); |
Aart Bik | e3dedc5 | 2016-11-02 17:50:27 -0700 | [diff] [blame] | 252 | } |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 253 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 254 | } |
Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 255 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 256 | } |
| 257 | |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 258 | bool HLoopOptimization::SimplifyInnerLoop(LoopNode* node) { |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 259 | HBasicBlock* header = node->loop_info->GetHeader(); |
| 260 | HBasicBlock* preheader = node->loop_info->GetPreHeader(); |
Aart Bik | 9abf894 | 2016-10-14 09:49:42 -0700 | [diff] [blame] | 261 | // Ensure loop header logic is finite. |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 262 | int64_t tc = 0; |
| 263 | if (!induction_range_.IsFinite(node->loop_info, &tc)) { |
| 264 | return false; |
Aart Bik | 9abf894 | 2016-10-14 09:49:42 -0700 | [diff] [blame] | 265 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 266 | // Ensure there is only a single loop-body (besides the header). |
| 267 | HBasicBlock* body = nullptr; |
| 268 | for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) { |
| 269 | if (it.Current() != header) { |
| 270 | if (body != nullptr) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 271 | return false; |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 272 | } |
| 273 | body = it.Current(); |
| 274 | } |
| 275 | } |
| 276 | // Ensure there is only a single exit point. |
| 277 | if (header->GetSuccessors().size() != 2) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 278 | return false; |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 279 | } |
| 280 | HBasicBlock* exit = (header->GetSuccessors()[0] == body) |
| 281 | ? header->GetSuccessors()[1] |
| 282 | : header->GetSuccessors()[0]; |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 283 | // Ensure exit can only be reached by exiting loop. |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 284 | if (exit->GetPredecessors().size() != 1) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 285 | return false; |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 286 | } |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 287 | // Detect either an empty loop (no side effects other than plain iteration) or |
| 288 | // a trivial loop (just iterating once). Replace subsequent index uses, if any, |
| 289 | // with the last value and remove the loop, possibly after unrolling its body. |
| 290 | HInstruction* phi = header->GetFirstPhi(); |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 291 | iset_->clear(); |
| 292 | int32_t use_count = 0; |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 293 | if (IsEmptyHeader(header)) { |
| 294 | bool is_empty = IsEmptyBody(body); |
| 295 | if ((is_empty || tc == 1) && |
| 296 | IsOnlyUsedAfterLoop(node->loop_info, phi, /*collect_loop_uses*/ true, &use_count) && |
| 297 | // No uses, or proper replacement. |
| 298 | (use_count == 0 || TryReplaceWithLastValue(phi, preheader))) { |
| 299 | if (!is_empty) { |
| 300 | // Unroll the loop body, which sees initial value of the index. |
| 301 | phi->ReplaceWith(phi->InputAt(0)); |
| 302 | preheader->MergeInstructionsWith(body); |
| 303 | } |
| 304 | body->DisconnectAndDelete(); |
| 305 | exit->RemovePredecessor(header); |
| 306 | header->RemoveSuccessor(exit); |
| 307 | header->RemoveDominatedBlock(exit); |
| 308 | header->DisconnectAndDelete(); |
| 309 | preheader->AddSuccessor(exit); |
| 310 | preheader->AddInstruction(new (graph_->GetArena()) HGoto()); // global allocator |
| 311 | preheader->AddDominatedBlock(exit); |
| 312 | exit->SetDominator(preheader); |
| 313 | RemoveLoop(node); // update hierarchy |
| 314 | return true; |
| 315 | } |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 316 | } |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 317 | return false; |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 318 | } |
| 319 | |
Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 320 | bool HLoopOptimization::IsPhiInduction(HPhi* phi) { |
| 321 | ArenaSet<HInstruction*>* set = induction_range_.LookupCycle(phi); |
| 322 | if (set != nullptr) { |
Aart Bik | e3dedc5 | 2016-11-02 17:50:27 -0700 | [diff] [blame] | 323 | DCHECK(iset_->empty()); |
Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 324 | for (HInstruction* i : *set) { |
Aart Bik | e3dedc5 | 2016-11-02 17:50:27 -0700 | [diff] [blame] | 325 | // Check that, other than instructions that are no longer in the graph (removed earlier) |
| 326 | // each instruction is removable and, other than the phi, uses are contained in the cycle. |
| 327 | if (!i->IsInBlock()) { |
| 328 | continue; |
| 329 | } else if (!i->IsRemovable()) { |
| 330 | return false; |
| 331 | } else if (i != phi) { |
Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 332 | for (const HUseListNode<HInstruction*>& use : i->GetUses()) { |
| 333 | if (set->find(use.GetUser()) == set->end()) { |
| 334 | return false; |
| 335 | } |
| 336 | } |
| 337 | } |
Aart Bik | e3dedc5 | 2016-11-02 17:50:27 -0700 | [diff] [blame] | 338 | iset_->insert(i); // copy |
Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 339 | } |
Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 340 | return true; |
| 341 | } |
| 342 | return false; |
| 343 | } |
| 344 | |
| 345 | // Find: phi: Phi(init, addsub) |
| 346 | // s: SuspendCheck |
| 347 | // c: Condition(phi, bound) |
| 348 | // i: If(c) |
| 349 | // TODO: Find a less pattern matching approach? |
| 350 | bool HLoopOptimization::IsEmptyHeader(HBasicBlock* block) { |
| 351 | DCHECK(iset_->empty()); |
| 352 | HInstruction* phi = block->GetFirstPhi(); |
| 353 | if (phi != nullptr && phi->GetNext() == nullptr && IsPhiInduction(phi->AsPhi())) { |
| 354 | HInstruction* s = block->GetFirstInstruction(); |
| 355 | if (s != nullptr && s->IsSuspendCheck()) { |
| 356 | HInstruction* c = s->GetNext(); |
| 357 | if (c != nullptr && c->IsCondition() && c->GetUses().HasExactlyOneElement()) { |
| 358 | HInstruction* i = c->GetNext(); |
| 359 | if (i != nullptr && i->IsIf() && i->InputAt(0) == c) { |
| 360 | iset_->insert(c); |
| 361 | iset_->insert(s); |
| 362 | return true; |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | return false; |
| 368 | } |
| 369 | |
| 370 | bool HLoopOptimization::IsEmptyBody(HBasicBlock* block) { |
| 371 | if (block->GetFirstPhi() == nullptr) { |
| 372 | for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { |
| 373 | HInstruction* instruction = it.Current(); |
| 374 | if (!instruction->IsGoto() && iset_->find(instruction) == iset_->end()) { |
| 375 | return false; |
| 376 | } |
| 377 | } |
| 378 | return true; |
| 379 | } |
| 380 | return false; |
| 381 | } |
| 382 | |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 383 | bool HLoopOptimization::IsOnlyUsedAfterLoop(HLoopInformation* loop_info, |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 384 | HInstruction* instruction, |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 385 | bool collect_loop_uses, |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 386 | /*out*/ int32_t* use_count) { |
| 387 | for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) { |
| 388 | HInstruction* user = use.GetUser(); |
| 389 | if (iset_->find(user) == iset_->end()) { // not excluded? |
| 390 | HLoopInformation* other_loop_info = user->GetBlock()->GetLoopInformation(); |
Aart Bik | 482095d | 2016-10-10 15:39:10 -0700 | [diff] [blame] | 391 | if (other_loop_info != nullptr && other_loop_info->IsIn(*loop_info)) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 392 | // If collect_loop_uses is set, simply keep adding those uses to the set. |
| 393 | // Otherwise, reject uses inside the loop that were not already in the set. |
| 394 | if (collect_loop_uses) { |
| 395 | iset_->insert(user); |
| 396 | continue; |
| 397 | } |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 398 | return false; |
| 399 | } |
| 400 | ++*use_count; |
| 401 | } |
| 402 | } |
| 403 | return true; |
| 404 | } |
| 405 | |
Aart Bik | 807868e | 2016-11-03 17:51:43 -0700 | [diff] [blame] | 406 | bool HLoopOptimization::TryReplaceWithLastValue(HInstruction* instruction, HBasicBlock* block) { |
| 407 | // Try to replace outside uses with the last value. Environment uses can consume this |
| 408 | // value too, since any first true use is outside the loop (although this may imply |
| 409 | // that de-opting may look "ahead" a bit on the phi value). If there are only environment |
| 410 | // uses, the value is dropped altogether, since the computations have no effect. |
| 411 | if (induction_range_.CanGenerateLastValue(instruction)) { |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 412 | HInstruction* replacement = induction_range_.GenerateLastValue(instruction, graph_, block); |
| 413 | const HUseList<HInstruction*>& uses = instruction->GetUses(); |
| 414 | for (auto it = uses.begin(), end = uses.end(); it != end;) { |
| 415 | HInstruction* user = it->GetUser(); |
| 416 | size_t index = it->GetIndex(); |
| 417 | ++it; // increment before replacing |
| 418 | if (iset_->find(user) == iset_->end()) { // not excluded? |
| 419 | user->ReplaceInput(replacement, index); |
| 420 | induction_range_.Replace(user, instruction, replacement); // update induction |
| 421 | } |
| 422 | } |
| 423 | const HUseList<HEnvironment*>& env_uses = instruction->GetEnvUses(); |
| 424 | for (auto it = env_uses.begin(), end = env_uses.end(); it != end;) { |
| 425 | HEnvironment* user = it->GetUser(); |
| 426 | size_t index = it->GetIndex(); |
| 427 | ++it; // increment before replacing |
| 428 | if (iset_->find(user->GetHolder()) == iset_->end()) { // not excluded? |
| 429 | user->RemoveAsUserOfInput(index); |
| 430 | user->SetRawEnvAt(index, replacement); |
| 431 | replacement->AddEnvUseAt(user, index); |
| 432 | } |
| 433 | } |
| 434 | induction_simplication_count_++; |
Aart Bik | 807868e | 2016-11-03 17:51:43 -0700 | [diff] [blame] | 435 | return true; |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 436 | } |
Aart Bik | 807868e | 2016-11-03 17:51:43 -0700 | [diff] [blame] | 437 | return false; |
Aart Bik | 8c4a854 | 2016-10-06 11:36:57 -0700 | [diff] [blame] | 438 | } |
| 439 | |
Aart Bik | 6b69e0a | 2017-01-11 10:20:43 -0800 | [diff] [blame] | 440 | void HLoopOptimization::RemoveDeadInstructions(const HInstructionList& list) { |
| 441 | for (HBackwardInstructionIterator i(list); !i.Done(); i.Advance()) { |
| 442 | HInstruction* instruction = i.Current(); |
| 443 | if (instruction->IsDeadAndRemovable()) { |
| 444 | simplified_ = true; |
| 445 | instruction->GetBlock()->RemoveInstructionOrPhi(instruction); |
| 446 | } |
| 447 | } |
| 448 | } |
| 449 | |
Aart Bik | 281c681 | 2016-08-26 11:31:48 -0700 | [diff] [blame] | 450 | } // namespace art |