Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 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 "ssa_liveness_analysis.h" |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 18 | |
Ian Rogers | e77493c | 2014-08-20 15:08:45 -0700 | [diff] [blame] | 19 | #include "base/bit_vector-inl.h" |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 20 | #include "code_generator.h" |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 21 | #include "nodes.h" |
| 22 | |
| 23 | namespace art { |
| 24 | |
| 25 | void SsaLivenessAnalysis::Analyze() { |
Nicolas Geoffray | 0d3f578 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 26 | LinearizeGraph(); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 27 | NumberInstructions(); |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 28 | ComputeLiveness(); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 29 | } |
| 30 | |
Nicolas Geoffray | 0d3f578 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 31 | static bool IsLoopExit(HLoopInformation* current, HLoopInformation* to) { |
| 32 | // `to` is either not part of a loop, or `current` is an inner loop of `to`. |
| 33 | return to == nullptr || (current != to && current->IsIn(*to)); |
| 34 | } |
| 35 | |
| 36 | static bool IsLoop(HLoopInformation* info) { |
| 37 | return info != nullptr; |
| 38 | } |
| 39 | |
| 40 | static bool InSameLoop(HLoopInformation* first_loop, HLoopInformation* second_loop) { |
| 41 | return first_loop == second_loop; |
| 42 | } |
| 43 | |
| 44 | static bool IsInnerLoop(HLoopInformation* outer, HLoopInformation* inner) { |
| 45 | return (inner != outer) |
| 46 | && (inner != nullptr) |
| 47 | && (outer != nullptr) |
| 48 | && inner->IsIn(*outer); |
| 49 | } |
| 50 | |
| 51 | static void VisitBlockForLinearization(HBasicBlock* block, |
| 52 | GrowableArray<HBasicBlock*>* order, |
| 53 | ArenaBitVector* visited) { |
| 54 | if (visited->IsBitSet(block->GetBlockId())) { |
| 55 | return; |
| 56 | } |
| 57 | visited->SetBit(block->GetBlockId()); |
| 58 | size_t number_of_successors = block->GetSuccessors().Size(); |
| 59 | if (number_of_successors == 0) { |
| 60 | // Nothing to do. |
| 61 | } else if (number_of_successors == 1) { |
| 62 | VisitBlockForLinearization(block->GetSuccessors().Get(0), order, visited); |
| 63 | } else { |
| 64 | DCHECK_EQ(number_of_successors, 2u); |
| 65 | HBasicBlock* first_successor = block->GetSuccessors().Get(0); |
| 66 | HBasicBlock* second_successor = block->GetSuccessors().Get(1); |
| 67 | HLoopInformation* my_loop = block->GetLoopInformation(); |
| 68 | HLoopInformation* first_loop = first_successor->GetLoopInformation(); |
| 69 | HLoopInformation* second_loop = second_successor->GetLoopInformation(); |
| 70 | |
| 71 | if (!IsLoop(my_loop)) { |
| 72 | // Nothing to do. Current order is fine. |
| 73 | } else if (IsLoopExit(my_loop, second_loop) && InSameLoop(my_loop, first_loop)) { |
| 74 | // Visit the loop exit first in post order. |
| 75 | std::swap(first_successor, second_successor); |
| 76 | } else if (IsInnerLoop(my_loop, first_loop) && !IsInnerLoop(my_loop, second_loop)) { |
| 77 | // Visit the inner loop last in post order. |
| 78 | std::swap(first_successor, second_successor); |
| 79 | } |
| 80 | VisitBlockForLinearization(first_successor, order, visited); |
| 81 | VisitBlockForLinearization(second_successor, order, visited); |
| 82 | } |
| 83 | order->Add(block); |
| 84 | } |
| 85 | |
Nicolas Geoffray | 0d3f578 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 86 | void SsaLivenessAnalysis::LinearizeGraph() { |
| 87 | // For simplicity of the implementation, we create post linear order. The order for |
| 88 | // computing live ranges is the reverse of that order. |
| 89 | ArenaBitVector visited(graph_.GetArena(), graph_.GetBlocks().Size(), false); |
| 90 | VisitBlockForLinearization(graph_.GetEntryBlock(), &linear_post_order_, &visited); |
| 91 | } |
| 92 | |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 93 | void SsaLivenessAnalysis::NumberInstructions() { |
| 94 | int ssa_index = 0; |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 95 | size_t lifetime_position = 0; |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 96 | // Each instruction gets a lifetime position, and a block gets a lifetime |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 97 | // start and end position. Non-phi instructions have a distinct lifetime position than |
| 98 | // the block they are in. Phi instructions have the lifetime start of their block as |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 99 | // lifetime position. |
| 100 | // |
| 101 | // Because the register allocator will insert moves in the graph, we need |
| 102 | // to differentiate between the start and end of an instruction. Adding 2 to |
| 103 | // the lifetime position for each instruction ensures the start of an |
| 104 | // instruction is different than the end of the previous instruction. |
Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 105 | HGraphVisitor* location_builder = codegen_->GetLocationBuilder(); |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 106 | for (HLinearOrderIterator it(*this); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 107 | HBasicBlock* block = it.Current(); |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 108 | block->SetLifetimeStart(lifetime_position); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 109 | |
Nicolas Geoffray | f635e63 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 110 | for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 111 | HInstruction* current = it.Current(); |
Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 112 | current->Accept(location_builder); |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 113 | LocationSummary* locations = current->GetLocations(); |
| 114 | if (locations != nullptr && locations->Out().IsValid()) { |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 115 | instructions_from_ssa_index_.Add(current); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 116 | current->SetSsaIndex(ssa_index++); |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 117 | current->SetLiveInterval( |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 118 | new (graph_.GetArena()) LiveInterval(graph_.GetArena(), current->GetType(), current)); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 119 | } |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 120 | current->SetLifetimePosition(lifetime_position); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 121 | } |
Nicolas Geoffray | ec7e472 | 2014-06-06 11:24:33 +0100 | [diff] [blame] | 122 | lifetime_position += 2; |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 123 | |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 124 | // Add a null marker to notify we are starting a block. |
| 125 | instructions_from_lifetime_position_.Add(nullptr); |
| 126 | |
Nicolas Geoffray | f635e63 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 127 | for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 128 | HInstruction* current = it.Current(); |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 129 | current->Accept(codegen_->GetLocationBuilder()); |
| 130 | LocationSummary* locations = current->GetLocations(); |
| 131 | if (locations != nullptr && locations->Out().IsValid()) { |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 132 | instructions_from_ssa_index_.Add(current); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 133 | current->SetSsaIndex(ssa_index++); |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 134 | current->SetLiveInterval( |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 135 | new (graph_.GetArena()) LiveInterval(graph_.GetArena(), current->GetType(), current)); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 136 | } |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 137 | instructions_from_lifetime_position_.Add(current); |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 138 | current->SetLifetimePosition(lifetime_position); |
| 139 | lifetime_position += 2; |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 140 | } |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 141 | |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 142 | block->SetLifetimeEnd(lifetime_position); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 143 | } |
| 144 | number_of_ssa_values_ = ssa_index; |
| 145 | } |
| 146 | |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 147 | void SsaLivenessAnalysis::ComputeLiveness() { |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 148 | for (HLinearOrderIterator it(*this); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 149 | HBasicBlock* block = it.Current(); |
| 150 | block_infos_.Put( |
| 151 | block->GetBlockId(), |
| 152 | new (graph_.GetArena()) BlockInfo(graph_.GetArena(), *block, number_of_ssa_values_)); |
| 153 | } |
| 154 | |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 155 | // Compute the live ranges, as well as the initial live_in, live_out, and kill sets. |
| 156 | // This method does not handle backward branches for the sets, therefore live_in |
| 157 | // and live_out sets are not yet correct. |
| 158 | ComputeLiveRanges(); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 159 | |
| 160 | // Do a fixed point calculation to take into account backward branches, |
| 161 | // that will update live_in of loop headers, and therefore live_out and live_in |
| 162 | // of blocks in the loop. |
| 163 | ComputeLiveInAndLiveOutSets(); |
| 164 | } |
| 165 | |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 166 | void SsaLivenessAnalysis::ComputeLiveRanges() { |
| 167 | // Do a post order visit, adding inputs of instructions live in the block where |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 168 | // that instruction is defined, and killing instructions that are being visited. |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 169 | for (HLinearPostOrderIterator it(*this); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 170 | HBasicBlock* block = it.Current(); |
| 171 | |
| 172 | BitVector* kill = GetKillSet(*block); |
| 173 | BitVector* live_in = GetLiveInSet(*block); |
| 174 | |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 175 | // Set phi inputs of successors of this block corresponding to this block |
| 176 | // as live_in. |
| 177 | for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) { |
| 178 | HBasicBlock* successor = block->GetSuccessors().Get(i); |
| 179 | live_in->Union(GetLiveInSet(*successor)); |
| 180 | size_t phi_input_index = successor->GetPredecessorIndexOf(block); |
| 181 | for (HInstructionIterator it(successor->GetPhis()); !it.Done(); it.Advance()) { |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 182 | HInstruction* phi = it.Current(); |
| 183 | HInstruction* input = phi->InputAt(phi_input_index); |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 184 | input->GetLiveInterval()->AddPhiUse(phi, phi_input_index, block); |
Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 185 | // A phi input whose last user is the phi dies at the end of the predecessor block, |
| 186 | // and not at the phi's lifetime position. |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 187 | live_in->SetBit(input->GetSsaIndex()); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | // Add a range that covers this block to all instructions live_in because of successors. |
Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 192 | // Instructions defined in this block will have their start of the range adjusted. |
Vladimir Marko | a5b8fde | 2014-05-23 15:16:44 +0100 | [diff] [blame] | 193 | for (uint32_t idx : live_in->Indexes()) { |
| 194 | HInstruction* current = instructions_from_ssa_index_.Get(idx); |
| 195 | current->GetLiveInterval()->AddRange(block->GetLifetimeStart(), block->GetLifetimeEnd()); |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 196 | } |
| 197 | |
Nicolas Geoffray | f635e63 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 198 | for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 199 | HInstruction* current = it.Current(); |
| 200 | if (current->HasSsaIndex()) { |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 201 | // Kill the instruction and shorten its interval. |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 202 | kill->SetBit(current->GetSsaIndex()); |
| 203 | live_in->ClearBit(current->GetSsaIndex()); |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 204 | current->GetLiveInterval()->SetFrom(current->GetLifetimePosition()); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | // All inputs of an instruction must be live. |
| 208 | for (size_t i = 0, e = current->InputCount(); i < e; ++i) { |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 209 | HInstruction* input = current->InputAt(i); |
Nicolas Geoffray | e503832 | 2014-07-04 09:41:32 +0100 | [diff] [blame] | 210 | // Some instructions 'inline' their inputs, that is they do not need |
| 211 | // to be materialized. |
| 212 | if (input->HasSsaIndex()) { |
| 213 | live_in->SetBit(input->GetSsaIndex()); |
| 214 | input->GetLiveInterval()->AddUse(current, i, false); |
| 215 | } |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | if (current->HasEnvironment()) { |
| 219 | // All instructions in the environment must be live. |
| 220 | GrowableArray<HInstruction*>* environment = current->GetEnvironment()->GetVRegs(); |
| 221 | for (size_t i = 0, e = environment->Size(); i < e; ++i) { |
| 222 | HInstruction* instruction = environment->Get(i); |
| 223 | if (instruction != nullptr) { |
| 224 | DCHECK(instruction->HasSsaIndex()); |
| 225 | live_in->SetBit(instruction->GetSsaIndex()); |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 226 | instruction->GetLiveInterval()->AddUse(current, i, true); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 227 | } |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 232 | // Kill phis defined in this block. |
Nicolas Geoffray | f635e63 | 2014-05-14 09:43:38 +0100 | [diff] [blame] | 233 | for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 234 | HInstruction* current = it.Current(); |
| 235 | if (current->HasSsaIndex()) { |
| 236 | kill->SetBit(current->GetSsaIndex()); |
| 237 | live_in->ClearBit(current->GetSsaIndex()); |
Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 238 | LiveInterval* interval = current->GetLiveInterval(); |
| 239 | DCHECK((interval->GetFirstRange() == nullptr) |
| 240 | || (interval->GetStart() == current->GetLifetimePosition())); |
| 241 | interval->SetFrom(current->GetLifetimePosition()); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 242 | } |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 243 | } |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 244 | |
Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 245 | if (block->IsLoopHeader()) { |
| 246 | HBasicBlock* back_edge = block->GetLoopInformation()->GetBackEdges().Get(0); |
| 247 | // For all live_in instructions at the loop header, we need to create a range |
| 248 | // that covers the full loop. |
Vladimir Marko | a5b8fde | 2014-05-23 15:16:44 +0100 | [diff] [blame] | 249 | for (uint32_t idx : live_in->Indexes()) { |
| 250 | HInstruction* current = instructions_from_ssa_index_.Get(idx); |
| 251 | current->GetLiveInterval()->AddLoopRange(block->GetLifetimeStart(), |
| 252 | back_edge->GetLifetimeEnd()); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 253 | } |
| 254 | } |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | void SsaLivenessAnalysis::ComputeLiveInAndLiveOutSets() { |
| 259 | bool changed; |
| 260 | do { |
| 261 | changed = false; |
| 262 | |
| 263 | for (HPostOrderIterator it(graph_); !it.Done(); it.Advance()) { |
| 264 | const HBasicBlock& block = *it.Current(); |
| 265 | |
| 266 | // The live_in set depends on the kill set (which does not |
| 267 | // change in this loop), and the live_out set. If the live_out |
| 268 | // set does not change, there is no need to update the live_in set. |
| 269 | if (UpdateLiveOut(block) && UpdateLiveIn(block)) { |
| 270 | changed = true; |
| 271 | } |
| 272 | } |
| 273 | } while (changed); |
| 274 | } |
| 275 | |
| 276 | bool SsaLivenessAnalysis::UpdateLiveOut(const HBasicBlock& block) { |
| 277 | BitVector* live_out = GetLiveOutSet(block); |
| 278 | bool changed = false; |
| 279 | // The live_out set of a block is the union of live_in sets of its successors. |
Nicolas Geoffray | 622d9c3 | 2014-05-12 16:11:02 +0100 | [diff] [blame] | 280 | for (size_t i = 0, e = block.GetSuccessors().Size(); i < e; ++i) { |
| 281 | HBasicBlock* successor = block.GetSuccessors().Get(i); |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 282 | if (live_out->Union(GetLiveInSet(*successor))) { |
| 283 | changed = true; |
| 284 | } |
| 285 | } |
| 286 | return changed; |
| 287 | } |
| 288 | |
| 289 | |
| 290 | bool SsaLivenessAnalysis::UpdateLiveIn(const HBasicBlock& block) { |
| 291 | BitVector* live_out = GetLiveOutSet(block); |
| 292 | BitVector* kill = GetKillSet(block); |
| 293 | BitVector* live_in = GetLiveInSet(block); |
| 294 | // If live_out is updated (because of backward branches), we need to make |
| 295 | // sure instructions in live_out are also in live_in, unless they are killed |
| 296 | // by this block. |
| 297 | return live_in->UnionIfNotIn(live_out, kill); |
| 298 | } |
| 299 | |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 300 | int LiveInterval::FindFirstRegisterHint(size_t* free_until) const { |
| 301 | if (GetParent() == this && defined_by_ != nullptr) { |
| 302 | // This is the first interval for the instruction. Try to find |
| 303 | // a register based on its definition. |
| 304 | DCHECK_EQ(defined_by_->GetLiveInterval(), this); |
| 305 | int hint = FindHintAtDefinition(); |
| 306 | if (hint != kNoRegister && free_until[hint] > GetStart()) { |
| 307 | return hint; |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | UsePosition* use = first_use_; |
| 312 | size_t start = GetStart(); |
| 313 | size_t end = GetEnd(); |
| 314 | while (use != nullptr && use->GetPosition() <= end) { |
| 315 | size_t use_position = use->GetPosition(); |
| 316 | if (use_position >= start && !use->GetIsEnvironment()) { |
| 317 | HInstruction* user = use->GetUser(); |
| 318 | size_t input_index = use->GetInputIndex(); |
| 319 | if (user->IsPhi()) { |
| 320 | // If the phi has a register, try to use the same. |
| 321 | Location phi_location = user->GetLiveInterval()->ToLocation(); |
Nicolas Geoffray | 102cbed | 2014-10-15 18:31:05 +0100 | [diff] [blame] | 322 | if (SameRegisterKind(phi_location) && free_until[phi_location.reg()] >= use_position) { |
Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 323 | return phi_location.reg(); |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 324 | } |
| 325 | const GrowableArray<HBasicBlock*>& predecessors = user->GetBlock()->GetPredecessors(); |
| 326 | // If the instruction dies at the phi assignment, we can try having the |
| 327 | // same register. |
| 328 | if (end == predecessors.Get(input_index)->GetLifetimeEnd()) { |
| 329 | for (size_t i = 0, e = user->InputCount(); i < e; ++i) { |
| 330 | if (i == input_index) { |
| 331 | continue; |
| 332 | } |
| 333 | HInstruction* input = user->InputAt(i); |
| 334 | Location location = input->GetLiveInterval()->GetLocationAt( |
| 335 | predecessors.Get(i)->GetLifetimeEnd() - 1); |
Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 336 | if (location.IsRegister() && free_until[location.reg()] >= use_position) { |
| 337 | return location.reg(); |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 338 | } |
| 339 | } |
| 340 | } |
| 341 | } else { |
| 342 | // If the instruction is expected in a register, try to use it. |
| 343 | LocationSummary* locations = user->GetLocations(); |
| 344 | Location expected = locations->InAt(use->GetInputIndex()); |
| 345 | // We use the user's lifetime position - 1 (and not `use_position`) because the |
| 346 | // register is blocked at the beginning of the user. |
| 347 | size_t position = user->GetLifetimePosition() - 1; |
Nicolas Geoffray | 102cbed | 2014-10-15 18:31:05 +0100 | [diff] [blame] | 348 | if (SameRegisterKind(expected) && free_until[expected.reg()] >= position) { |
Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 349 | return expected.reg(); |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 350 | } |
| 351 | } |
| 352 | } |
| 353 | use = use->GetNext(); |
| 354 | } |
| 355 | |
| 356 | return kNoRegister; |
| 357 | } |
| 358 | |
| 359 | int LiveInterval::FindHintAtDefinition() const { |
| 360 | if (defined_by_->IsPhi()) { |
| 361 | // Try to use the same register as one of the inputs. |
| 362 | const GrowableArray<HBasicBlock*>& predecessors = defined_by_->GetBlock()->GetPredecessors(); |
| 363 | for (size_t i = 0, e = defined_by_->InputCount(); i < e; ++i) { |
| 364 | HInstruction* input = defined_by_->InputAt(i); |
| 365 | size_t end = predecessors.Get(i)->GetLifetimeEnd(); |
| 366 | const LiveInterval& input_interval = input->GetLiveInterval()->GetIntervalAt(end - 1); |
| 367 | if (input_interval.GetEnd() == end) { |
| 368 | // If the input dies at the end of the predecessor, we know its register can |
| 369 | // be reused. |
| 370 | Location input_location = input_interval.ToLocation(); |
Nicolas Geoffray | 102cbed | 2014-10-15 18:31:05 +0100 | [diff] [blame] | 371 | if (SameRegisterKind(input_location)) { |
Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 372 | return input_location.reg(); |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 373 | } |
| 374 | } |
| 375 | } |
| 376 | } else { |
| 377 | LocationSummary* locations = GetDefinedBy()->GetLocations(); |
| 378 | Location out = locations->Out(); |
| 379 | if (out.IsUnallocated() && out.GetPolicy() == Location::kSameAsFirstInput) { |
| 380 | // Try to use the same register as the first input. |
| 381 | const LiveInterval& input_interval = |
| 382 | GetDefinedBy()->InputAt(0)->GetLiveInterval()->GetIntervalAt(GetStart() - 1); |
| 383 | if (input_interval.GetEnd() == GetStart()) { |
| 384 | // If the input dies at the start of this instruction, we know its register can |
| 385 | // be reused. |
| 386 | Location location = input_interval.ToLocation(); |
Nicolas Geoffray | 102cbed | 2014-10-15 18:31:05 +0100 | [diff] [blame] | 387 | if (SameRegisterKind(location)) { |
Nicolas Geoffray | 56b9ee6 | 2014-10-09 11:47:51 +0100 | [diff] [blame] | 388 | return location.reg(); |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 389 | } |
| 390 | } |
| 391 | } |
| 392 | } |
| 393 | return kNoRegister; |
| 394 | } |
| 395 | |
Nicolas Geoffray | 102cbed | 2014-10-15 18:31:05 +0100 | [diff] [blame] | 396 | bool LiveInterval::SameRegisterKind(Location other) const { |
| 397 | return IsFloatingPoint() |
| 398 | ? other.IsFpuRegister() |
| 399 | : other.IsRegister(); |
| 400 | } |
| 401 | |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 402 | bool LiveInterval::NeedsTwoSpillSlots() const { |
| 403 | return type_ == Primitive::kPrimLong || type_ == Primitive::kPrimDouble; |
| 404 | } |
| 405 | |
| 406 | Location LiveInterval::ToLocation() const { |
| 407 | if (HasRegister()) { |
Nicolas Geoffray | 102cbed | 2014-10-15 18:31:05 +0100 | [diff] [blame] | 408 | return IsFloatingPoint() |
| 409 | ? Location::FpuRegisterLocation(GetRegister()) |
| 410 | : Location::RegisterLocation(GetRegister()); |
Nicolas Geoffray | 01ef345 | 2014-10-01 11:32:17 +0100 | [diff] [blame] | 411 | } else { |
| 412 | HInstruction* defined_by = GetParent()->GetDefinedBy(); |
| 413 | if (defined_by->IsConstant()) { |
| 414 | return defined_by->GetLocations()->Out(); |
| 415 | } else if (GetParent()->HasSpillSlot()) { |
| 416 | if (NeedsTwoSpillSlots()) { |
| 417 | return Location::DoubleStackSlot(GetParent()->GetSpillSlot()); |
| 418 | } else { |
| 419 | return Location::StackSlot(GetParent()->GetSpillSlot()); |
| 420 | } |
| 421 | } else { |
| 422 | return Location(); |
| 423 | } |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | Location LiveInterval::GetLocationAt(size_t position) const { |
| 428 | return GetIntervalAt(position).ToLocation(); |
| 429 | } |
| 430 | |
| 431 | const LiveInterval& LiveInterval::GetIntervalAt(size_t position) const { |
| 432 | const LiveInterval* current = this; |
| 433 | while (!current->Covers(position)) { |
| 434 | current = current->GetNextSibling(); |
| 435 | DCHECK(current != nullptr); |
| 436 | } |
| 437 | return *current; |
| 438 | } |
| 439 | |
Nicolas Geoffray | 804d093 | 2014-05-02 08:46:00 +0100 | [diff] [blame] | 440 | } // namespace art |