blob: 348e9d4921a54d270b490d7d94a2d7b2fcbcdc02 [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
19#include "code_generator.h"
20#include "ssa_liveness_analysis.h"
21
22namespace art {
23
24static constexpr size_t kMaxLifetimePosition = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010025static constexpr size_t kDefaultNumberOfSpillSlots = 4;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010026
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010027RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
28 CodeGenerator* codegen,
29 const SsaLivenessAnalysis& liveness)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010030 : allocator_(allocator),
31 codegen_(codegen),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010032 liveness_(liveness),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010033 unhandled_(allocator, 0),
34 handled_(allocator, 0),
35 active_(allocator, 0),
36 inactive_(allocator, 0),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010037 physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010038 spill_slots_(allocator, kDefaultNumberOfSpillSlots),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010039 processing_core_registers_(false),
40 number_of_registers_(-1),
41 registers_array_(nullptr),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010042 blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())) {
43 codegen->SetupBlockedRegisters(blocked_registers_);
44 physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010045}
46
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010047bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
48 InstructionSet instruction_set) {
49 if (!Supports(instruction_set)) {
50 return false;
51 }
52 for (size_t i = 0, e = graph.GetBlocks().Size(); i < e; ++i) {
53 for (HInstructionIterator it(graph.GetBlocks().Get(i)->GetInstructions());
54 !it.Done();
55 it.Advance()) {
56 HInstruction* current = it.Current();
57 if (current->NeedsEnvironment()) return false;
58 if (current->GetType() == Primitive::kPrimLong) return false;
59 if (current->GetType() == Primitive::kPrimFloat) return false;
60 if (current->GetType() == Primitive::kPrimDouble) return false;
61 }
62 }
63 return true;
64}
65
66static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
67 bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
68 && (interval->GetType() != Primitive::kPrimFloat);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010069 return processing_core_registers == is_core_register;
70}
71
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010072void RegisterAllocator::AllocateRegisters() {
73 processing_core_registers_ = true;
74 AllocateRegistersInternal();
75 processing_core_registers_ = false;
76 AllocateRegistersInternal();
77
78 Resolve();
79
80 if (kIsDebugBuild) {
81 processing_core_registers_ = true;
82 ValidateInternal(true);
83 processing_core_registers_ = false;
84 ValidateInternal(true);
85 }
86}
87
88void RegisterAllocator::BlockRegister(Location location,
89 size_t start,
90 size_t end,
91 Primitive::Type type) {
92 int reg = location.reg().RegId();
93 LiveInterval* interval = physical_register_intervals_.Get(reg);
94 if (interval == nullptr) {
95 interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
96 physical_register_intervals_.Put(reg, interval);
97 inactive_.Add(interval);
98 }
99 DCHECK(interval->GetRegister() == reg);
100 interval->AddRange(start, end);
101}
102
103void RegisterAllocator::AllocateRegistersInternal() {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100104 number_of_registers_ = processing_core_registers_
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100105 ? codegen_->GetNumberOfCoreRegisters()
106 : codegen_->GetNumberOfFloatingPointRegisters();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100107
108 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
109
110 // Iterate post-order, to ensure the list is sorted, and the last added interval
111 // is the one with the lowest start position.
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100112 for (size_t i = liveness_.GetNumberOfSsaValues(); i > 0; --i) {
113 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i - 1);
114 LiveInterval* current = instruction->GetLiveInterval();
115 if (ShouldProcess(processing_core_registers_, current)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100116 DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100117
118 LocationSummary* locations = instruction->GetLocations();
119 if (locations->GetTempCount() != 0) {
120 // Note that we already filtered out instructions requiring temporaries in
121 // RegisterAllocator::CanAllocateRegistersFor.
122 LOG(FATAL) << "Unimplemented";
123 }
124
125 // Some instructions define their output in fixed register/stack slot. We need
126 // to ensure we know these locations before doing register allocation. For a
127 // given register, we create an interval that covers these locations. The register
128 // will be unavailable at these locations when trying to allocate one for an
129 // interval.
130 //
131 // The backwards walking ensures the ranges are ordered on increasing start positions.
132 Location output = locations->Out();
133 size_t position = instruction->GetLifetimePosition();
134 if (output.IsRegister()) {
135 // Shift the interval's start by one to account for the blocked register.
136 current->SetFrom(position + 1);
137 current->SetRegister(output.reg().RegId());
138 BlockRegister(output, position, position + 1, instruction->GetType());
139 } else if (output.IsStackSlot()) {
140 current->SetSpillSlot(output.GetStackIndex());
141 }
142 for (size_t i = 0; i < instruction->InputCount(); ++i) {
143 Location input = locations->InAt(i);
144 if (input.IsRegister()) {
145 BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
146 }
147 }
148
149 // Add the interval to the correct list.
150 if (current->HasRegister()) {
151 DCHECK(instruction->IsParameterValue());
152 inactive_.Add(current);
153 } else if (current->HasSpillSlot()) {
154 DCHECK(instruction->IsParameterValue());
155 // Split before first register use.
156 size_t first_register_use = current->FirstRegisterUse();
157 if (first_register_use != kNoLifetime) {
158 LiveInterval* split = Split(current, first_register_use - 1);
159 // The new interval may start at a late
160 AddToUnhandled(split);
161 } else {
162 // Nothing to do, we won't allocate a register for this value.
163 }
164 } else {
165 DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
166 unhandled_.Add(current);
167 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100168 }
169 }
170
171 LinearScan();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100172}
173
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100174class AllRangesIterator : public ValueObject {
175 public:
176 explicit AllRangesIterator(LiveInterval* interval)
177 : current_interval_(interval),
178 current_range_(interval->GetFirstRange()) {}
179
180 bool Done() const { return current_interval_ == nullptr; }
181 LiveRange* CurrentRange() const { return current_range_; }
182 LiveInterval* CurrentInterval() const { return current_interval_; }
183
184 void Advance() {
185 current_range_ = current_range_->GetNext();
186 if (current_range_ == nullptr) {
187 current_interval_ = current_interval_->GetNextSibling();
188 if (current_interval_ != nullptr) {
189 current_range_ = current_interval_->GetFirstRange();
190 }
191 }
192 }
193
194 private:
195 LiveInterval* current_interval_;
196 LiveRange* current_range_;
197
198 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
199};
200
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100201bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
202 // To simplify unit testing, we eagerly create the array of intervals, and
203 // call the helper method.
204 GrowableArray<LiveInterval*> intervals(allocator_, 0);
205 for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
206 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
207 if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
208 intervals.Add(instruction->GetLiveInterval());
209 }
210 }
211
212 for (size_t i = 0, e = physical_register_intervals_.Size(); i < e; ++i) {
213 LiveInterval* fixed = physical_register_intervals_.Get(i);
214 if (fixed != nullptr && ShouldProcess(processing_core_registers_, fixed)) {
215 intervals.Add(fixed);
216 }
217 }
218
219 return ValidateIntervals(intervals, spill_slots_.Size(), *codegen_, allocator_,
220 processing_core_registers_, log_fatal_on_failure);
221}
222
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100223bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
224 size_t number_of_spill_slots,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100225 const CodeGenerator& codegen,
226 ArenaAllocator* allocator,
227 bool processing_core_registers,
228 bool log_fatal_on_failure) {
229 size_t number_of_registers = processing_core_registers
230 ? codegen.GetNumberOfCoreRegisters()
231 : codegen.GetNumberOfFloatingPointRegisters();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100232 GrowableArray<ArenaBitVector*> liveness_of_values(
233 allocator, number_of_registers + number_of_spill_slots);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100234
235 // Allocate a bit vector per register. A live interval that has a register
236 // allocated will populate the associated bit vector based on its live ranges.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100237 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
238 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100239 }
240
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100241 for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
242 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
243 LiveInterval* current = it.CurrentInterval();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100244 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
245 if (current->GetParent()->HasSpillSlot()
246 // Parameters have their own stack slot.
247 && !(defined_by != nullptr && defined_by->IsParameterValue())) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100248 BitVector* liveness_of_spill_slot = liveness_of_values.Get(
249 number_of_registers + current->GetParent()->GetSpillSlot() / kVRegSize);
250 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
251 if (liveness_of_spill_slot->IsBitSet(j)) {
252 if (log_fatal_on_failure) {
253 std::ostringstream message;
254 message << "Spill slot conflict at " << j;
255 LOG(FATAL) << message.str();
256 } else {
257 return false;
258 }
259 } else {
260 liveness_of_spill_slot->SetBit(j);
261 }
262 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100263 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100264
265 if (current->HasRegister()) {
266 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
267 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
268 if (liveness_of_register->IsBitSet(j)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100269 if (log_fatal_on_failure) {
270 std::ostringstream message;
271 message << "Register conflict at " << j << " for ";
272 if (processing_core_registers) {
273 codegen.DumpCoreRegister(message, current->GetRegister());
274 } else {
275 codegen.DumpFloatingPointRegister(message, current->GetRegister());
276 }
277 LOG(FATAL) << message.str();
278 } else {
279 return false;
280 }
281 } else {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100282 liveness_of_register->SetBit(j);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100283 }
284 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100285 }
286 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100287 }
288 return true;
289}
290
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100291void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100292 interval->Dump(stream);
293 stream << ": ";
294 if (interval->HasRegister()) {
295 if (processing_core_registers_) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100296 codegen_->DumpCoreRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100297 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100298 codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100299 }
300 } else {
301 stream << "spilled";
302 }
303 stream << std::endl;
304}
305
306// By the book implementation of a linear scan register allocator.
307void RegisterAllocator::LinearScan() {
308 while (!unhandled_.IsEmpty()) {
309 // (1) Remove interval with the lowest start position from unhandled.
310 LiveInterval* current = unhandled_.Pop();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100311 DCHECK(!current->IsFixed() && !current->HasRegister() && !current->HasSpillSlot());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100312 size_t position = current->GetStart();
313
314 // (2) Remove currently active intervals that are dead at this position.
315 // Move active intervals that have a lifetime hole at this position
316 // to inactive.
317 for (size_t i = 0; i < active_.Size(); ++i) {
318 LiveInterval* interval = active_.Get(i);
319 if (interval->IsDeadAt(position)) {
320 active_.Delete(interval);
321 --i;
322 handled_.Add(interval);
323 } else if (!interval->Covers(position)) {
324 active_.Delete(interval);
325 --i;
326 inactive_.Add(interval);
327 }
328 }
329
330 // (3) Remove currently inactive intervals that are dead at this position.
331 // Move inactive intervals that cover this position to active.
332 for (size_t i = 0; i < inactive_.Size(); ++i) {
333 LiveInterval* interval = inactive_.Get(i);
334 if (interval->IsDeadAt(position)) {
335 inactive_.Delete(interval);
336 --i;
337 handled_.Add(interval);
338 } else if (interval->Covers(position)) {
339 inactive_.Delete(interval);
340 --i;
341 active_.Add(interval);
342 }
343 }
344
345 // (4) Try to find an available register.
346 bool success = TryAllocateFreeReg(current);
347
348 // (5) If no register could be found, we need to spill.
349 if (!success) {
350 success = AllocateBlockedReg(current);
351 }
352
353 // (6) If the interval had a register allocated, add it to the list of active
354 // intervals.
355 if (success) {
356 active_.Add(current);
357 }
358 }
359}
360
361// Find a free register. If multiple are found, pick the register that
362// is free the longest.
363bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
364 size_t* free_until = registers_array_;
365
366 // First set all registers to be free.
367 for (size_t i = 0; i < number_of_registers_; ++i) {
368 free_until[i] = kMaxLifetimePosition;
369 }
370
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100371 // For each inactive interval, set its register to be free until
372 // the next intersection with `current`.
373 // Thanks to SSA, this should only be needed for intervals
374 // that are the result of a split.
375 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
376 LiveInterval* inactive = inactive_.Get(i);
377 DCHECK(inactive->HasRegister());
378 size_t next_intersection = inactive->FirstIntersectionWith(current);
379 if (next_intersection != kNoLifetime) {
380 free_until[inactive->GetRegister()] = next_intersection;
381 }
382 }
383
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100384 // For each active interval, set its register to not free.
385 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
386 LiveInterval* interval = active_.Get(i);
387 DCHECK(interval->HasRegister());
388 free_until[interval->GetRegister()] = 0;
389 }
390
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100391 // Pick the register that is free the longest.
392 int reg = -1;
393 for (size_t i = 0; i < number_of_registers_; ++i) {
394 if (IsBlocked(i)) continue;
395 if (reg == -1 || free_until[i] > free_until[reg]) {
396 reg = i;
397 if (free_until[i] == kMaxLifetimePosition) break;
398 }
399 }
400
401 // If we could not find a register, we need to spill.
402 if (reg == -1 || free_until[reg] == 0) {
403 return false;
404 }
405
406 current->SetRegister(reg);
407 if (!current->IsDeadAt(free_until[reg])) {
408 // If the register is only available for a subset of live ranges
409 // covered by `current`, split `current` at the position where
410 // the register is not available anymore.
411 LiveInterval* split = Split(current, free_until[reg]);
412 DCHECK(split != nullptr);
413 AddToUnhandled(split);
414 }
415 return true;
416}
417
418bool RegisterAllocator::IsBlocked(int reg) const {
419 // TODO: This only works for core registers and needs to be adjusted for
420 // floating point registers.
421 DCHECK(processing_core_registers_);
422 return blocked_registers_[reg];
423}
424
425// Find the register that is used the last, and spill the interval
426// that holds it. If the first use of `current` is after that register
427// we spill `current` instead.
428bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
429 size_t first_register_use = current->FirstRegisterUse();
430 if (current->FirstRegisterUse() == kNoLifetime) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100431 AllocateSpillSlotFor(current);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100432 return false;
433 }
434
435 // First set all registers as not being used.
436 size_t* next_use = registers_array_;
437 for (size_t i = 0; i < number_of_registers_; ++i) {
438 next_use[i] = kMaxLifetimePosition;
439 }
440
441 // For each active interval, find the next use of its register after the
442 // start of current.
443 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
444 LiveInterval* active = active_.Get(i);
445 DCHECK(active->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100446 if (active->IsFixed()) {
447 next_use[active->GetRegister()] = current->GetStart();
448 } else {
449 size_t use = active->FirstRegisterUseAfter(current->GetStart());
450 if (use != kNoLifetime) {
451 next_use[active->GetRegister()] = use;
452 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100453 }
454 }
455
456 // For each inactive interval, find the next use of its register after the
457 // start of current.
458 // Thanks to SSA, this should only be needed for intervals
459 // that are the result of a split.
460 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
461 LiveInterval* inactive = inactive_.Get(i);
462 DCHECK(inactive->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100463 size_t next_intersection = inactive->FirstIntersectionWith(current);
464 if (next_intersection != kNoLifetime) {
465 if (inactive->IsFixed()) {
466 next_use[inactive->GetRegister()] =
467 std::min(next_intersection, next_use[inactive->GetRegister()]);
468 } else {
469 size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
470 if (use != kNoLifetime) {
471 next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
472 }
473 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100474 }
475 }
476
477 // Pick the register that is used the last.
478 int reg = -1;
479 for (size_t i = 0; i < number_of_registers_; ++i) {
480 if (IsBlocked(i)) continue;
481 if (reg == -1 || next_use[i] > next_use[reg]) {
482 reg = i;
483 if (next_use[i] == kMaxLifetimePosition) break;
484 }
485 }
486
487 if (first_register_use >= next_use[reg]) {
488 // If the first use of that instruction is after the last use of the found
489 // register, we split this interval just before its first register use.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100490 AllocateSpillSlotFor(current);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100491 LiveInterval* split = Split(current, first_register_use - 1);
492 AddToUnhandled(split);
493 return false;
494 } else {
495 // Use this register and spill the active and inactives interval that
496 // have that register.
497 current->SetRegister(reg);
498
499 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
500 LiveInterval* active = active_.Get(i);
501 if (active->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100502 DCHECK(!active->IsFixed());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100503 LiveInterval* split = Split(active, current->GetStart());
504 active_.DeleteAt(i);
505 handled_.Add(active);
506 AddToUnhandled(split);
507 break;
508 }
509 }
510
511 for (size_t i = 0; i < inactive_.Size(); ++i) {
512 LiveInterval* inactive = inactive_.Get(i);
513 if (inactive->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100514 size_t next_intersection = inactive->FirstIntersectionWith(current);
515 if (next_intersection != kNoLifetime) {
516 if (inactive->IsFixed()) {
517 LiveInterval* split = Split(current, next_intersection);
518 AddToUnhandled(split);
519 } else {
520 LiveInterval* split = Split(inactive, current->GetStart());
521 inactive_.DeleteAt(i);
522 handled_.Add(inactive);
523 AddToUnhandled(split);
524 --i;
525 }
526 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100527 }
528 }
529
530 return true;
531 }
532}
533
534void RegisterAllocator::AddToUnhandled(LiveInterval* interval) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100535 size_t insert_at = 0;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100536 for (size_t i = unhandled_.Size(); i > 0; --i) {
537 LiveInterval* current = unhandled_.Get(i - 1);
538 if (current->StartsAfter(interval)) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100539 insert_at = i;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100540 break;
541 }
542 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100543 unhandled_.InsertAt(insert_at, interval);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100544}
545
546LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
547 DCHECK(position >= interval->GetStart());
548 DCHECK(!interval->IsDeadAt(position));
549 if (position == interval->GetStart()) {
550 // Spill slot will be allocated when handling `interval` again.
551 interval->ClearRegister();
552 return interval;
553 } else {
554 LiveInterval* new_interval = interval->SplitAt(position);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100555 return new_interval;
556 }
557}
558
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100559void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
560 LiveInterval* parent = interval->GetParent();
561
562 // An instruction gets a spill slot for its entire lifetime. If the parent
563 // of this interval already has a spill slot, there is nothing to do.
564 if (parent->HasSpillSlot()) {
565 return;
566 }
567
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100568 HInstruction* defined_by = parent->GetDefinedBy();
569 if (defined_by->IsParameterValue()) {
570 // Parameters have their own stack slot.
571 parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
572 return;
573 }
574
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100575 LiveInterval* last_sibling = interval;
576 while (last_sibling->GetNextSibling() != nullptr) {
577 last_sibling = last_sibling->GetNextSibling();
578 }
579 size_t end = last_sibling->GetEnd();
580
581 // Find an available spill slot.
582 size_t slot = 0;
583 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
584 if (spill_slots_.Get(slot) <= parent->GetStart()) {
585 break;
586 }
587 }
588
589 if (slot == spill_slots_.Size()) {
590 // We need a new spill slot.
591 spill_slots_.Add(end);
592 } else {
593 spill_slots_.Put(slot, end);
594 }
595
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100596 parent->SetSpillSlot(slot * kVRegSize);
597}
598
599static Location ConvertToLocation(LiveInterval* interval) {
600 if (interval->HasRegister()) {
601 return Location::RegisterLocation(ManagedRegister(interval->GetRegister()));
602 } else {
603 DCHECK(interval->GetParent()->HasSpillSlot());
604 return Location::StackSlot(interval->GetParent()->GetSpillSlot());
605 }
606}
607
608// We create a special marker for inputs moves to differentiate them from
609// moves created during resolution. They must be different instructions
610// because the input moves work on the assumption that the interval moves
611// have been executed.
612static constexpr size_t kInputMoveLifetimePosition = 0;
613static bool IsInputMove(HInstruction* instruction) {
614 return instruction->GetLifetimePosition() == kInputMoveLifetimePosition;
615}
616
617void RegisterAllocator::AddInputMoveFor(HInstruction* instruction,
618 Location source,
619 Location destination) const {
620 if (source.Equals(destination)) return;
621
622 DCHECK(instruction->AsPhi() == nullptr);
623
624 HInstruction* previous = instruction->GetPrevious();
625 HParallelMove* move = nullptr;
626 if (previous == nullptr
627 || previous->AsParallelMove() == nullptr
628 || !IsInputMove(previous)) {
629 move = new (allocator_) HParallelMove(allocator_);
630 move->SetLifetimePosition(kInputMoveLifetimePosition);
631 instruction->GetBlock()->InsertInstructionBefore(move, instruction);
632 } else {
633 move = previous->AsParallelMove();
634 }
635 DCHECK(IsInputMove(move));
636 move->AddMove(new (allocator_) MoveOperands(source, destination));
637}
638
639void RegisterAllocator::InsertParallelMoveAt(size_t position,
640 Location source,
641 Location destination) const {
642 if (source.Equals(destination)) return;
643
644 HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
645 if (at == nullptr) {
646 // Block boundary, don't no anything the connection of split siblings will handle it.
647 return;
648 }
649 HParallelMove* move;
650 if ((position & 1) == 1) {
651 // Move must happen after the instruction.
652 DCHECK(!at->IsControlFlow());
653 move = at->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100654 // This is a parallel move for connecting siblings in a same block. We need to
655 // differentiate it with moves for connecting blocks, and input moves.
656 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100657 move = new (allocator_) HParallelMove(allocator_);
658 move->SetLifetimePosition(position);
659 at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
660 }
661 } else {
662 // Move must happen before the instruction.
663 HInstruction* previous = at->GetPrevious();
664 if (previous != nullptr && previous->AsParallelMove() != nullptr) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100665 // This is a parallel move for connecting siblings in a same block. We need to
666 // differentiate it with moves for connecting blocks, and input moves.
667 if (previous->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100668 previous = previous->GetPrevious();
669 }
670 }
671 if (previous == nullptr || previous->AsParallelMove() == nullptr) {
672 move = new (allocator_) HParallelMove(allocator_);
673 move->SetLifetimePosition(position);
674 at->GetBlock()->InsertInstructionBefore(move, at);
675 } else {
676 move = previous->AsParallelMove();
677 }
678 }
679 move->AddMove(new (allocator_) MoveOperands(source, destination));
680}
681
682void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
683 Location source,
684 Location destination) const {
685 if (source.Equals(destination)) return;
686
687 DCHECK_EQ(block->GetSuccessors().Size(), 1u);
688 HInstruction* last = block->GetLastInstruction();
689 HInstruction* previous = last->GetPrevious();
690 HParallelMove* move;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100691 // This is a parallel move for connecting blocks. We need to differentiate
692 // it with moves for connecting siblings in a same block, and output moves.
693 if (previous == nullptr || previous->AsParallelMove() == nullptr
694 || previous->AsParallelMove()->GetLifetimePosition() != block->GetLifetimeEnd()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100695 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100696 move->SetLifetimePosition(block->GetLifetimeEnd());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100697 block->InsertInstructionBefore(move, last);
698 } else {
699 move = previous->AsParallelMove();
700 }
701 move->AddMove(new (allocator_) MoveOperands(source, destination));
702}
703
704void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
705 Location source,
706 Location destination) const {
707 if (source.Equals(destination)) return;
708
709 HInstruction* first = block->GetFirstInstruction();
710 HParallelMove* move = first->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100711 // This is a parallel move for connecting blocks. We need to differentiate
712 // it with moves for connecting siblings in a same block, and input moves.
713 if (move == nullptr || move->GetLifetimePosition() != block->GetLifetimeStart()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100714 move = new (allocator_) HParallelMove(allocator_);
715 move->SetLifetimePosition(block->GetLifetimeStart());
716 block->InsertInstructionBefore(move, first);
717 }
718 move->AddMove(new (allocator_) MoveOperands(source, destination));
719}
720
721void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
722 Location source,
723 Location destination) const {
724 if (source.Equals(destination)) return;
725
726 if (instruction->AsPhi() != nullptr) {
727 InsertParallelMoveAtEntryOf(instruction->GetBlock(), source, destination);
728 return;
729 }
730
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100731 size_t position = instruction->GetLifetimePosition() + 1;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100732 HParallelMove* move = instruction->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100733 // This is a parallel move for moving the output of an instruction. We need
734 // to differentiate with input moves, moves for connecting siblings in a
735 // and moves for connecting blocks.
736 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100737 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100738 move->SetLifetimePosition(position);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100739 instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
740 }
741 move->AddMove(new (allocator_) MoveOperands(source, destination));
742}
743
744void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
745 LiveInterval* current = interval;
746 if (current->HasSpillSlot() && current->HasRegister()) {
747 // We spill eagerly, so move must be at definition.
748 InsertMoveAfter(interval->GetDefinedBy(),
749 Location::RegisterLocation(ManagedRegister(interval->GetRegister())),
750 Location::StackSlot(interval->GetParent()->GetSpillSlot()));
751 }
752 UsePosition* use = current->GetFirstUse();
753
754 // Walk over all siblings, updating locations of use positions, and
755 // connecting them when they are adjacent.
756 do {
757 Location source = ConvertToLocation(current);
758
759 // Walk over all uses covered by this interval, and update the location
760 // information.
761 while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
762 if (!use->GetIsEnvironment()) {
763 LocationSummary* locations = use->GetUser()->GetLocations();
764 Location expected_location = locations->InAt(use->GetInputIndex());
765 if (expected_location.IsUnallocated()) {
766 locations->SetInAt(use->GetInputIndex(), source);
767 } else {
768 AddInputMoveFor(use->GetUser(), source, expected_location);
769 }
770 }
771 use = use->GetNext();
772 }
773
774 // If the next interval starts just after this one, and has a register,
775 // insert a move.
776 LiveInterval* next_sibling = current->GetNextSibling();
777 if (next_sibling != nullptr
778 && next_sibling->HasRegister()
779 && current->GetEnd() == next_sibling->GetStart()) {
780 Location destination = ConvertToLocation(next_sibling);
781 InsertParallelMoveAt(current->GetEnd(), source, destination);
782 }
783 current = next_sibling;
784 } while (current != nullptr);
785 DCHECK(use == nullptr);
786}
787
788void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
789 HBasicBlock* from,
790 HBasicBlock* to) const {
791 if (interval->GetNextSibling() == nullptr) {
792 // Nothing to connect. The whole range was allocated to the same location.
793 return;
794 }
795
796 size_t from_position = from->GetLifetimeEnd() - 1;
797 size_t to_position = to->GetLifetimeStart();
798
799 LiveInterval* destination = nullptr;
800 LiveInterval* source = nullptr;
801
802 LiveInterval* current = interval;
803
804 // Check the intervals that cover `from` and `to`.
805 while ((current != nullptr) && (source == nullptr || destination == nullptr)) {
806 if (current->Covers(from_position)) {
807 DCHECK(source == nullptr);
808 source = current;
809 }
810 if (current->Covers(to_position)) {
811 DCHECK(destination == nullptr);
812 destination = current;
813 }
814
815 current = current->GetNextSibling();
816 }
817
818 if (destination == source) {
819 // Interval was not split.
820 return;
821 }
822
823 if (!destination->HasRegister()) {
824 // Values are eagerly spilled. Spill slot already contains appropriate value.
825 return;
826 }
827
828 // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
829 // we need to put the moves at the entry of `to`.
830 if (from->GetSuccessors().Size() == 1) {
831 InsertParallelMoveAtExitOf(from, ConvertToLocation(source), ConvertToLocation(destination));
832 } else {
833 DCHECK_EQ(to->GetPredecessors().Size(), 1u);
834 InsertParallelMoveAtEntryOf(to, ConvertToLocation(source), ConvertToLocation(destination));
835 }
836}
837
838// Returns the location of `interval`, or siblings of `interval`, at `position`.
839static Location FindLocationAt(LiveInterval* interval, size_t position) {
840 LiveInterval* current = interval;
841 while (!current->Covers(position)) {
842 current = current->GetNextSibling();
843 DCHECK(current != nullptr);
844 }
845 return ConvertToLocation(current);
846}
847
848void RegisterAllocator::Resolve() {
849 codegen_->ComputeFrameSize(spill_slots_.Size());
850
851 // Adjust the Out Location of instructions.
852 // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
853 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
854 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
855 LiveInterval* current = instruction->GetLiveInterval();
856 LocationSummary* locations = instruction->GetLocations();
857 Location location = locations->Out();
858 if (instruction->AsParameterValue() != nullptr) {
859 // Now that we know the frame size, adjust the parameter's location.
860 if (location.IsStackSlot()) {
861 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
862 current->SetSpillSlot(location.GetStackIndex());
863 locations->SetOut(location);
864 } else if (location.IsDoubleStackSlot()) {
865 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
866 current->SetSpillSlot(location.GetStackIndex());
867 locations->SetOut(location);
868 } else if (current->HasSpillSlot()) {
869 current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
870 }
871 }
872
873 Location source = ConvertToLocation(current);
874
875 if (location.IsUnallocated()) {
876 if (location.GetPolicy() == Location::kSameAsFirstInput) {
877 locations->SetInAt(0, source);
878 }
879 locations->SetOut(source);
880 } else {
881 DCHECK(source.Equals(location));
882 }
883 }
884
885 // Connect siblings.
886 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
887 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
888 ConnectSiblings(instruction->GetLiveInterval());
889 }
890
891 // Resolve non-linear control flow across branches. Order does not matter.
892 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
893 HBasicBlock* block = it.Current();
894 BitVector* live = liveness_.GetLiveInSet(*block);
895 for (uint32_t idx : live->Indexes()) {
896 HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
897 LiveInterval* interval = current->GetLiveInterval();
898 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
899 ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
900 }
901 }
902 }
903
904 // Resolve phi inputs. Order does not matter.
905 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
906 HBasicBlock* current = it.Current();
907 for (HInstructionIterator it(current->GetPhis()); !it.Done(); it.Advance()) {
908 HInstruction* phi = it.Current();
909 for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
910 HBasicBlock* predecessor = current->GetPredecessors().Get(i);
911 DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
912 HInstruction* input = phi->InputAt(i);
913 Location source = FindLocationAt(input->GetLiveInterval(),
914 predecessor->GetLastInstruction()->GetLifetimePosition());
915 Location destination = ConvertToLocation(phi->GetLiveInterval());
916 InsertParallelMoveAtExitOf(predecessor, source, destination);
917 }
918 }
919 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100920}
921
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100922} // namespace art