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 "register_allocator.h"
18
19 #include "code_generator.h"
20 #include "ssa_liveness_analysis.h"
21
22 namespace art {
23
24 static constexpr size_t kMaxLifetimePosition = -1;
25 static constexpr size_t kDefaultNumberOfSpillSlots = 4;
26
RegisterAllocator(ArenaAllocator * allocator,CodeGenerator * codegen,const SsaLivenessAnalysis & liveness)27 RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
28 CodeGenerator* codegen,
29 const SsaLivenessAnalysis& liveness)
30 : allocator_(allocator),
31 codegen_(codegen),
32 liveness_(liveness),
33 unhandled_(allocator, 0),
34 handled_(allocator, 0),
35 active_(allocator, 0),
36 inactive_(allocator, 0),
37 physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
38 spill_slots_(allocator, kDefaultNumberOfSpillSlots),
39 processing_core_registers_(false),
40 number_of_registers_(-1),
41 registers_array_(nullptr),
42 blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())) {
43 codegen->SetupBlockedRegisters(blocked_registers_);
44 physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
45 }
46
CanAllocateRegistersFor(const HGraph & graph,InstructionSet instruction_set)47 bool 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 && instruction_set != kX86_64) 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
ShouldProcess(bool processing_core_registers,LiveInterval * interval)66 static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
67 bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
68 && (interval->GetType() != Primitive::kPrimFloat);
69 return processing_core_registers == is_core_register;
70 }
71
AllocateRegisters()72 void 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
BlockRegister(Location location,size_t start,size_t end,Primitive::Type type)88 void 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
103 // TODO: make the register allocator understand instructions like HCondition
104 // that may not need to be materialized. It doesn't need to allocate any
105 // registers for it.
AllocateRegistersInternal()106 void RegisterAllocator::AllocateRegistersInternal() {
107 number_of_registers_ = processing_core_registers_
108 ? codegen_->GetNumberOfCoreRegisters()
109 : codegen_->GetNumberOfFloatingPointRegisters();
110
111 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
112
113 // Iterate post-order, to ensure the list is sorted, and the last added interval
114 // is the one with the lowest start position.
115 for (size_t i = liveness_.GetNumberOfSsaValues(); i > 0; --i) {
116 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i - 1);
117 LiveInterval* current = instruction->GetLiveInterval();
118 if (ShouldProcess(processing_core_registers_, current)) {
119 DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
120
121 LocationSummary* locations = instruction->GetLocations();
122 if (locations->GetTempCount() != 0) {
123 // Note that we already filtered out instructions requiring temporaries in
124 // RegisterAllocator::CanAllocateRegistersFor.
125 LOG(FATAL) << "Unimplemented";
126 }
127
128 // Some instructions define their output in fixed register/stack slot. We need
129 // to ensure we know these locations before doing register allocation. For a
130 // given register, we create an interval that covers these locations. The register
131 // will be unavailable at these locations when trying to allocate one for an
132 // interval.
133 //
134 // The backwards walking ensures the ranges are ordered on increasing start positions.
135 Location output = locations->Out();
136 size_t position = instruction->GetLifetimePosition();
137 if (output.IsRegister()) {
138 // Shift the interval's start by one to account for the blocked register.
139 current->SetFrom(position + 1);
140 current->SetRegister(output.reg().RegId());
141 BlockRegister(output, position, position + 1, instruction->GetType());
142 } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
143 current->SetSpillSlot(output.GetStackIndex());
144 }
145 for (size_t i = 0; i < instruction->InputCount(); ++i) {
146 Location input = locations->InAt(i);
147 if (input.IsRegister()) {
148 BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
149 }
150 }
151
152 // Add the interval to the correct list.
153 if (current->HasRegister()) {
154 DCHECK(instruction->IsParameterValue());
155 inactive_.Add(current);
156 } else if (current->HasSpillSlot() || instruction->IsConstant()) {
157 // Split before first register use.
158 size_t first_register_use = current->FirstRegisterUse();
159 if (first_register_use != kNoLifetime) {
160 LiveInterval* split = Split(current, first_register_use - 1);
161 // Don't add direclty to `unhandled_`, it needs to be sorted and the start
162 // of this new interval might be after intervals already in the list.
163 AddToUnhandled(split);
164 } else {
165 // Nothing to do, we won't allocate a register for this value.
166 }
167 } else {
168 DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
169 unhandled_.Add(current);
170 }
171 }
172 }
173
174 LinearScan();
175 }
176
177 class AllRangesIterator : public ValueObject {
178 public:
AllRangesIterator(LiveInterval * interval)179 explicit AllRangesIterator(LiveInterval* interval)
180 : current_interval_(interval),
181 current_range_(interval->GetFirstRange()) {}
182
Done() const183 bool Done() const { return current_interval_ == nullptr; }
CurrentRange() const184 LiveRange* CurrentRange() const { return current_range_; }
CurrentInterval() const185 LiveInterval* CurrentInterval() const { return current_interval_; }
186
Advance()187 void Advance() {
188 current_range_ = current_range_->GetNext();
189 if (current_range_ == nullptr) {
190 current_interval_ = current_interval_->GetNextSibling();
191 if (current_interval_ != nullptr) {
192 current_range_ = current_interval_->GetFirstRange();
193 }
194 }
195 }
196
197 private:
198 LiveInterval* current_interval_;
199 LiveRange* current_range_;
200
201 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
202 };
203
ValidateInternal(bool log_fatal_on_failure) const204 bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
205 // To simplify unit testing, we eagerly create the array of intervals, and
206 // call the helper method.
207 GrowableArray<LiveInterval*> intervals(allocator_, 0);
208 for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
209 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
210 if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
211 intervals.Add(instruction->GetLiveInterval());
212 }
213 }
214
215 for (size_t i = 0, e = physical_register_intervals_.Size(); i < e; ++i) {
216 LiveInterval* fixed = physical_register_intervals_.Get(i);
217 if (fixed != nullptr && ShouldProcess(processing_core_registers_, fixed)) {
218 intervals.Add(fixed);
219 }
220 }
221
222 return ValidateIntervals(intervals, spill_slots_.Size(), *codegen_, allocator_,
223 processing_core_registers_, log_fatal_on_failure);
224 }
225
ValidateIntervals(const GrowableArray<LiveInterval * > & intervals,size_t number_of_spill_slots,const CodeGenerator & codegen,ArenaAllocator * allocator,bool processing_core_registers,bool log_fatal_on_failure)226 bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
227 size_t number_of_spill_slots,
228 const CodeGenerator& codegen,
229 ArenaAllocator* allocator,
230 bool processing_core_registers,
231 bool log_fatal_on_failure) {
232 size_t number_of_registers = processing_core_registers
233 ? codegen.GetNumberOfCoreRegisters()
234 : codegen.GetNumberOfFloatingPointRegisters();
235 GrowableArray<ArenaBitVector*> liveness_of_values(
236 allocator, number_of_registers + number_of_spill_slots);
237
238 // Allocate a bit vector per register. A live interval that has a register
239 // allocated will populate the associated bit vector based on its live ranges.
240 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
241 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true));
242 }
243
244 for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
245 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
246 LiveInterval* current = it.CurrentInterval();
247 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
248 if (current->GetParent()->HasSpillSlot()
249 // Parameters have their own stack slot.
250 && !(defined_by != nullptr && defined_by->IsParameterValue())) {
251 BitVector* liveness_of_spill_slot = liveness_of_values.Get(
252 number_of_registers + current->GetParent()->GetSpillSlot() / kVRegSize);
253 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
254 if (liveness_of_spill_slot->IsBitSet(j)) {
255 if (log_fatal_on_failure) {
256 std::ostringstream message;
257 message << "Spill slot conflict at " << j;
258 LOG(FATAL) << message.str();
259 } else {
260 return false;
261 }
262 } else {
263 liveness_of_spill_slot->SetBit(j);
264 }
265 }
266 }
267
268 if (current->HasRegister()) {
269 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
270 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
271 if (liveness_of_register->IsBitSet(j)) {
272 if (log_fatal_on_failure) {
273 std::ostringstream message;
274 message << "Register conflict at " << j << " for ";
275 if (processing_core_registers) {
276 codegen.DumpCoreRegister(message, current->GetRegister());
277 } else {
278 codegen.DumpFloatingPointRegister(message, current->GetRegister());
279 }
280 LOG(FATAL) << message.str();
281 } else {
282 return false;
283 }
284 } else {
285 liveness_of_register->SetBit(j);
286 }
287 }
288 }
289 }
290 }
291 return true;
292 }
293
DumpInterval(std::ostream & stream,LiveInterval * interval) const294 void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
295 interval->Dump(stream);
296 stream << ": ";
297 if (interval->HasRegister()) {
298 if (processing_core_registers_) {
299 codegen_->DumpCoreRegister(stream, interval->GetRegister());
300 } else {
301 codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
302 }
303 } else {
304 stream << "spilled";
305 }
306 stream << std::endl;
307 }
308
309 // By the book implementation of a linear scan register allocator.
LinearScan()310 void RegisterAllocator::LinearScan() {
311 while (!unhandled_.IsEmpty()) {
312 // (1) Remove interval with the lowest start position from unhandled.
313 LiveInterval* current = unhandled_.Pop();
314 DCHECK(!current->IsFixed() && !current->HasRegister() && !current->HasSpillSlot());
315 size_t position = current->GetStart();
316
317 // (2) Remove currently active intervals that are dead at this position.
318 // Move active intervals that have a lifetime hole at this position
319 // to inactive.
320 for (size_t i = 0; i < active_.Size(); ++i) {
321 LiveInterval* interval = active_.Get(i);
322 if (interval->IsDeadAt(position)) {
323 active_.Delete(interval);
324 --i;
325 handled_.Add(interval);
326 } else if (!interval->Covers(position)) {
327 active_.Delete(interval);
328 --i;
329 inactive_.Add(interval);
330 }
331 }
332
333 // (3) Remove currently inactive intervals that are dead at this position.
334 // Move inactive intervals that cover this position to active.
335 for (size_t i = 0; i < inactive_.Size(); ++i) {
336 LiveInterval* interval = inactive_.Get(i);
337 if (interval->IsDeadAt(position)) {
338 inactive_.Delete(interval);
339 --i;
340 handled_.Add(interval);
341 } else if (interval->Covers(position)) {
342 inactive_.Delete(interval);
343 --i;
344 active_.Add(interval);
345 }
346 }
347
348 // (4) Try to find an available register.
349 bool success = TryAllocateFreeReg(current);
350
351 // (5) If no register could be found, we need to spill.
352 if (!success) {
353 success = AllocateBlockedReg(current);
354 }
355
356 // (6) If the interval had a register allocated, add it to the list of active
357 // intervals.
358 if (success) {
359 active_.Add(current);
360 }
361 }
362 }
363
364 // Find a free register. If multiple are found, pick the register that
365 // is free the longest.
TryAllocateFreeReg(LiveInterval * current)366 bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
367 size_t* free_until = registers_array_;
368
369 // First set all registers to be free.
370 for (size_t i = 0; i < number_of_registers_; ++i) {
371 free_until[i] = kMaxLifetimePosition;
372 }
373
374 // For each inactive interval, set its register to be free until
375 // the next intersection with `current`.
376 // Thanks to SSA, this should only be needed for intervals
377 // that are the result of a split.
378 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
379 LiveInterval* inactive = inactive_.Get(i);
380 DCHECK(inactive->HasRegister());
381 size_t next_intersection = inactive->FirstIntersectionWith(current);
382 if (next_intersection != kNoLifetime) {
383 free_until[inactive->GetRegister()] = next_intersection;
384 }
385 }
386
387 // For each active interval, set its register to not free.
388 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
389 LiveInterval* interval = active_.Get(i);
390 DCHECK(interval->HasRegister());
391 free_until[interval->GetRegister()] = 0;
392 }
393
394 // Pick the register that is free the longest.
395 int reg = -1;
396 for (size_t i = 0; i < number_of_registers_; ++i) {
397 if (IsBlocked(i)) continue;
398 if (reg == -1 || free_until[i] > free_until[reg]) {
399 reg = i;
400 if (free_until[i] == kMaxLifetimePosition) break;
401 }
402 }
403
404 // If we could not find a register, we need to spill.
405 if (reg == -1 || free_until[reg] == 0) {
406 return false;
407 }
408
409 current->SetRegister(reg);
410 if (!current->IsDeadAt(free_until[reg])) {
411 // If the register is only available for a subset of live ranges
412 // covered by `current`, split `current` at the position where
413 // the register is not available anymore.
414 LiveInterval* split = Split(current, free_until[reg]);
415 DCHECK(split != nullptr);
416 AddToUnhandled(split);
417 }
418 return true;
419 }
420
IsBlocked(int reg) const421 bool RegisterAllocator::IsBlocked(int reg) const {
422 // TODO: This only works for core registers and needs to be adjusted for
423 // floating point registers.
424 DCHECK(processing_core_registers_);
425 return blocked_registers_[reg];
426 }
427
428 // Find the register that is used the last, and spill the interval
429 // that holds it. If the first use of `current` is after that register
430 // we spill `current` instead.
AllocateBlockedReg(LiveInterval * current)431 bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
432 size_t first_register_use = current->FirstRegisterUse();
433 if (first_register_use == kNoLifetime) {
434 AllocateSpillSlotFor(current);
435 return false;
436 }
437
438 // First set all registers as not being used.
439 size_t* next_use = registers_array_;
440 for (size_t i = 0; i < number_of_registers_; ++i) {
441 next_use[i] = kMaxLifetimePosition;
442 }
443
444 // For each active interval, find the next use of its register after the
445 // start of current.
446 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
447 LiveInterval* active = active_.Get(i);
448 DCHECK(active->HasRegister());
449 if (active->IsFixed()) {
450 next_use[active->GetRegister()] = current->GetStart();
451 } else {
452 size_t use = active->FirstRegisterUseAfter(current->GetStart());
453 if (use != kNoLifetime) {
454 next_use[active->GetRegister()] = use;
455 }
456 }
457 }
458
459 // For each inactive interval, find the next use of its register after the
460 // start of current.
461 // Thanks to SSA, this should only be needed for intervals
462 // that are the result of a split.
463 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
464 LiveInterval* inactive = inactive_.Get(i);
465 DCHECK(inactive->HasRegister());
466 size_t next_intersection = inactive->FirstIntersectionWith(current);
467 if (next_intersection != kNoLifetime) {
468 if (inactive->IsFixed()) {
469 next_use[inactive->GetRegister()] =
470 std::min(next_intersection, next_use[inactive->GetRegister()]);
471 } else {
472 size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
473 if (use != kNoLifetime) {
474 next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
475 }
476 }
477 }
478 }
479
480 // Pick the register that is used the last.
481 int reg = -1;
482 for (size_t i = 0; i < number_of_registers_; ++i) {
483 if (IsBlocked(i)) continue;
484 if (reg == -1 || next_use[i] > next_use[reg]) {
485 reg = i;
486 if (next_use[i] == kMaxLifetimePosition) break;
487 }
488 }
489
490 if (first_register_use >= next_use[reg]) {
491 // If the first use of that instruction is after the last use of the found
492 // register, we split this interval just before its first register use.
493 AllocateSpillSlotFor(current);
494 LiveInterval* split = Split(current, first_register_use - 1);
495 AddToUnhandled(split);
496 return false;
497 } else {
498 // Use this register and spill the active and inactives interval that
499 // have that register.
500 current->SetRegister(reg);
501
502 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
503 LiveInterval* active = active_.Get(i);
504 if (active->GetRegister() == reg) {
505 DCHECK(!active->IsFixed());
506 LiveInterval* split = Split(active, current->GetStart());
507 active_.DeleteAt(i);
508 handled_.Add(active);
509 AddToUnhandled(split);
510 break;
511 }
512 }
513
514 for (size_t i = 0; i < inactive_.Size(); ++i) {
515 LiveInterval* inactive = inactive_.Get(i);
516 if (inactive->GetRegister() == reg) {
517 size_t next_intersection = inactive->FirstIntersectionWith(current);
518 if (next_intersection != kNoLifetime) {
519 if (inactive->IsFixed()) {
520 LiveInterval* split = Split(current, next_intersection);
521 AddToUnhandled(split);
522 } else {
523 LiveInterval* split = Split(inactive, current->GetStart());
524 inactive_.DeleteAt(i);
525 handled_.Add(inactive);
526 AddToUnhandled(split);
527 --i;
528 }
529 }
530 }
531 }
532
533 return true;
534 }
535 }
536
AddToUnhandled(LiveInterval * interval)537 void RegisterAllocator::AddToUnhandled(LiveInterval* interval) {
538 size_t insert_at = 0;
539 for (size_t i = unhandled_.Size(); i > 0; --i) {
540 LiveInterval* current = unhandled_.Get(i - 1);
541 if (current->StartsAfter(interval)) {
542 insert_at = i;
543 break;
544 }
545 }
546 unhandled_.InsertAt(insert_at, interval);
547 }
548
Split(LiveInterval * interval,size_t position)549 LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
550 DCHECK(position >= interval->GetStart());
551 DCHECK(!interval->IsDeadAt(position));
552 if (position == interval->GetStart()) {
553 // Spill slot will be allocated when handling `interval` again.
554 interval->ClearRegister();
555 return interval;
556 } else {
557 LiveInterval* new_interval = interval->SplitAt(position);
558 return new_interval;
559 }
560 }
561
NeedTwoSpillSlot(Primitive::Type type)562 static bool NeedTwoSpillSlot(Primitive::Type type) {
563 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
564 }
565
AllocateSpillSlotFor(LiveInterval * interval)566 void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
567 LiveInterval* parent = interval->GetParent();
568
569 // An instruction gets a spill slot for its entire lifetime. If the parent
570 // of this interval already has a spill slot, there is nothing to do.
571 if (parent->HasSpillSlot()) {
572 return;
573 }
574
575 HInstruction* defined_by = parent->GetDefinedBy();
576 if (defined_by->IsParameterValue()) {
577 // Parameters have their own stack slot.
578 parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
579 return;
580 }
581
582 if (defined_by->IsConstant()) {
583 // Constants don't need a spill slot.
584 return;
585 }
586
587 LiveInterval* last_sibling = interval;
588 while (last_sibling->GetNextSibling() != nullptr) {
589 last_sibling = last_sibling->GetNextSibling();
590 }
591 size_t end = last_sibling->GetEnd();
592
593 if (NeedTwoSpillSlot(parent->GetType())) {
594 AllocateTwoSpillSlots(parent, end);
595 } else {
596 AllocateOneSpillSlot(parent, end);
597 }
598 }
599
AllocateTwoSpillSlots(LiveInterval * parent,size_t end)600 void RegisterAllocator::AllocateTwoSpillSlots(LiveInterval* parent, size_t end) {
601 // Find an available spill slot.
602 size_t slot = 0;
603 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
604 // We check if it is less rather than less or equal because the parallel move
605 // resolver does not work when a single spill slot needs to be exchanged with
606 // a double spill slot. The strict comparison avoids needing to exchange these
607 // locations at the same lifetime position.
608 if (spill_slots_.Get(slot) < parent->GetStart()
609 && (slot == (e - 1) || spill_slots_.Get(slot + 1) < parent->GetStart())) {
610 break;
611 }
612 }
613
614 if (slot == spill_slots_.Size()) {
615 // We need a new spill slot.
616 spill_slots_.Add(end);
617 spill_slots_.Add(end);
618 } else if (slot == spill_slots_.Size() - 1) {
619 spill_slots_.Put(slot, end);
620 spill_slots_.Add(end);
621 } else {
622 spill_slots_.Put(slot, end);
623 spill_slots_.Put(slot + 1, end);
624 }
625
626 parent->SetSpillSlot(slot * kVRegSize);
627 }
628
AllocateOneSpillSlot(LiveInterval * parent,size_t end)629 void RegisterAllocator::AllocateOneSpillSlot(LiveInterval* parent, size_t end) {
630 // Find an available spill slot.
631 size_t slot = 0;
632 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
633 if (spill_slots_.Get(slot) <= parent->GetStart()) {
634 break;
635 }
636 }
637
638 if (slot == spill_slots_.Size()) {
639 // We need a new spill slot.
640 spill_slots_.Add(end);
641 } else {
642 spill_slots_.Put(slot, end);
643 }
644
645 parent->SetSpillSlot(slot * kVRegSize);
646 }
647
ConvertToLocation(LiveInterval * interval)648 static Location ConvertToLocation(LiveInterval* interval) {
649 if (interval->HasRegister()) {
650 return Location::RegisterLocation(ManagedRegister(interval->GetRegister()));
651 } else {
652 HInstruction* defined_by = interval->GetParent()->GetDefinedBy();
653 if (defined_by->IsConstant()) {
654 return defined_by->GetLocations()->Out();
655 } else {
656 DCHECK(interval->GetParent()->HasSpillSlot());
657 if (NeedTwoSpillSlot(interval->GetType())) {
658 return Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot());
659 } else {
660 return Location::StackSlot(interval->GetParent()->GetSpillSlot());
661 }
662 }
663 }
664 }
665
666 // We create a special marker for inputs moves to differentiate them from
667 // moves created during resolution. They must be different instructions
668 // because the input moves work on the assumption that the interval moves
669 // have been executed.
670 static constexpr size_t kInputMoveLifetimePosition = 0;
IsInputMove(HInstruction * instruction)671 static bool IsInputMove(HInstruction* instruction) {
672 return instruction->GetLifetimePosition() == kInputMoveLifetimePosition;
673 }
674
AddInputMoveFor(HInstruction * instruction,Location source,Location destination) const675 void RegisterAllocator::AddInputMoveFor(HInstruction* instruction,
676 Location source,
677 Location destination) const {
678 if (source.Equals(destination)) return;
679
680 DCHECK(instruction->AsPhi() == nullptr);
681
682 HInstruction* previous = instruction->GetPrevious();
683 HParallelMove* move = nullptr;
684 if (previous == nullptr
685 || previous->AsParallelMove() == nullptr
686 || !IsInputMove(previous)) {
687 move = new (allocator_) HParallelMove(allocator_);
688 move->SetLifetimePosition(kInputMoveLifetimePosition);
689 instruction->GetBlock()->InsertInstructionBefore(move, instruction);
690 } else {
691 move = previous->AsParallelMove();
692 }
693 DCHECK(IsInputMove(move));
694 move->AddMove(new (allocator_) MoveOperands(source, destination));
695 }
696
InsertParallelMoveAt(size_t position,Location source,Location destination) const697 void RegisterAllocator::InsertParallelMoveAt(size_t position,
698 Location source,
699 Location destination) const {
700 if (source.Equals(destination)) return;
701
702 HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
703 if (at == nullptr) {
704 // Block boundary, don't no anything the connection of split siblings will handle it.
705 return;
706 }
707 HParallelMove* move;
708 if ((position & 1) == 1) {
709 // Move must happen after the instruction.
710 DCHECK(!at->IsControlFlow());
711 move = at->GetNext()->AsParallelMove();
712 // This is a parallel move for connecting siblings in a same block. We need to
713 // differentiate it with moves for connecting blocks, and input moves.
714 if (move == nullptr || move->GetLifetimePosition() != position) {
715 move = new (allocator_) HParallelMove(allocator_);
716 move->SetLifetimePosition(position);
717 at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
718 }
719 } else {
720 // Move must happen before the instruction.
721 HInstruction* previous = at->GetPrevious();
722 if (previous != nullptr && previous->AsParallelMove() != nullptr) {
723 // This is a parallel move for connecting siblings in a same block. We need to
724 // differentiate it with moves for connecting blocks, and input moves.
725 if (previous->GetLifetimePosition() != position) {
726 previous = previous->GetPrevious();
727 }
728 }
729 if (previous == nullptr || previous->AsParallelMove() == nullptr) {
730 move = new (allocator_) HParallelMove(allocator_);
731 move->SetLifetimePosition(position);
732 at->GetBlock()->InsertInstructionBefore(move, at);
733 } else {
734 move = previous->AsParallelMove();
735 }
736 }
737 move->AddMove(new (allocator_) MoveOperands(source, destination));
738 }
739
InsertParallelMoveAtExitOf(HBasicBlock * block,Location source,Location destination) const740 void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
741 Location source,
742 Location destination) const {
743 if (source.Equals(destination)) return;
744
745 DCHECK_EQ(block->GetSuccessors().Size(), 1u);
746 HInstruction* last = block->GetLastInstruction();
747 HInstruction* previous = last->GetPrevious();
748 HParallelMove* move;
749 // This is a parallel move for connecting blocks. We need to differentiate
750 // it with moves for connecting siblings in a same block, and output moves.
751 if (previous == nullptr || previous->AsParallelMove() == nullptr
752 || previous->AsParallelMove()->GetLifetimePosition() != block->GetLifetimeEnd()) {
753 move = new (allocator_) HParallelMove(allocator_);
754 move->SetLifetimePosition(block->GetLifetimeEnd());
755 block->InsertInstructionBefore(move, last);
756 } else {
757 move = previous->AsParallelMove();
758 }
759 move->AddMove(new (allocator_) MoveOperands(source, destination));
760 }
761
InsertParallelMoveAtEntryOf(HBasicBlock * block,Location source,Location destination) const762 void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
763 Location source,
764 Location destination) const {
765 if (source.Equals(destination)) return;
766
767 HInstruction* first = block->GetFirstInstruction();
768 HParallelMove* move = first->AsParallelMove();
769 // This is a parallel move for connecting blocks. We need to differentiate
770 // it with moves for connecting siblings in a same block, and input moves.
771 if (move == nullptr || move->GetLifetimePosition() != block->GetLifetimeStart()) {
772 move = new (allocator_) HParallelMove(allocator_);
773 move->SetLifetimePosition(block->GetLifetimeStart());
774 block->InsertInstructionBefore(move, first);
775 }
776 move->AddMove(new (allocator_) MoveOperands(source, destination));
777 }
778
InsertMoveAfter(HInstruction * instruction,Location source,Location destination) const779 void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
780 Location source,
781 Location destination) const {
782 if (source.Equals(destination)) return;
783
784 if (instruction->AsPhi() != nullptr) {
785 InsertParallelMoveAtEntryOf(instruction->GetBlock(), source, destination);
786 return;
787 }
788
789 size_t position = instruction->GetLifetimePosition() + 1;
790 HParallelMove* move = instruction->GetNext()->AsParallelMove();
791 // This is a parallel move for moving the output of an instruction. We need
792 // to differentiate with input moves, moves for connecting siblings in a
793 // and moves for connecting blocks.
794 if (move == nullptr || move->GetLifetimePosition() != position) {
795 move = new (allocator_) HParallelMove(allocator_);
796 move->SetLifetimePosition(position);
797 instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
798 }
799 move->AddMove(new (allocator_) MoveOperands(source, destination));
800 }
801
ConnectSiblings(LiveInterval * interval)802 void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
803 LiveInterval* current = interval;
804 if (current->HasSpillSlot() && current->HasRegister()) {
805 // We spill eagerly, so move must be at definition.
806 InsertMoveAfter(interval->GetDefinedBy(),
807 Location::RegisterLocation(ManagedRegister(interval->GetRegister())),
808 NeedTwoSpillSlot(interval->GetType())
809 ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
810 : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
811 }
812 UsePosition* use = current->GetFirstUse();
813
814 // Walk over all siblings, updating locations of use positions, and
815 // connecting them when they are adjacent.
816 do {
817 Location source = ConvertToLocation(current);
818
819 // Walk over all uses covered by this interval, and update the location
820 // information.
821 while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
822 if (!use->GetIsEnvironment()) {
823 LocationSummary* locations = use->GetUser()->GetLocations();
824 Location expected_location = locations->InAt(use->GetInputIndex());
825 if (expected_location.IsUnallocated()) {
826 locations->SetInAt(use->GetInputIndex(), source);
827 } else {
828 AddInputMoveFor(use->GetUser(), source, expected_location);
829 }
830 }
831 use = use->GetNext();
832 }
833
834 // If the next interval starts just after this one, and has a register,
835 // insert a move.
836 LiveInterval* next_sibling = current->GetNextSibling();
837 if (next_sibling != nullptr
838 && next_sibling->HasRegister()
839 && current->GetEnd() == next_sibling->GetStart()) {
840 Location destination = ConvertToLocation(next_sibling);
841 InsertParallelMoveAt(current->GetEnd(), source, destination);
842 }
843 current = next_sibling;
844 } while (current != nullptr);
845 DCHECK(use == nullptr);
846 }
847
ConnectSplitSiblings(LiveInterval * interval,HBasicBlock * from,HBasicBlock * to) const848 void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
849 HBasicBlock* from,
850 HBasicBlock* to) const {
851 if (interval->GetNextSibling() == nullptr) {
852 // Nothing to connect. The whole range was allocated to the same location.
853 return;
854 }
855
856 size_t from_position = from->GetLifetimeEnd() - 1;
857 size_t to_position = to->GetLifetimeStart();
858
859 LiveInterval* destination = nullptr;
860 LiveInterval* source = nullptr;
861
862 LiveInterval* current = interval;
863
864 // Check the intervals that cover `from` and `to`.
865 while ((current != nullptr) && (source == nullptr || destination == nullptr)) {
866 if (current->Covers(from_position)) {
867 DCHECK(source == nullptr);
868 source = current;
869 }
870 if (current->Covers(to_position)) {
871 DCHECK(destination == nullptr);
872 destination = current;
873 }
874
875 current = current->GetNextSibling();
876 }
877
878 if (destination == source) {
879 // Interval was not split.
880 return;
881 }
882
883 if (!destination->HasRegister()) {
884 // Values are eagerly spilled. Spill slot already contains appropriate value.
885 return;
886 }
887
888 // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
889 // we need to put the moves at the entry of `to`.
890 if (from->GetSuccessors().Size() == 1) {
891 InsertParallelMoveAtExitOf(from, ConvertToLocation(source), ConvertToLocation(destination));
892 } else {
893 DCHECK_EQ(to->GetPredecessors().Size(), 1u);
894 InsertParallelMoveAtEntryOf(to, ConvertToLocation(source), ConvertToLocation(destination));
895 }
896 }
897
898 // Returns the location of `interval`, or siblings of `interval`, at `position`.
FindLocationAt(LiveInterval * interval,size_t position)899 static Location FindLocationAt(LiveInterval* interval, size_t position) {
900 LiveInterval* current = interval;
901 while (!current->Covers(position)) {
902 current = current->GetNextSibling();
903 DCHECK(current != nullptr);
904 }
905 return ConvertToLocation(current);
906 }
907
Resolve()908 void RegisterAllocator::Resolve() {
909 codegen_->ComputeFrameSize(spill_slots_.Size());
910
911 // Adjust the Out Location of instructions.
912 // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
913 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
914 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
915 LiveInterval* current = instruction->GetLiveInterval();
916 LocationSummary* locations = instruction->GetLocations();
917 Location location = locations->Out();
918 if (instruction->AsParameterValue() != nullptr) {
919 // Now that we know the frame size, adjust the parameter's location.
920 if (location.IsStackSlot()) {
921 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
922 current->SetSpillSlot(location.GetStackIndex());
923 locations->SetOut(location);
924 } else if (location.IsDoubleStackSlot()) {
925 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
926 current->SetSpillSlot(location.GetStackIndex());
927 locations->SetOut(location);
928 } else if (current->HasSpillSlot()) {
929 current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
930 }
931 }
932
933 Location source = ConvertToLocation(current);
934
935 if (location.IsUnallocated()) {
936 if (location.GetPolicy() == Location::kSameAsFirstInput) {
937 locations->SetInAt(0, source);
938 }
939 locations->SetOut(source);
940 } else {
941 DCHECK(source.Equals(location));
942 }
943 }
944
945 // Connect siblings.
946 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
947 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
948 ConnectSiblings(instruction->GetLiveInterval());
949 }
950
951 // Resolve non-linear control flow across branches. Order does not matter.
952 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
953 HBasicBlock* block = it.Current();
954 BitVector* live = liveness_.GetLiveInSet(*block);
955 for (uint32_t idx : live->Indexes()) {
956 HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
957 LiveInterval* interval = current->GetLiveInterval();
958 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
959 ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
960 }
961 }
962 }
963
964 // Resolve phi inputs. Order does not matter.
965 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
966 HBasicBlock* current = it.Current();
967 for (HInstructionIterator it(current->GetPhis()); !it.Done(); it.Advance()) {
968 HInstruction* phi = it.Current();
969 for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
970 HBasicBlock* predecessor = current->GetPredecessors().Get(i);
971 DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
972 HInstruction* input = phi->InputAt(i);
973 Location source = FindLocationAt(input->GetLiveInterval(),
974 predecessor->GetLastInstruction()->GetLifetimePosition());
975 Location destination = ConvertToLocation(phi->GetLiveInterval());
976 InsertParallelMoveAtExitOf(predecessor, source, destination);
977 }
978 }
979 }
980 }
981
982 } // namespace art
983