blob: 9ba75b8da42ed3618cd3848bde3f7d2c715e9d27 [file] [log] [blame]
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001/*
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 "register_allocator.h"
18
Ian Rogerse77493c2014-08-20 15:08:45 -070019#include "base/bit_vector-inl.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010020#include "code_generator.h"
21#include "ssa_liveness_analysis.h"
22
23namespace art {
24
25static constexpr size_t kMaxLifetimePosition = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010026static constexpr size_t kDefaultNumberOfSpillSlots = 4;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010027
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010028RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
29 CodeGenerator* codegen,
30 const SsaLivenessAnalysis& liveness)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010031 : allocator_(allocator),
32 codegen_(codegen),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010033 liveness_(liveness),
Nicolas Geoffray39468442014-09-02 15:17:15 +010034 unhandled_core_intervals_(allocator, 0),
35 unhandled_fp_intervals_(allocator, 0),
36 unhandled_(nullptr),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010037 handled_(allocator, 0),
38 active_(allocator, 0),
39 inactive_(allocator, 0),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010040 physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
Nicolas Geoffray39468442014-09-02 15:17:15 +010041 temp_intervals_(allocator, 4),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010042 spill_slots_(allocator, kDefaultNumberOfSpillSlots),
Nicolas Geoffray39468442014-09-02 15:17:15 +010043 safepoints_(allocator, 0),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010044 processing_core_registers_(false),
45 number_of_registers_(-1),
46 registers_array_(nullptr),
Nicolas Geoffray39468442014-09-02 15:17:15 +010047 blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())),
48 reserved_out_slots_(0) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010049 codegen->SetupBlockedRegisters(blocked_registers_);
50 physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
Nicolas Geoffray39468442014-09-02 15:17:15 +010051 // Always reserve for the current method and the graph's max out registers.
52 // TODO: compute it instead.
53 reserved_out_slots_ = 1 + codegen->GetGraph()->GetMaximumNumberOfOutVRegs();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010054}
55
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010056bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
57 InstructionSet instruction_set) {
58 if (!Supports(instruction_set)) {
59 return false;
60 }
61 for (size_t i = 0, e = graph.GetBlocks().Size(); i < e; ++i) {
62 for (HInstructionIterator it(graph.GetBlocks().Get(i)->GetInstructions());
63 !it.Done();
64 it.Advance()) {
65 HInstruction* current = it.Current();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +010066 if (current->GetType() == Primitive::kPrimLong && instruction_set != kX86_64) return false;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010067 if (current->GetType() == Primitive::kPrimFloat) return false;
68 if (current->GetType() == Primitive::kPrimDouble) return false;
69 }
70 }
71 return true;
72}
73
74static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 if (interval == nullptr) return false;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010076 bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
77 && (interval->GetType() != Primitive::kPrimFloat);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010078 return processing_core_registers == is_core_register;
79}
80
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010081void RegisterAllocator::AllocateRegisters() {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010082 AllocateRegistersInternal();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010083 Resolve();
84
85 if (kIsDebugBuild) {
86 processing_core_registers_ = true;
87 ValidateInternal(true);
88 processing_core_registers_ = false;
89 ValidateInternal(true);
90 }
91}
92
93void RegisterAllocator::BlockRegister(Location location,
94 size_t start,
95 size_t end,
96 Primitive::Type type) {
97 int reg = location.reg().RegId();
98 LiveInterval* interval = physical_register_intervals_.Get(reg);
99 if (interval == nullptr) {
100 interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
101 physical_register_intervals_.Put(reg, interval);
102 inactive_.Add(interval);
103 }
104 DCHECK(interval->GetRegister() == reg);
105 interval->AddRange(start, end);
106}
107
108void RegisterAllocator::AllocateRegistersInternal() {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100109 // Iterate post-order, to ensure the list is sorted, and the last added interval
110 // is the one with the lowest start position.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100111 for (HLinearPostOrderIterator it(liveness_); !it.Done(); it.Advance()) {
112 HBasicBlock* block = it.Current();
113 for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
114 ProcessInstruction(it.Current());
115 }
116 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
117 ProcessInstruction(it.Current());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118 }
119 }
120
Nicolas Geoffray39468442014-09-02 15:17:15 +0100121 number_of_registers_ = codegen_->GetNumberOfCoreRegisters();
122 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
123 processing_core_registers_ = true;
124 unhandled_ = &unhandled_core_intervals_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100125 LinearScan();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100126
127 inactive_.Reset();
128 active_.Reset();
129 handled_.Reset();
130
131 number_of_registers_ = codegen_->GetNumberOfFloatingPointRegisters();
132 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
133 processing_core_registers_ = false;
134 unhandled_ = &unhandled_fp_intervals_;
135 // TODO: Enable FP register allocation.
136 DCHECK(unhandled_->IsEmpty());
137 LinearScan();
138}
139
140void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
141 LocationSummary* locations = instruction->GetLocations();
142 size_t position = instruction->GetLifetimePosition();
143
144 if (locations == nullptr) return;
145
146 // Create synthesized intervals for temporaries.
147 for (size_t i = 0; i < locations->GetTempCount(); ++i) {
148 Location temp = locations->GetTemp(i);
149 if (temp.IsRegister()) {
150 BlockRegister(temp, position, position + 1, Primitive::kPrimInt);
151 } else {
152 LiveInterval* interval =
153 LiveInterval::MakeTempInterval(allocator_, instruction, Primitive::kPrimInt);
154 temp_intervals_.Add(interval);
155 interval->AddRange(position, position + 1);
156 unhandled_core_intervals_.Add(interval);
157 }
158 }
159
160 if (locations->CanCall()) {
161 codegen_->MarkNotLeaf();
162 safepoints_.Add(instruction);
163 // Block all registers.
164 for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
165 BlockRegister(Location::RegisterLocation(ManagedRegister(i)),
166 position,
167 position + 1,
168 Primitive::kPrimInt);
169 }
170 }
171
172 for (size_t i = 0; i < instruction->InputCount(); ++i) {
173 Location input = locations->InAt(i);
174 if (input.IsRegister()) {
175 BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
176 }
177 }
178
179 bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
180 && (instruction->GetType() != Primitive::kPrimFloat);
181 GrowableArray<LiveInterval*>& unhandled = core_register
182 ? unhandled_core_intervals_
183 : unhandled_fp_intervals_;
184
185 LiveInterval* current = instruction->GetLiveInterval();
186 if (current == nullptr) return;
187
188 DCHECK(unhandled.IsEmpty() || current->StartsBefore(unhandled.Peek()));
189 // Some instructions define their output in fixed register/stack slot. We need
190 // to ensure we know these locations before doing register allocation. For a
191 // given register, we create an interval that covers these locations. The register
192 // will be unavailable at these locations when trying to allocate one for an
193 // interval.
194 //
195 // The backwards walking ensures the ranges are ordered on increasing start positions.
196 Location output = locations->Out();
197 if (output.IsRegister()) {
198 // Shift the interval's start by one to account for the blocked register.
199 current->SetFrom(position + 1);
200 current->SetRegister(output.reg().RegId());
201 BlockRegister(output, position, position + 1, instruction->GetType());
202 } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
203 current->SetSpillSlot(output.GetStackIndex());
204 }
205
206 // If needed, add interval to the list of unhandled intervals.
207 if (current->HasSpillSlot() || instruction->IsConstant()) {
208 // Split before first register use.
209 size_t first_register_use = current->FirstRegisterUse();
210 if (first_register_use != kNoLifetime) {
211 LiveInterval* split = Split(current, first_register_use - 1);
212 // Don't add direclty to `unhandled`, it needs to be sorted and the start
213 // of this new interval might be after intervals already in the list.
214 AddSorted(&unhandled, split);
215 } else {
216 // Nothing to do, we won't allocate a register for this value.
217 }
218 } else {
219 DCHECK(unhandled.IsEmpty() || current->StartsBefore(unhandled.Peek()));
220 unhandled.Add(current);
221 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100222}
223
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100224class AllRangesIterator : public ValueObject {
225 public:
226 explicit AllRangesIterator(LiveInterval* interval)
227 : current_interval_(interval),
228 current_range_(interval->GetFirstRange()) {}
229
230 bool Done() const { return current_interval_ == nullptr; }
231 LiveRange* CurrentRange() const { return current_range_; }
232 LiveInterval* CurrentInterval() const { return current_interval_; }
233
234 void Advance() {
235 current_range_ = current_range_->GetNext();
236 if (current_range_ == nullptr) {
237 current_interval_ = current_interval_->GetNextSibling();
238 if (current_interval_ != nullptr) {
239 current_range_ = current_interval_->GetFirstRange();
240 }
241 }
242 }
243
244 private:
245 LiveInterval* current_interval_;
246 LiveRange* current_range_;
247
248 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
249};
250
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100251bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
252 // To simplify unit testing, we eagerly create the array of intervals, and
253 // call the helper method.
254 GrowableArray<LiveInterval*> intervals(allocator_, 0);
255 for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
256 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
257 if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
258 intervals.Add(instruction->GetLiveInterval());
259 }
260 }
261
262 for (size_t i = 0, e = physical_register_intervals_.Size(); i < e; ++i) {
263 LiveInterval* fixed = physical_register_intervals_.Get(i);
264 if (fixed != nullptr && ShouldProcess(processing_core_registers_, fixed)) {
265 intervals.Add(fixed);
266 }
267 }
268
Nicolas Geoffray39468442014-09-02 15:17:15 +0100269 for (size_t i = 0, e = temp_intervals_.Size(); i < e; ++i) {
270 LiveInterval* temp = temp_intervals_.Get(i);
271 if (ShouldProcess(processing_core_registers_, temp)) {
272 intervals.Add(temp);
273 }
274 }
275
276 return ValidateIntervals(intervals, spill_slots_.Size(), reserved_out_slots_, *codegen_,
277 allocator_, processing_core_registers_, log_fatal_on_failure);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100278}
279
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100280bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
281 size_t number_of_spill_slots,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100282 size_t number_of_out_slots,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100283 const CodeGenerator& codegen,
284 ArenaAllocator* allocator,
285 bool processing_core_registers,
286 bool log_fatal_on_failure) {
287 size_t number_of_registers = processing_core_registers
288 ? codegen.GetNumberOfCoreRegisters()
289 : codegen.GetNumberOfFloatingPointRegisters();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100290 GrowableArray<ArenaBitVector*> liveness_of_values(
291 allocator, number_of_registers + number_of_spill_slots);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100292
293 // Allocate a bit vector per register. A live interval that has a register
294 // allocated will populate the associated bit vector based on its live ranges.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100295 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
296 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100297 }
298
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100299 for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
300 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
301 LiveInterval* current = it.CurrentInterval();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100302 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
303 if (current->GetParent()->HasSpillSlot()
304 // Parameters have their own stack slot.
305 && !(defined_by != nullptr && defined_by->IsParameterValue())) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100306 BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers
307 + current->GetParent()->GetSpillSlot() / kVRegSize
308 - number_of_out_slots);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100309 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
310 if (liveness_of_spill_slot->IsBitSet(j)) {
311 if (log_fatal_on_failure) {
312 std::ostringstream message;
313 message << "Spill slot conflict at " << j;
314 LOG(FATAL) << message.str();
315 } else {
316 return false;
317 }
318 } else {
319 liveness_of_spill_slot->SetBit(j);
320 }
321 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100322 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100323
324 if (current->HasRegister()) {
325 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
326 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
327 if (liveness_of_register->IsBitSet(j)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100328 if (log_fatal_on_failure) {
329 std::ostringstream message;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100330 message << "Register conflict at " << j << " ";
331 if (defined_by != nullptr) {
332 message << "(" << defined_by->DebugName() << ")";
333 }
334 message << "for ";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100335 if (processing_core_registers) {
336 codegen.DumpCoreRegister(message, current->GetRegister());
337 } else {
338 codegen.DumpFloatingPointRegister(message, current->GetRegister());
339 }
340 LOG(FATAL) << message.str();
341 } else {
342 return false;
343 }
344 } else {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100345 liveness_of_register->SetBit(j);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100346 }
347 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100348 }
349 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100350 }
351 return true;
352}
353
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100354void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100355 interval->Dump(stream);
356 stream << ": ";
357 if (interval->HasRegister()) {
358 if (processing_core_registers_) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100359 codegen_->DumpCoreRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100360 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100361 codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100362 }
363 } else {
364 stream << "spilled";
365 }
366 stream << std::endl;
367}
368
369// By the book implementation of a linear scan register allocator.
370void RegisterAllocator::LinearScan() {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100371 while (!unhandled_->IsEmpty()) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100372 // (1) Remove interval with the lowest start position from unhandled.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100373 LiveInterval* current = unhandled_->Pop();
374 DCHECK(!current->IsFixed() && !current->HasSpillSlot());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100375 size_t position = current->GetStart();
376
377 // (2) Remove currently active intervals that are dead at this position.
378 // Move active intervals that have a lifetime hole at this position
379 // to inactive.
380 for (size_t i = 0; i < active_.Size(); ++i) {
381 LiveInterval* interval = active_.Get(i);
382 if (interval->IsDeadAt(position)) {
383 active_.Delete(interval);
384 --i;
385 handled_.Add(interval);
386 } else if (!interval->Covers(position)) {
387 active_.Delete(interval);
388 --i;
389 inactive_.Add(interval);
390 }
391 }
392
393 // (3) Remove currently inactive intervals that are dead at this position.
394 // Move inactive intervals that cover this position to active.
395 for (size_t i = 0; i < inactive_.Size(); ++i) {
396 LiveInterval* interval = inactive_.Get(i);
397 if (interval->IsDeadAt(position)) {
398 inactive_.Delete(interval);
399 --i;
400 handled_.Add(interval);
401 } else if (interval->Covers(position)) {
402 inactive_.Delete(interval);
403 --i;
404 active_.Add(interval);
405 }
406 }
407
408 // (4) Try to find an available register.
409 bool success = TryAllocateFreeReg(current);
410
411 // (5) If no register could be found, we need to spill.
412 if (!success) {
413 success = AllocateBlockedReg(current);
414 }
415
416 // (6) If the interval had a register allocated, add it to the list of active
417 // intervals.
418 if (success) {
419 active_.Add(current);
420 }
421 }
422}
423
424// Find a free register. If multiple are found, pick the register that
425// is free the longest.
426bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
427 size_t* free_until = registers_array_;
428
429 // First set all registers to be free.
430 for (size_t i = 0; i < number_of_registers_; ++i) {
431 free_until[i] = kMaxLifetimePosition;
432 }
433
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100434 // For each inactive interval, set its register to be free until
435 // the next intersection with `current`.
436 // Thanks to SSA, this should only be needed for intervals
437 // that are the result of a split.
438 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
439 LiveInterval* inactive = inactive_.Get(i);
440 DCHECK(inactive->HasRegister());
441 size_t next_intersection = inactive->FirstIntersectionWith(current);
442 if (next_intersection != kNoLifetime) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100443 free_until[inactive->GetRegister()] =
444 std::min(free_until[inactive->GetRegister()], next_intersection);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100445 }
446 }
447
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100448 // For each active interval, set its register to not free.
449 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
450 LiveInterval* interval = active_.Get(i);
451 DCHECK(interval->HasRegister());
452 free_until[interval->GetRegister()] = 0;
453 }
454
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100455 int reg = -1;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100456 if (current->HasRegister()) {
457 // Some instructions have a fixed register output.
458 reg = current->GetRegister();
459 DCHECK_NE(free_until[reg], 0u);
460 } else {
461 // Pick the register that is free the longest.
462 for (size_t i = 0; i < number_of_registers_; ++i) {
463 if (IsBlocked(i)) continue;
464 if (reg == -1 || free_until[i] > free_until[reg]) {
465 reg = i;
466 if (free_until[i] == kMaxLifetimePosition) break;
467 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100468 }
469 }
470
471 // If we could not find a register, we need to spill.
472 if (reg == -1 || free_until[reg] == 0) {
473 return false;
474 }
475
476 current->SetRegister(reg);
477 if (!current->IsDeadAt(free_until[reg])) {
478 // If the register is only available for a subset of live ranges
479 // covered by `current`, split `current` at the position where
480 // the register is not available anymore.
481 LiveInterval* split = Split(current, free_until[reg]);
482 DCHECK(split != nullptr);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100483 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100484 }
485 return true;
486}
487
488bool RegisterAllocator::IsBlocked(int reg) const {
489 // TODO: This only works for core registers and needs to be adjusted for
490 // floating point registers.
491 DCHECK(processing_core_registers_);
492 return blocked_registers_[reg];
493}
494
495// Find the register that is used the last, and spill the interval
496// that holds it. If the first use of `current` is after that register
497// we spill `current` instead.
498bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
499 size_t first_register_use = current->FirstRegisterUse();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100500 if (first_register_use == kNoLifetime) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100501 AllocateSpillSlotFor(current);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100502 return false;
503 }
504
505 // First set all registers as not being used.
506 size_t* next_use = registers_array_;
507 for (size_t i = 0; i < number_of_registers_; ++i) {
508 next_use[i] = kMaxLifetimePosition;
509 }
510
511 // For each active interval, find the next use of its register after the
512 // start of current.
513 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
514 LiveInterval* active = active_.Get(i);
515 DCHECK(active->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100516 if (active->IsFixed()) {
517 next_use[active->GetRegister()] = current->GetStart();
518 } else {
519 size_t use = active->FirstRegisterUseAfter(current->GetStart());
520 if (use != kNoLifetime) {
521 next_use[active->GetRegister()] = use;
522 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100523 }
524 }
525
526 // For each inactive interval, find the next use of its register after the
527 // start of current.
528 // Thanks to SSA, this should only be needed for intervals
529 // that are the result of a split.
530 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
531 LiveInterval* inactive = inactive_.Get(i);
532 DCHECK(inactive->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100533 size_t next_intersection = inactive->FirstIntersectionWith(current);
534 if (next_intersection != kNoLifetime) {
535 if (inactive->IsFixed()) {
536 next_use[inactive->GetRegister()] =
537 std::min(next_intersection, next_use[inactive->GetRegister()]);
538 } else {
539 size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
540 if (use != kNoLifetime) {
541 next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
542 }
543 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100544 }
545 }
546
547 // Pick the register that is used the last.
548 int reg = -1;
549 for (size_t i = 0; i < number_of_registers_; ++i) {
550 if (IsBlocked(i)) continue;
551 if (reg == -1 || next_use[i] > next_use[reg]) {
552 reg = i;
553 if (next_use[i] == kMaxLifetimePosition) break;
554 }
555 }
556
557 if (first_register_use >= next_use[reg]) {
558 // If the first use of that instruction is after the last use of the found
559 // register, we split this interval just before its first register use.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100560 AllocateSpillSlotFor(current);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100561 LiveInterval* split = Split(current, first_register_use - 1);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100562 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100563 return false;
564 } else {
565 // Use this register and spill the active and inactives interval that
566 // have that register.
567 current->SetRegister(reg);
568
569 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
570 LiveInterval* active = active_.Get(i);
571 if (active->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100572 DCHECK(!active->IsFixed());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100573 LiveInterval* split = Split(active, current->GetStart());
574 active_.DeleteAt(i);
575 handled_.Add(active);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100576 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100577 break;
578 }
579 }
580
581 for (size_t i = 0; i < inactive_.Size(); ++i) {
582 LiveInterval* inactive = inactive_.Get(i);
583 if (inactive->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100584 size_t next_intersection = inactive->FirstIntersectionWith(current);
585 if (next_intersection != kNoLifetime) {
586 if (inactive->IsFixed()) {
587 LiveInterval* split = Split(current, next_intersection);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100588 AddSorted(unhandled_, split);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100589 } else {
590 LiveInterval* split = Split(inactive, current->GetStart());
591 inactive_.DeleteAt(i);
592 handled_.Add(inactive);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100593 AddSorted(unhandled_, split);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100594 --i;
595 }
596 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100597 }
598 }
599
600 return true;
601 }
602}
603
Nicolas Geoffray39468442014-09-02 15:17:15 +0100604void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100605 size_t insert_at = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100606 for (size_t i = array->Size(); i > 0; --i) {
607 LiveInterval* current = array->Get(i - 1);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100608 if (current->StartsAfter(interval)) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100609 insert_at = i;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100610 break;
611 }
612 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100613 array->InsertAt(insert_at, interval);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100614}
615
616LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
617 DCHECK(position >= interval->GetStart());
618 DCHECK(!interval->IsDeadAt(position));
619 if (position == interval->GetStart()) {
620 // Spill slot will be allocated when handling `interval` again.
621 interval->ClearRegister();
622 return interval;
623 } else {
624 LiveInterval* new_interval = interval->SplitAt(position);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100625 return new_interval;
626 }
627}
628
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100629static bool NeedTwoSpillSlot(Primitive::Type type) {
630 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
631}
632
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100633void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
634 LiveInterval* parent = interval->GetParent();
635
636 // An instruction gets a spill slot for its entire lifetime. If the parent
637 // of this interval already has a spill slot, there is nothing to do.
638 if (parent->HasSpillSlot()) {
639 return;
640 }
641
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100642 HInstruction* defined_by = parent->GetDefinedBy();
643 if (defined_by->IsParameterValue()) {
644 // Parameters have their own stack slot.
645 parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
646 return;
647 }
648
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100649 if (defined_by->IsConstant()) {
650 // Constants don't need a spill slot.
651 return;
652 }
653
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100654 LiveInterval* last_sibling = interval;
655 while (last_sibling->GetNextSibling() != nullptr) {
656 last_sibling = last_sibling->GetNextSibling();
657 }
658 size_t end = last_sibling->GetEnd();
659
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100660 if (NeedTwoSpillSlot(parent->GetType())) {
661 AllocateTwoSpillSlots(parent, end);
662 } else {
663 AllocateOneSpillSlot(parent, end);
664 }
665}
666
667void RegisterAllocator::AllocateTwoSpillSlots(LiveInterval* parent, size_t end) {
668 // Find an available spill slot.
669 size_t slot = 0;
670 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
671 // We check if it is less rather than less or equal because the parallel move
672 // resolver does not work when a single spill slot needs to be exchanged with
673 // a double spill slot. The strict comparison avoids needing to exchange these
674 // locations at the same lifetime position.
675 if (spill_slots_.Get(slot) < parent->GetStart()
676 && (slot == (e - 1) || spill_slots_.Get(slot + 1) < parent->GetStart())) {
677 break;
678 }
679 }
680
681 if (slot == spill_slots_.Size()) {
682 // We need a new spill slot.
683 spill_slots_.Add(end);
684 spill_slots_.Add(end);
685 } else if (slot == spill_slots_.Size() - 1) {
686 spill_slots_.Put(slot, end);
687 spill_slots_.Add(end);
688 } else {
689 spill_slots_.Put(slot, end);
690 spill_slots_.Put(slot + 1, end);
691 }
692
Nicolas Geoffray39468442014-09-02 15:17:15 +0100693 parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100694}
695
696void RegisterAllocator::AllocateOneSpillSlot(LiveInterval* parent, size_t end) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100697 // Find an available spill slot.
698 size_t slot = 0;
699 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
700 if (spill_slots_.Get(slot) <= parent->GetStart()) {
701 break;
702 }
703 }
704
705 if (slot == spill_slots_.Size()) {
706 // We need a new spill slot.
707 spill_slots_.Add(end);
708 } else {
709 spill_slots_.Put(slot, end);
710 }
711
Nicolas Geoffray39468442014-09-02 15:17:15 +0100712 parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100713}
714
715static Location ConvertToLocation(LiveInterval* interval) {
716 if (interval->HasRegister()) {
717 return Location::RegisterLocation(ManagedRegister(interval->GetRegister()));
718 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100719 HInstruction* defined_by = interval->GetParent()->GetDefinedBy();
720 if (defined_by->IsConstant()) {
721 return defined_by->GetLocations()->Out();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100722 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100723 DCHECK(interval->GetParent()->HasSpillSlot());
724 if (NeedTwoSpillSlot(interval->GetType())) {
725 return Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot());
726 } else {
727 return Location::StackSlot(interval->GetParent()->GetSpillSlot());
728 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100729 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100730 }
731}
732
733// We create a special marker for inputs moves to differentiate them from
734// moves created during resolution. They must be different instructions
735// because the input moves work on the assumption that the interval moves
736// have been executed.
737static constexpr size_t kInputMoveLifetimePosition = 0;
738static bool IsInputMove(HInstruction* instruction) {
739 return instruction->GetLifetimePosition() == kInputMoveLifetimePosition;
740}
741
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100742static bool IsValidDestination(Location destination) {
743 return destination.IsRegister() || destination.IsStackSlot() || destination.IsDoubleStackSlot();
744}
745
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100746void RegisterAllocator::AddInputMoveFor(HInstruction* instruction,
747 Location source,
748 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100749 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100750 if (source.Equals(destination)) return;
751
752 DCHECK(instruction->AsPhi() == nullptr);
753
754 HInstruction* previous = instruction->GetPrevious();
755 HParallelMove* move = nullptr;
756 if (previous == nullptr
757 || previous->AsParallelMove() == nullptr
758 || !IsInputMove(previous)) {
759 move = new (allocator_) HParallelMove(allocator_);
760 move->SetLifetimePosition(kInputMoveLifetimePosition);
761 instruction->GetBlock()->InsertInstructionBefore(move, instruction);
762 } else {
763 move = previous->AsParallelMove();
764 }
765 DCHECK(IsInputMove(move));
766 move->AddMove(new (allocator_) MoveOperands(source, destination));
767}
768
769void RegisterAllocator::InsertParallelMoveAt(size_t position,
770 Location source,
771 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100772 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100773 if (source.Equals(destination)) return;
774
775 HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
776 if (at == nullptr) {
777 // Block boundary, don't no anything the connection of split siblings will handle it.
778 return;
779 }
780 HParallelMove* move;
781 if ((position & 1) == 1) {
782 // Move must happen after the instruction.
783 DCHECK(!at->IsControlFlow());
784 move = at->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100785 // This is a parallel move for connecting siblings in a same block. We need to
786 // differentiate it with moves for connecting blocks, and input moves.
787 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100788 move = new (allocator_) HParallelMove(allocator_);
789 move->SetLifetimePosition(position);
790 at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
791 }
792 } else {
793 // Move must happen before the instruction.
794 HInstruction* previous = at->GetPrevious();
795 if (previous != nullptr && previous->AsParallelMove() != nullptr) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100796 // This is a parallel move for connecting siblings in a same block. We need to
797 // differentiate it with moves for connecting blocks, and input moves.
798 if (previous->GetLifetimePosition() != position) {
Nicolas Geoffray145f0ca2014-09-22 11:51:51 +0100799 // If the previous instruction of the previous instruction is not a parallel
800 // move, we have to insert the new parallel move before the input or connecting
801 // block moves.
802 at = previous;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100803 previous = previous->GetPrevious();
804 }
805 }
806 if (previous == nullptr || previous->AsParallelMove() == nullptr) {
807 move = new (allocator_) HParallelMove(allocator_);
808 move->SetLifetimePosition(position);
809 at->GetBlock()->InsertInstructionBefore(move, at);
810 } else {
811 move = previous->AsParallelMove();
812 }
813 }
814 move->AddMove(new (allocator_) MoveOperands(source, destination));
815}
816
817void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
818 Location source,
819 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100820 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100821 if (source.Equals(destination)) return;
822
823 DCHECK_EQ(block->GetSuccessors().Size(), 1u);
824 HInstruction* last = block->GetLastInstruction();
825 HInstruction* previous = last->GetPrevious();
826 HParallelMove* move;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100827 // This is a parallel move for connecting blocks. We need to differentiate
828 // it with moves for connecting siblings in a same block, and output moves.
829 if (previous == nullptr || previous->AsParallelMove() == nullptr
830 || previous->AsParallelMove()->GetLifetimePosition() != block->GetLifetimeEnd()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100831 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100832 move->SetLifetimePosition(block->GetLifetimeEnd());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100833 block->InsertInstructionBefore(move, last);
834 } else {
835 move = previous->AsParallelMove();
836 }
837 move->AddMove(new (allocator_) MoveOperands(source, destination));
838}
839
840void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
841 Location source,
842 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100843 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100844 if (source.Equals(destination)) return;
845
846 HInstruction* first = block->GetFirstInstruction();
847 HParallelMove* move = first->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100848 // This is a parallel move for connecting blocks. We need to differentiate
849 // it with moves for connecting siblings in a same block, and input moves.
850 if (move == nullptr || move->GetLifetimePosition() != block->GetLifetimeStart()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100851 move = new (allocator_) HParallelMove(allocator_);
852 move->SetLifetimePosition(block->GetLifetimeStart());
853 block->InsertInstructionBefore(move, first);
854 }
855 move->AddMove(new (allocator_) MoveOperands(source, destination));
856}
857
858void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
859 Location source,
860 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100861 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100862 if (source.Equals(destination)) return;
863
864 if (instruction->AsPhi() != nullptr) {
865 InsertParallelMoveAtEntryOf(instruction->GetBlock(), source, destination);
866 return;
867 }
868
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100869 size_t position = instruction->GetLifetimePosition() + 1;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100870 HParallelMove* move = instruction->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100871 // This is a parallel move for moving the output of an instruction. We need
872 // to differentiate with input moves, moves for connecting siblings in a
873 // and moves for connecting blocks.
874 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100875 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100876 move->SetLifetimePosition(position);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100877 instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
878 }
879 move->AddMove(new (allocator_) MoveOperands(source, destination));
880}
881
882void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
883 LiveInterval* current = interval;
884 if (current->HasSpillSlot() && current->HasRegister()) {
885 // We spill eagerly, so move must be at definition.
886 InsertMoveAfter(interval->GetDefinedBy(),
887 Location::RegisterLocation(ManagedRegister(interval->GetRegister())),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100888 NeedTwoSpillSlot(interval->GetType())
889 ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
890 : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100891 }
892 UsePosition* use = current->GetFirstUse();
893
894 // Walk over all siblings, updating locations of use positions, and
895 // connecting them when they are adjacent.
896 do {
897 Location source = ConvertToLocation(current);
898
899 // Walk over all uses covered by this interval, and update the location
900 // information.
901 while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100902 LocationSummary* locations = use->GetUser()->GetLocations();
903 if (use->GetIsEnvironment()) {
904 locations->SetEnvironmentAt(use->GetInputIndex(), source);
905 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100906 Location expected_location = locations->InAt(use->GetInputIndex());
907 if (expected_location.IsUnallocated()) {
908 locations->SetInAt(use->GetInputIndex(), source);
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100909 } else if (!expected_location.IsConstant()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100910 AddInputMoveFor(use->GetUser(), source, expected_location);
911 }
912 }
913 use = use->GetNext();
914 }
915
916 // If the next interval starts just after this one, and has a register,
917 // insert a move.
918 LiveInterval* next_sibling = current->GetNextSibling();
919 if (next_sibling != nullptr
920 && next_sibling->HasRegister()
921 && current->GetEnd() == next_sibling->GetStart()) {
922 Location destination = ConvertToLocation(next_sibling);
923 InsertParallelMoveAt(current->GetEnd(), source, destination);
924 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100925
926 // At each safepoint, we record stack and register information.
927 for (size_t i = 0, e = safepoints_.Size(); i < e; ++i) {
928 HInstruction* safepoint = safepoints_.Get(i);
929 size_t position = safepoint->GetLifetimePosition();
930 LocationSummary* locations = safepoint->GetLocations();
931 if (!current->Covers(position)) continue;
932
933 if (current->GetType() == Primitive::kPrimNot) {
934 DCHECK(current->GetParent()->HasSpillSlot());
935 locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
936 }
937
938 switch (source.GetKind()) {
939 case Location::kRegister: {
940 locations->SetLiveRegister(source.reg().RegId());
941 if (current->GetType() == Primitive::kPrimNot) {
942 locations->SetRegisterBit(source.reg().RegId());
943 }
944 break;
945 }
946 case Location::kStackSlot: // Fall-through
947 case Location::kDoubleStackSlot: // Fall-through
948 case Location::kConstant: {
949 // Nothing to do.
950 break;
951 }
952 default: {
953 LOG(FATAL) << "Unexpected location for object";
954 }
955 }
956 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100957 current = next_sibling;
958 } while (current != nullptr);
959 DCHECK(use == nullptr);
960}
961
962void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
963 HBasicBlock* from,
964 HBasicBlock* to) const {
965 if (interval->GetNextSibling() == nullptr) {
966 // Nothing to connect. The whole range was allocated to the same location.
967 return;
968 }
969
970 size_t from_position = from->GetLifetimeEnd() - 1;
971 size_t to_position = to->GetLifetimeStart();
972
973 LiveInterval* destination = nullptr;
974 LiveInterval* source = nullptr;
975
976 LiveInterval* current = interval;
977
978 // Check the intervals that cover `from` and `to`.
979 while ((current != nullptr) && (source == nullptr || destination == nullptr)) {
980 if (current->Covers(from_position)) {
981 DCHECK(source == nullptr);
982 source = current;
983 }
984 if (current->Covers(to_position)) {
985 DCHECK(destination == nullptr);
986 destination = current;
987 }
988
989 current = current->GetNextSibling();
990 }
991
992 if (destination == source) {
993 // Interval was not split.
994 return;
995 }
996
997 if (!destination->HasRegister()) {
998 // Values are eagerly spilled. Spill slot already contains appropriate value.
999 return;
1000 }
1001
1002 // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
1003 // we need to put the moves at the entry of `to`.
1004 if (from->GetSuccessors().Size() == 1) {
1005 InsertParallelMoveAtExitOf(from, ConvertToLocation(source), ConvertToLocation(destination));
1006 } else {
1007 DCHECK_EQ(to->GetPredecessors().Size(), 1u);
1008 InsertParallelMoveAtEntryOf(to, ConvertToLocation(source), ConvertToLocation(destination));
1009 }
1010}
1011
1012// Returns the location of `interval`, or siblings of `interval`, at `position`.
1013static Location FindLocationAt(LiveInterval* interval, size_t position) {
1014 LiveInterval* current = interval;
1015 while (!current->Covers(position)) {
1016 current = current->GetNextSibling();
1017 DCHECK(current != nullptr);
1018 }
1019 return ConvertToLocation(current);
1020}
1021
1022void RegisterAllocator::Resolve() {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001023 codegen_->ComputeFrameSize(spill_slots_.Size(), reserved_out_slots_);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001024
1025 // Adjust the Out Location of instructions.
1026 // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
1027 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1028 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1029 LiveInterval* current = instruction->GetLiveInterval();
1030 LocationSummary* locations = instruction->GetLocations();
1031 Location location = locations->Out();
1032 if (instruction->AsParameterValue() != nullptr) {
1033 // Now that we know the frame size, adjust the parameter's location.
1034 if (location.IsStackSlot()) {
1035 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1036 current->SetSpillSlot(location.GetStackIndex());
1037 locations->SetOut(location);
1038 } else if (location.IsDoubleStackSlot()) {
1039 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1040 current->SetSpillSlot(location.GetStackIndex());
1041 locations->SetOut(location);
1042 } else if (current->HasSpillSlot()) {
1043 current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
1044 }
1045 }
1046
1047 Location source = ConvertToLocation(current);
1048
1049 if (location.IsUnallocated()) {
1050 if (location.GetPolicy() == Location::kSameAsFirstInput) {
1051 locations->SetInAt(0, source);
1052 }
1053 locations->SetOut(source);
1054 } else {
1055 DCHECK(source.Equals(location));
1056 }
1057 }
1058
1059 // Connect siblings.
1060 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1061 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1062 ConnectSiblings(instruction->GetLiveInterval());
1063 }
1064
1065 // Resolve non-linear control flow across branches. Order does not matter.
1066 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
1067 HBasicBlock* block = it.Current();
1068 BitVector* live = liveness_.GetLiveInSet(*block);
1069 for (uint32_t idx : live->Indexes()) {
1070 HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
1071 LiveInterval* interval = current->GetLiveInterval();
1072 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
1073 ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
1074 }
1075 }
1076 }
1077
1078 // Resolve phi inputs. Order does not matter.
1079 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
1080 HBasicBlock* current = it.Current();
1081 for (HInstructionIterator it(current->GetPhis()); !it.Done(); it.Advance()) {
1082 HInstruction* phi = it.Current();
1083 for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
1084 HBasicBlock* predecessor = current->GetPredecessors().Get(i);
1085 DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
1086 HInstruction* input = phi->InputAt(i);
1087 Location source = FindLocationAt(input->GetLiveInterval(),
1088 predecessor->GetLastInstruction()->GetLifetimePosition());
1089 Location destination = ConvertToLocation(phi->GetLiveInterval());
1090 InsertParallelMoveAtExitOf(predecessor, source, destination);
1091 }
1092 }
1093 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001094
1095 // Assign temp locations.
1096 HInstruction* current = nullptr;
1097 size_t temp_index = 0;
1098 for (size_t i = 0; i < temp_intervals_.Size(); ++i) {
1099 LiveInterval* temp = temp_intervals_.Get(i);
1100 if (temp->GetDefinedBy() != current) {
1101 temp_index = 0;
1102 current = temp->GetDefinedBy();
1103 }
1104 LocationSummary* locations = current->GetLocations();
1105 locations->SetTempAt(
1106 temp_index++, Location::RegisterLocation(ManagedRegister(temp->GetRegister())));
1107 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001108}
1109
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001110} // namespace art