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 <iostream>
20 #include <sstream>
21
22 #include "base/bit_vector-inl.h"
23 #include "code_generator.h"
24 #include "ssa_liveness_analysis.h"
25
26 namespace art {
27
28 static constexpr size_t kMaxLifetimePosition = -1;
29 static constexpr size_t kDefaultNumberOfSpillSlots = 4;
30
31 // For simplicity, we implement register pairs as (reg, reg + 1).
32 // Note that this is a requirement for double registers on ARM, since we
33 // allocate SRegister.
GetHighForLowRegister(int reg)34 static int GetHighForLowRegister(int reg) { return reg + 1; }
IsLowRegister(int reg)35 static bool IsLowRegister(int reg) { return (reg & 1) == 0; }
IsLowOfUnalignedPairInterval(LiveInterval * low)36 static bool IsLowOfUnalignedPairInterval(LiveInterval* low) {
37 return GetHighForLowRegister(low->GetRegister()) != low->GetHighInterval()->GetRegister();
38 }
39
RegisterAllocator(ArenaAllocator * allocator,CodeGenerator * codegen,const SsaLivenessAnalysis & liveness)40 RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
41 CodeGenerator* codegen,
42 const SsaLivenessAnalysis& liveness)
43 : allocator_(allocator),
44 codegen_(codegen),
45 liveness_(liveness),
46 unhandled_core_intervals_(allocator, 0),
47 unhandled_fp_intervals_(allocator, 0),
48 unhandled_(nullptr),
49 handled_(allocator, 0),
50 active_(allocator, 0),
51 inactive_(allocator, 0),
52 physical_core_register_intervals_(allocator, codegen->GetNumberOfCoreRegisters()),
53 physical_fp_register_intervals_(allocator, codegen->GetNumberOfFloatingPointRegisters()),
54 temp_intervals_(allocator, 4),
55 int_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
56 long_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
57 float_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
58 double_spill_slots_(allocator, kDefaultNumberOfSpillSlots),
59 safepoints_(allocator, 0),
60 processing_core_registers_(false),
61 number_of_registers_(-1),
62 registers_array_(nullptr),
63 blocked_core_registers_(codegen->GetBlockedCoreRegisters()),
64 blocked_fp_registers_(codegen->GetBlockedFloatingPointRegisters()),
65 reserved_out_slots_(0),
66 maximum_number_of_live_core_registers_(0),
67 maximum_number_of_live_fp_registers_(0) {
68 static constexpr bool kIsBaseline = false;
69 codegen->SetupBlockedRegisters(kIsBaseline);
70 physical_core_register_intervals_.SetSize(codegen->GetNumberOfCoreRegisters());
71 physical_fp_register_intervals_.SetSize(codegen->GetNumberOfFloatingPointRegisters());
72 // Always reserve for the current method and the graph's max out registers.
73 // TODO: compute it instead.
74 // ArtMethod* takes 2 vregs for 64 bits.
75 reserved_out_slots_ = InstructionSetPointerSize(codegen->GetInstructionSet()) / kVRegSize +
76 codegen->GetGraph()->GetMaximumNumberOfOutVRegs();
77 }
78
CanAllocateRegistersFor(const HGraph & graph ATTRIBUTE_UNUSED,InstructionSet instruction_set)79 bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph ATTRIBUTE_UNUSED,
80 InstructionSet instruction_set) {
81 return instruction_set == kArm64
82 || instruction_set == kX86_64
83 || instruction_set == kMips64
84 || instruction_set == kArm
85 || instruction_set == kX86
86 || instruction_set == kThumb2;
87 }
88
ShouldProcess(bool processing_core_registers,LiveInterval * interval)89 static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
90 if (interval == nullptr) return false;
91 bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
92 && (interval->GetType() != Primitive::kPrimFloat);
93 return processing_core_registers == is_core_register;
94 }
95
AllocateRegisters()96 void RegisterAllocator::AllocateRegisters() {
97 AllocateRegistersInternal();
98 Resolve();
99
100 if (kIsDebugBuild) {
101 processing_core_registers_ = true;
102 ValidateInternal(true);
103 processing_core_registers_ = false;
104 ValidateInternal(true);
105 // Check that the linear order is still correct with regards to lifetime positions.
106 // Since only parallel moves have been inserted during the register allocation,
107 // these checks are mostly for making sure these moves have been added correctly.
108 size_t current_liveness = 0;
109 for (HLinearOrderIterator it(*codegen_->GetGraph()); !it.Done(); it.Advance()) {
110 HBasicBlock* block = it.Current();
111 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
112 HInstruction* instruction = inst_it.Current();
113 DCHECK_LE(current_liveness, instruction->GetLifetimePosition());
114 current_liveness = instruction->GetLifetimePosition();
115 }
116 for (HInstructionIterator inst_it(block->GetInstructions());
117 !inst_it.Done();
118 inst_it.Advance()) {
119 HInstruction* instruction = inst_it.Current();
120 DCHECK_LE(current_liveness, instruction->GetLifetimePosition()) << instruction->DebugName();
121 current_liveness = instruction->GetLifetimePosition();
122 }
123 }
124 }
125 }
126
BlockRegister(Location location,size_t start,size_t end)127 void RegisterAllocator::BlockRegister(Location location,
128 size_t start,
129 size_t end) {
130 int reg = location.reg();
131 DCHECK(location.IsRegister() || location.IsFpuRegister());
132 LiveInterval* interval = location.IsRegister()
133 ? physical_core_register_intervals_.Get(reg)
134 : physical_fp_register_intervals_.Get(reg);
135 Primitive::Type type = location.IsRegister()
136 ? Primitive::kPrimInt
137 : Primitive::kPrimFloat;
138 if (interval == nullptr) {
139 interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
140 if (location.IsRegister()) {
141 physical_core_register_intervals_.Put(reg, interval);
142 } else {
143 physical_fp_register_intervals_.Put(reg, interval);
144 }
145 }
146 DCHECK(interval->GetRegister() == reg);
147 interval->AddRange(start, end);
148 }
149
AllocateRegistersInternal()150 void RegisterAllocator::AllocateRegistersInternal() {
151 // Iterate post-order, to ensure the list is sorted, and the last added interval
152 // is the one with the lowest start position.
153 for (HLinearPostOrderIterator it(*codegen_->GetGraph()); !it.Done(); it.Advance()) {
154 HBasicBlock* block = it.Current();
155 for (HBackwardInstructionIterator back_it(block->GetInstructions()); !back_it.Done();
156 back_it.Advance()) {
157 ProcessInstruction(back_it.Current());
158 }
159 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
160 ProcessInstruction(inst_it.Current());
161 }
162 }
163
164 number_of_registers_ = codegen_->GetNumberOfCoreRegisters();
165 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
166 processing_core_registers_ = true;
167 unhandled_ = &unhandled_core_intervals_;
168 for (size_t i = 0, e = physical_core_register_intervals_.Size(); i < e; ++i) {
169 LiveInterval* fixed = physical_core_register_intervals_.Get(i);
170 if (fixed != nullptr) {
171 // Fixed interval is added to inactive_ instead of unhandled_.
172 // It's also the only type of inactive interval whose start position
173 // can be after the current interval during linear scan.
174 // Fixed interval is never split and never moves to unhandled_.
175 inactive_.Add(fixed);
176 }
177 }
178 LinearScan();
179
180 inactive_.Reset();
181 active_.Reset();
182 handled_.Reset();
183
184 number_of_registers_ = codegen_->GetNumberOfFloatingPointRegisters();
185 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
186 processing_core_registers_ = false;
187 unhandled_ = &unhandled_fp_intervals_;
188 for (size_t i = 0, e = physical_fp_register_intervals_.Size(); i < e; ++i) {
189 LiveInterval* fixed = physical_fp_register_intervals_.Get(i);
190 if (fixed != nullptr) {
191 // Fixed interval is added to inactive_ instead of unhandled_.
192 // It's also the only type of inactive interval whose start position
193 // can be after the current interval during linear scan.
194 // Fixed interval is never split and never moves to unhandled_.
195 inactive_.Add(fixed);
196 }
197 }
198 LinearScan();
199 }
200
ProcessInstruction(HInstruction * instruction)201 void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
202 LocationSummary* locations = instruction->GetLocations();
203 size_t position = instruction->GetLifetimePosition();
204
205 if (locations == nullptr) return;
206
207 // Create synthesized intervals for temporaries.
208 for (size_t i = 0; i < locations->GetTempCount(); ++i) {
209 Location temp = locations->GetTemp(i);
210 if (temp.IsRegister() || temp.IsFpuRegister()) {
211 BlockRegister(temp, position, position + 1);
212 } else {
213 DCHECK(temp.IsUnallocated());
214 switch (temp.GetPolicy()) {
215 case Location::kRequiresRegister: {
216 LiveInterval* interval =
217 LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
218 temp_intervals_.Add(interval);
219 interval->AddTempUse(instruction, i);
220 unhandled_core_intervals_.Add(interval);
221 break;
222 }
223
224 case Location::kRequiresFpuRegister: {
225 LiveInterval* interval =
226 LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
227 temp_intervals_.Add(interval);
228 interval->AddTempUse(instruction, i);
229 if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
230 interval->AddHighInterval(/* is_temp */ true);
231 LiveInterval* high = interval->GetHighInterval();
232 temp_intervals_.Add(high);
233 unhandled_fp_intervals_.Add(high);
234 }
235 unhandled_fp_intervals_.Add(interval);
236 break;
237 }
238
239 default:
240 LOG(FATAL) << "Unexpected policy for temporary location "
241 << temp.GetPolicy();
242 }
243 }
244 }
245
246 bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
247 && (instruction->GetType() != Primitive::kPrimFloat);
248
249 if (locations->CanCall()) {
250 if (codegen_->IsLeafMethod()) {
251 // TODO: We do this here because we do not want the suspend check to artificially
252 // create live registers. We should find another place, but this is currently the
253 // simplest.
254 DCHECK(instruction->IsSuspendCheckEntry());
255 instruction->GetBlock()->RemoveInstruction(instruction);
256 return;
257 }
258 safepoints_.Add(instruction);
259 if (locations->OnlyCallsOnSlowPath()) {
260 // We add a synthesized range at this position to record the live registers
261 // at this position. Ideally, we could just update the safepoints when locations
262 // are updated, but we currently need to know the full stack size before updating
263 // locations (because of parameters and the fact that we don't have a frame pointer).
264 // And knowing the full stack size requires to know the maximum number of live
265 // registers at calls in slow paths.
266 // By adding the following interval in the algorithm, we can compute this
267 // maximum before updating locations.
268 LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
269 interval->AddRange(position, position + 1);
270 AddSorted(&unhandled_core_intervals_, interval);
271 AddSorted(&unhandled_fp_intervals_, interval);
272 }
273 }
274
275 if (locations->WillCall()) {
276 // Block all registers.
277 for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
278 if (!codegen_->IsCoreCalleeSaveRegister(i)) {
279 BlockRegister(Location::RegisterLocation(i),
280 position,
281 position + 1);
282 }
283 }
284 for (size_t i = 0; i < codegen_->GetNumberOfFloatingPointRegisters(); ++i) {
285 if (!codegen_->IsFloatingPointCalleeSaveRegister(i)) {
286 BlockRegister(Location::FpuRegisterLocation(i),
287 position,
288 position + 1);
289 }
290 }
291 }
292
293 for (size_t i = 0; i < instruction->InputCount(); ++i) {
294 Location input = locations->InAt(i);
295 if (input.IsRegister() || input.IsFpuRegister()) {
296 BlockRegister(input, position, position + 1);
297 } else if (input.IsPair()) {
298 BlockRegister(input.ToLow(), position, position + 1);
299 BlockRegister(input.ToHigh(), position, position + 1);
300 }
301 }
302
303 LiveInterval* current = instruction->GetLiveInterval();
304 if (current == nullptr) return;
305
306 GrowableArray<LiveInterval*>& unhandled = core_register
307 ? unhandled_core_intervals_
308 : unhandled_fp_intervals_;
309
310 DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
311
312 if (codegen_->NeedsTwoRegisters(current->GetType())) {
313 current->AddHighInterval();
314 }
315
316 for (size_t safepoint_index = safepoints_.Size(); safepoint_index > 0; --safepoint_index) {
317 HInstruction* safepoint = safepoints_.Get(safepoint_index - 1);
318 size_t safepoint_position = safepoint->GetLifetimePosition();
319
320 // Test that safepoints are ordered in the optimal way.
321 DCHECK(safepoint_index == safepoints_.Size()
322 || safepoints_.Get(safepoint_index)->GetLifetimePosition() < safepoint_position);
323
324 if (safepoint_position == current->GetStart()) {
325 // The safepoint is for this instruction, so the location of the instruction
326 // does not need to be saved.
327 DCHECK_EQ(safepoint_index, safepoints_.Size());
328 DCHECK_EQ(safepoint, instruction);
329 continue;
330 } else if (current->IsDeadAt(safepoint_position)) {
331 break;
332 } else if (!current->Covers(safepoint_position)) {
333 // Hole in the interval.
334 continue;
335 }
336 current->AddSafepoint(safepoint);
337 }
338 current->ResetSearchCache();
339
340 // Some instructions define their output in fixed register/stack slot. We need
341 // to ensure we know these locations before doing register allocation. For a
342 // given register, we create an interval that covers these locations. The register
343 // will be unavailable at these locations when trying to allocate one for an
344 // interval.
345 //
346 // The backwards walking ensures the ranges are ordered on increasing start positions.
347 Location output = locations->Out();
348 if (output.IsUnallocated() && output.GetPolicy() == Location::kSameAsFirstInput) {
349 Location first = locations->InAt(0);
350 if (first.IsRegister() || first.IsFpuRegister()) {
351 current->SetFrom(position + 1);
352 current->SetRegister(first.reg());
353 } else if (first.IsPair()) {
354 current->SetFrom(position + 1);
355 current->SetRegister(first.low());
356 LiveInterval* high = current->GetHighInterval();
357 high->SetRegister(first.high());
358 high->SetFrom(position + 1);
359 }
360 } else if (output.IsRegister() || output.IsFpuRegister()) {
361 // Shift the interval's start by one to account for the blocked register.
362 current->SetFrom(position + 1);
363 current->SetRegister(output.reg());
364 BlockRegister(output, position, position + 1);
365 } else if (output.IsPair()) {
366 current->SetFrom(position + 1);
367 current->SetRegister(output.low());
368 LiveInterval* high = current->GetHighInterval();
369 high->SetRegister(output.high());
370 high->SetFrom(position + 1);
371 BlockRegister(output.ToLow(), position, position + 1);
372 BlockRegister(output.ToHigh(), position, position + 1);
373 } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
374 current->SetSpillSlot(output.GetStackIndex());
375 } else {
376 DCHECK(output.IsUnallocated() || output.IsConstant());
377 }
378
379 // If needed, add interval to the list of unhandled intervals.
380 if (current->HasSpillSlot() || instruction->IsConstant()) {
381 // Split just before first register use.
382 size_t first_register_use = current->FirstRegisterUse();
383 if (first_register_use != kNoLifetime) {
384 LiveInterval* split = SplitBetween(current, current->GetStart(), first_register_use - 1);
385 // Don't add directly to `unhandled`, it needs to be sorted and the start
386 // of this new interval might be after intervals already in the list.
387 AddSorted(&unhandled, split);
388 } else {
389 // Nothing to do, we won't allocate a register for this value.
390 }
391 } else {
392 // Don't add directly to `unhandled`, temp or safepoint intervals
393 // for this instruction may have been added, and those can be
394 // processed first.
395 AddSorted(&unhandled, current);
396 }
397 }
398
399 class AllRangesIterator : public ValueObject {
400 public:
AllRangesIterator(LiveInterval * interval)401 explicit AllRangesIterator(LiveInterval* interval)
402 : current_interval_(interval),
403 current_range_(interval->GetFirstRange()) {}
404
Done() const405 bool Done() const { return current_interval_ == nullptr; }
CurrentRange() const406 LiveRange* CurrentRange() const { return current_range_; }
CurrentInterval() const407 LiveInterval* CurrentInterval() const { return current_interval_; }
408
Advance()409 void Advance() {
410 current_range_ = current_range_->GetNext();
411 if (current_range_ == nullptr) {
412 current_interval_ = current_interval_->GetNextSibling();
413 if (current_interval_ != nullptr) {
414 current_range_ = current_interval_->GetFirstRange();
415 }
416 }
417 }
418
419 private:
420 LiveInterval* current_interval_;
421 LiveRange* current_range_;
422
423 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
424 };
425
ValidateInternal(bool log_fatal_on_failure) const426 bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
427 // To simplify unit testing, we eagerly create the array of intervals, and
428 // call the helper method.
429 GrowableArray<LiveInterval*> intervals(allocator_, 0);
430 for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
431 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
432 if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
433 intervals.Add(instruction->GetLiveInterval());
434 }
435 }
436
437 if (processing_core_registers_) {
438 for (size_t i = 0, e = physical_core_register_intervals_.Size(); i < e; ++i) {
439 LiveInterval* fixed = physical_core_register_intervals_.Get(i);
440 if (fixed != nullptr) {
441 intervals.Add(fixed);
442 }
443 }
444 } else {
445 for (size_t i = 0, e = physical_fp_register_intervals_.Size(); i < e; ++i) {
446 LiveInterval* fixed = physical_fp_register_intervals_.Get(i);
447 if (fixed != nullptr) {
448 intervals.Add(fixed);
449 }
450 }
451 }
452
453 for (size_t i = 0, e = temp_intervals_.Size(); i < e; ++i) {
454 LiveInterval* temp = temp_intervals_.Get(i);
455 if (ShouldProcess(processing_core_registers_, temp)) {
456 intervals.Add(temp);
457 }
458 }
459
460 return ValidateIntervals(intervals, GetNumberOfSpillSlots(), reserved_out_slots_, *codegen_,
461 allocator_, processing_core_registers_, log_fatal_on_failure);
462 }
463
ValidateIntervals(const GrowableArray<LiveInterval * > & intervals,size_t number_of_spill_slots,size_t number_of_out_slots,const CodeGenerator & codegen,ArenaAllocator * allocator,bool processing_core_registers,bool log_fatal_on_failure)464 bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
465 size_t number_of_spill_slots,
466 size_t number_of_out_slots,
467 const CodeGenerator& codegen,
468 ArenaAllocator* allocator,
469 bool processing_core_registers,
470 bool log_fatal_on_failure) {
471 size_t number_of_registers = processing_core_registers
472 ? codegen.GetNumberOfCoreRegisters()
473 : codegen.GetNumberOfFloatingPointRegisters();
474 GrowableArray<ArenaBitVector*> liveness_of_values(
475 allocator, number_of_registers + number_of_spill_slots);
476
477 // Allocate a bit vector per register. A live interval that has a register
478 // allocated will populate the associated bit vector based on its live ranges.
479 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
480 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true));
481 }
482
483 for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
484 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
485 LiveInterval* current = it.CurrentInterval();
486 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
487 if (current->GetParent()->HasSpillSlot()
488 // Parameters have their own stack slot.
489 && !(defined_by != nullptr && defined_by->IsParameterValue())) {
490 BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers
491 + current->GetParent()->GetSpillSlot() / kVRegSize
492 - number_of_out_slots);
493 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
494 if (liveness_of_spill_slot->IsBitSet(j)) {
495 if (log_fatal_on_failure) {
496 std::ostringstream message;
497 message << "Spill slot conflict at " << j;
498 LOG(FATAL) << message.str();
499 } else {
500 return false;
501 }
502 } else {
503 liveness_of_spill_slot->SetBit(j);
504 }
505 }
506 }
507
508 if (current->HasRegister()) {
509 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
510 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
511 if (liveness_of_register->IsBitSet(j)) {
512 if (current->IsUsingInputRegister() && current->CanUseInputRegister()) {
513 continue;
514 }
515 if (log_fatal_on_failure) {
516 std::ostringstream message;
517 message << "Register conflict at " << j << " ";
518 if (defined_by != nullptr) {
519 message << "(" << defined_by->DebugName() << ")";
520 }
521 message << "for ";
522 if (processing_core_registers) {
523 codegen.DumpCoreRegister(message, current->GetRegister());
524 } else {
525 codegen.DumpFloatingPointRegister(message, current->GetRegister());
526 }
527 LOG(FATAL) << message.str();
528 } else {
529 return false;
530 }
531 } else {
532 liveness_of_register->SetBit(j);
533 }
534 }
535 }
536 }
537 }
538 return true;
539 }
540
DumpInterval(std::ostream & stream,LiveInterval * interval) const541 void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
542 interval->Dump(stream);
543 stream << ": ";
544 if (interval->HasRegister()) {
545 if (interval->IsFloatingPoint()) {
546 codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
547 } else {
548 codegen_->DumpCoreRegister(stream, interval->GetRegister());
549 }
550 } else {
551 stream << "spilled";
552 }
553 stream << std::endl;
554 }
555
DumpAllIntervals(std::ostream & stream) const556 void RegisterAllocator::DumpAllIntervals(std::ostream& stream) const {
557 stream << "inactive: " << std::endl;
558 for (size_t i = 0; i < inactive_.Size(); i ++) {
559 DumpInterval(stream, inactive_.Get(i));
560 }
561 stream << "active: " << std::endl;
562 for (size_t i = 0; i < active_.Size(); i ++) {
563 DumpInterval(stream, active_.Get(i));
564 }
565 stream << "unhandled: " << std::endl;
566 auto unhandled = (unhandled_ != nullptr) ?
567 unhandled_ : &unhandled_core_intervals_;
568 for (size_t i = 0; i < unhandled->Size(); i ++) {
569 DumpInterval(stream, unhandled->Get(i));
570 }
571 stream << "handled: " << std::endl;
572 for (size_t i = 0; i < handled_.Size(); i ++) {
573 DumpInterval(stream, handled_.Get(i));
574 }
575 }
576
577 // By the book implementation of a linear scan register allocator.
LinearScan()578 void RegisterAllocator::LinearScan() {
579 while (!unhandled_->IsEmpty()) {
580 // (1) Remove interval with the lowest start position from unhandled.
581 LiveInterval* current = unhandled_->Pop();
582 DCHECK(!current->IsFixed() && !current->HasSpillSlot());
583 DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart());
584 DCHECK(!current->IsLowInterval() || unhandled_->Peek()->IsHighInterval());
585
586 size_t position = current->GetStart();
587
588 // Remember the inactive_ size here since the ones moved to inactive_ from
589 // active_ below shouldn't need to be re-checked.
590 size_t inactive_intervals_to_handle = inactive_.Size();
591
592 // (2) Remove currently active intervals that are dead at this position.
593 // Move active intervals that have a lifetime hole at this position
594 // to inactive.
595 for (size_t i = 0; i < active_.Size(); ++i) {
596 LiveInterval* interval = active_.Get(i);
597 if (interval->IsDeadAt(position)) {
598 active_.Delete(interval);
599 --i;
600 handled_.Add(interval);
601 } else if (!interval->Covers(position)) {
602 active_.Delete(interval);
603 --i;
604 inactive_.Add(interval);
605 }
606 }
607
608 // (3) Remove currently inactive intervals that are dead at this position.
609 // Move inactive intervals that cover this position to active.
610 for (size_t i = 0; i < inactive_intervals_to_handle; ++i) {
611 LiveInterval* interval = inactive_.Get(i);
612 DCHECK(interval->GetStart() < position || interval->IsFixed());
613 if (interval->IsDeadAt(position)) {
614 inactive_.Delete(interval);
615 --i;
616 --inactive_intervals_to_handle;
617 handled_.Add(interval);
618 } else if (interval->Covers(position)) {
619 inactive_.Delete(interval);
620 --i;
621 --inactive_intervals_to_handle;
622 active_.Add(interval);
623 }
624 }
625
626 if (current->IsSlowPathSafepoint()) {
627 // Synthesized interval to record the maximum number of live registers
628 // at safepoints. No need to allocate a register for it.
629 if (processing_core_registers_) {
630 maximum_number_of_live_core_registers_ =
631 std::max(maximum_number_of_live_core_registers_, active_.Size());
632 } else {
633 maximum_number_of_live_fp_registers_ =
634 std::max(maximum_number_of_live_fp_registers_, active_.Size());
635 }
636 DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() > current->GetStart());
637 continue;
638 }
639
640 if (current->IsHighInterval() && !current->GetLowInterval()->HasRegister()) {
641 DCHECK(!current->HasRegister());
642 // Allocating the low part was unsucessful. The splitted interval for the high part
643 // will be handled next (it is in the `unhandled_` list).
644 continue;
645 }
646
647 // (4) Try to find an available register.
648 bool success = TryAllocateFreeReg(current);
649
650 // (5) If no register could be found, we need to spill.
651 if (!success) {
652 success = AllocateBlockedReg(current);
653 }
654
655 // (6) If the interval had a register allocated, add it to the list of active
656 // intervals.
657 if (success) {
658 codegen_->AddAllocatedRegister(processing_core_registers_
659 ? Location::RegisterLocation(current->GetRegister())
660 : Location::FpuRegisterLocation(current->GetRegister()));
661 active_.Add(current);
662 if (current->HasHighInterval() && !current->GetHighInterval()->HasRegister()) {
663 current->GetHighInterval()->SetRegister(GetHighForLowRegister(current->GetRegister()));
664 }
665 }
666 }
667 }
668
FreeIfNotCoverAt(LiveInterval * interval,size_t position,size_t * free_until)669 static void FreeIfNotCoverAt(LiveInterval* interval, size_t position, size_t* free_until) {
670 DCHECK(!interval->IsHighInterval());
671 // Note that the same instruction may occur multiple times in the input list,
672 // so `free_until` may have changed already.
673 // Since `position` is not the current scan position, we need to use CoversSlow.
674 if (interval->IsDeadAt(position)) {
675 // Set the register to be free. Note that inactive intervals might later
676 // update this.
677 free_until[interval->GetRegister()] = kMaxLifetimePosition;
678 if (interval->HasHighInterval()) {
679 DCHECK(interval->GetHighInterval()->IsDeadAt(position));
680 free_until[interval->GetHighInterval()->GetRegister()] = kMaxLifetimePosition;
681 }
682 } else if (!interval->CoversSlow(position)) {
683 // The interval becomes inactive at `defined_by`. We make its register
684 // available only until the next use strictly after `defined_by`.
685 free_until[interval->GetRegister()] = interval->FirstUseAfter(position);
686 if (interval->HasHighInterval()) {
687 DCHECK(!interval->GetHighInterval()->CoversSlow(position));
688 free_until[interval->GetHighInterval()->GetRegister()] = free_until[interval->GetRegister()];
689 }
690 }
691 }
692
693 // Find a free register. If multiple are found, pick the register that
694 // is free the longest.
TryAllocateFreeReg(LiveInterval * current)695 bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
696 size_t* free_until = registers_array_;
697
698 // First set all registers to be free.
699 for (size_t i = 0; i < number_of_registers_; ++i) {
700 free_until[i] = kMaxLifetimePosition;
701 }
702
703 // For each active interval, set its register to not free.
704 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
705 LiveInterval* interval = active_.Get(i);
706 DCHECK(interval->HasRegister());
707 free_until[interval->GetRegister()] = 0;
708 }
709
710 // An interval that starts an instruction (that is, it is not split), may
711 // re-use the registers used by the inputs of that instruciton, based on the
712 // location summary.
713 HInstruction* defined_by = current->GetDefinedBy();
714 if (defined_by != nullptr && !current->IsSplit()) {
715 LocationSummary* locations = defined_by->GetLocations();
716 if (!locations->OutputCanOverlapWithInputs() && locations->Out().IsUnallocated()) {
717 for (HInputIterator it(defined_by); !it.Done(); it.Advance()) {
718 // Take the last interval of the input. It is the location of that interval
719 // that will be used at `defined_by`.
720 LiveInterval* interval = it.Current()->GetLiveInterval()->GetLastSibling();
721 // Note that interval may have not been processed yet.
722 // TODO: Handle non-split intervals last in the work list.
723 if (interval->HasRegister() && interval->SameRegisterKind(*current)) {
724 // The input must be live until the end of `defined_by`, to comply to
725 // the linear scan algorithm. So we use `defined_by`'s end lifetime
726 // position to check whether the input is dead or is inactive after
727 // `defined_by`.
728 DCHECK(interval->CoversSlow(defined_by->GetLifetimePosition()));
729 size_t position = defined_by->GetLifetimePosition() + 1;
730 FreeIfNotCoverAt(interval, position, free_until);
731 }
732 }
733 }
734 }
735
736 // For each inactive interval, set its register to be free until
737 // the next intersection with `current`.
738 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
739 LiveInterval* inactive = inactive_.Get(i);
740 // Temp/Slow-path-safepoint interval has no holes.
741 DCHECK(!inactive->IsTemp() && !inactive->IsSlowPathSafepoint());
742 if (!current->IsSplit() && !inactive->IsFixed()) {
743 // Neither current nor inactive are fixed.
744 // Thanks to SSA, a non-split interval starting in a hole of an
745 // inactive interval should never intersect with that inactive interval.
746 // Only if it's not fixed though, because fixed intervals don't come from SSA.
747 DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
748 continue;
749 }
750
751 DCHECK(inactive->HasRegister());
752 if (free_until[inactive->GetRegister()] == 0) {
753 // Already used by some active interval. No need to intersect.
754 continue;
755 }
756 size_t next_intersection = inactive->FirstIntersectionWith(current);
757 if (next_intersection != kNoLifetime) {
758 free_until[inactive->GetRegister()] =
759 std::min(free_until[inactive->GetRegister()], next_intersection);
760 }
761 }
762
763 int reg = kNoRegister;
764 if (current->HasRegister()) {
765 // Some instructions have a fixed register output.
766 reg = current->GetRegister();
767 if (free_until[reg] == 0) {
768 DCHECK(current->IsHighInterval());
769 // AllocateBlockedReg will spill the holder of the register.
770 return false;
771 }
772 } else {
773 DCHECK(!current->IsHighInterval());
774 int hint = current->FindFirstRegisterHint(free_until, liveness_);
775 if ((hint != kNoRegister)
776 // For simplicity, if the hint we are getting for a pair cannot be used,
777 // we are just going to allocate a new pair.
778 && !(current->IsLowInterval() && IsBlocked(GetHighForLowRegister(hint)))) {
779 DCHECK(!IsBlocked(hint));
780 reg = hint;
781 } else if (current->IsLowInterval()) {
782 reg = FindAvailableRegisterPair(free_until, current->GetStart());
783 } else {
784 reg = FindAvailableRegister(free_until);
785 }
786 }
787
788 DCHECK_NE(reg, kNoRegister);
789 // If we could not find a register, we need to spill.
790 if (free_until[reg] == 0) {
791 return false;
792 }
793
794 if (current->IsLowInterval()) {
795 // If the high register of this interval is not available, we need to spill.
796 int high_reg = current->GetHighInterval()->GetRegister();
797 if (high_reg == kNoRegister) {
798 high_reg = GetHighForLowRegister(reg);
799 }
800 if (free_until[high_reg] == 0) {
801 return false;
802 }
803 }
804
805 current->SetRegister(reg);
806 if (!current->IsDeadAt(free_until[reg])) {
807 // If the register is only available for a subset of live ranges
808 // covered by `current`, split `current` at the position where
809 // the register is not available anymore.
810 LiveInterval* split = Split(current, free_until[reg]);
811 DCHECK(split != nullptr);
812 AddSorted(unhandled_, split);
813 }
814 return true;
815 }
816
IsBlocked(int reg) const817 bool RegisterAllocator::IsBlocked(int reg) const {
818 return processing_core_registers_
819 ? blocked_core_registers_[reg]
820 : blocked_fp_registers_[reg];
821 }
822
FindAvailableRegisterPair(size_t * next_use,size_t starting_at) const823 int RegisterAllocator::FindAvailableRegisterPair(size_t* next_use, size_t starting_at) const {
824 int reg = kNoRegister;
825 // Pick the register pair that is used the last.
826 for (size_t i = 0; i < number_of_registers_; ++i) {
827 if (IsBlocked(i)) continue;
828 if (!IsLowRegister(i)) continue;
829 int high_register = GetHighForLowRegister(i);
830 if (IsBlocked(high_register)) continue;
831 int existing_high_register = GetHighForLowRegister(reg);
832 if ((reg == kNoRegister) || (next_use[i] >= next_use[reg]
833 && next_use[high_register] >= next_use[existing_high_register])) {
834 reg = i;
835 if (next_use[i] == kMaxLifetimePosition
836 && next_use[high_register] == kMaxLifetimePosition) {
837 break;
838 }
839 } else if (next_use[reg] <= starting_at || next_use[existing_high_register] <= starting_at) {
840 // If one of the current register is known to be unavailable, just unconditionally
841 // try a new one.
842 reg = i;
843 }
844 }
845 return reg;
846 }
847
FindAvailableRegister(size_t * next_use) const848 int RegisterAllocator::FindAvailableRegister(size_t* next_use) const {
849 int reg = kNoRegister;
850 // Pick the register that is used the last.
851 for (size_t i = 0; i < number_of_registers_; ++i) {
852 if (IsBlocked(i)) continue;
853 if (reg == kNoRegister || next_use[i] > next_use[reg]) {
854 reg = i;
855 if (next_use[i] == kMaxLifetimePosition) break;
856 }
857 }
858 return reg;
859 }
860
TrySplitNonPairOrUnalignedPairIntervalAt(size_t position,size_t first_register_use,size_t * next_use)861 bool RegisterAllocator::TrySplitNonPairOrUnalignedPairIntervalAt(size_t position,
862 size_t first_register_use,
863 size_t* next_use) {
864 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
865 LiveInterval* active = active_.Get(i);
866 DCHECK(active->HasRegister());
867 if (active->IsFixed()) continue;
868 if (active->IsHighInterval()) continue;
869 if (first_register_use > next_use[active->GetRegister()]) continue;
870
871 // Split the first interval found.
872 if (!active->IsLowInterval() || IsLowOfUnalignedPairInterval(active)) {
873 LiveInterval* split = Split(active, position);
874 active_.DeleteAt(i);
875 if (split != active) {
876 handled_.Add(active);
877 }
878 AddSorted(unhandled_, split);
879 return true;
880 }
881 }
882 return false;
883 }
884
PotentiallyRemoveOtherHalf(LiveInterval * interval,GrowableArray<LiveInterval * > * intervals,size_t index)885 bool RegisterAllocator::PotentiallyRemoveOtherHalf(LiveInterval* interval,
886 GrowableArray<LiveInterval*>* intervals,
887 size_t index) {
888 if (interval->IsLowInterval()) {
889 DCHECK_EQ(intervals->Get(index), interval->GetHighInterval());
890 intervals->DeleteAt(index);
891 return true;
892 } else if (interval->IsHighInterval()) {
893 DCHECK_GT(index, 0u);
894 DCHECK_EQ(intervals->Get(index - 1), interval->GetLowInterval());
895 intervals->DeleteAt(index - 1);
896 return true;
897 } else {
898 return false;
899 }
900 }
901
902 // Find the register that is used the last, and spill the interval
903 // that holds it. If the first use of `current` is after that register
904 // we spill `current` instead.
AllocateBlockedReg(LiveInterval * current)905 bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
906 size_t first_register_use = current->FirstRegisterUse();
907 if (first_register_use == kNoLifetime) {
908 AllocateSpillSlotFor(current);
909 return false;
910 }
911
912 // We use the first use to compare with other intervals. If this interval
913 // is used after any active intervals, we will spill this interval.
914 size_t first_use = current->FirstUseAfter(current->GetStart());
915
916 // First set all registers as not being used.
917 size_t* next_use = registers_array_;
918 for (size_t i = 0; i < number_of_registers_; ++i) {
919 next_use[i] = kMaxLifetimePosition;
920 }
921
922 // For each active interval, find the next use of its register after the
923 // start of current.
924 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
925 LiveInterval* active = active_.Get(i);
926 DCHECK(active->HasRegister());
927 if (active->IsFixed()) {
928 next_use[active->GetRegister()] = current->GetStart();
929 } else {
930 size_t use = active->FirstUseAfter(current->GetStart());
931 if (use != kNoLifetime) {
932 next_use[active->GetRegister()] = use;
933 }
934 }
935 }
936
937 // For each inactive interval, find the next use of its register after the
938 // start of current.
939 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
940 LiveInterval* inactive = inactive_.Get(i);
941 // Temp/Slow-path-safepoint interval has no holes.
942 DCHECK(!inactive->IsTemp() && !inactive->IsSlowPathSafepoint());
943 if (!current->IsSplit() && !inactive->IsFixed()) {
944 // Neither current nor inactive are fixed.
945 // Thanks to SSA, a non-split interval starting in a hole of an
946 // inactive interval should never intersect with that inactive interval.
947 // Only if it's not fixed though, because fixed intervals don't come from SSA.
948 DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
949 continue;
950 }
951 DCHECK(inactive->HasRegister());
952 size_t next_intersection = inactive->FirstIntersectionWith(current);
953 if (next_intersection != kNoLifetime) {
954 if (inactive->IsFixed()) {
955 next_use[inactive->GetRegister()] =
956 std::min(next_intersection, next_use[inactive->GetRegister()]);
957 } else {
958 size_t use = inactive->FirstUseAfter(current->GetStart());
959 if (use != kNoLifetime) {
960 next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
961 }
962 }
963 }
964 }
965
966 int reg = kNoRegister;
967 bool should_spill = false;
968 if (current->HasRegister()) {
969 DCHECK(current->IsHighInterval());
970 reg = current->GetRegister();
971 // When allocating the low part, we made sure the high register was available.
972 DCHECK_LT(first_use, next_use[reg]);
973 } else if (current->IsLowInterval()) {
974 reg = FindAvailableRegisterPair(next_use, first_register_use);
975 // We should spill if both registers are not available.
976 should_spill = (first_use >= next_use[reg])
977 || (first_use >= next_use[GetHighForLowRegister(reg)]);
978 } else {
979 DCHECK(!current->IsHighInterval());
980 reg = FindAvailableRegister(next_use);
981 should_spill = (first_use >= next_use[reg]);
982 }
983
984 DCHECK_NE(reg, kNoRegister);
985 if (should_spill) {
986 DCHECK(!current->IsHighInterval());
987 bool is_allocation_at_use_site = (current->GetStart() >= (first_register_use - 1));
988 if (current->IsLowInterval()
989 && is_allocation_at_use_site
990 && TrySplitNonPairOrUnalignedPairIntervalAt(current->GetStart(),
991 first_register_use,
992 next_use)) {
993 // If we're allocating a register for `current` because the instruction at
994 // that position requires it, but we think we should spill, then there are
995 // non-pair intervals or unaligned pair intervals blocking the allocation.
996 // We split the first interval found, and put ourselves first in the
997 // `unhandled_` list.
998 LiveInterval* existing = unhandled_->Peek();
999 DCHECK(existing->IsHighInterval());
1000 DCHECK_EQ(existing->GetLowInterval(), current);
1001 unhandled_->Add(current);
1002 } else {
1003 // If the first use of that instruction is after the last use of the found
1004 // register, we split this interval just before its first register use.
1005 AllocateSpillSlotFor(current);
1006 LiveInterval* split = SplitBetween(current, current->GetStart(), first_register_use - 1);
1007 if (current == split) {
1008 DumpInterval(std::cerr, current);
1009 DumpAllIntervals(std::cerr);
1010 // This situation has the potential to infinite loop, so we make it a non-debug CHECK.
1011 HInstruction* at = liveness_.GetInstructionFromPosition(first_register_use / 2);
1012 CHECK(false) << "There is not enough registers available for "
1013 << split->GetParent()->GetDefinedBy()->DebugName() << " "
1014 << split->GetParent()->GetDefinedBy()->GetId()
1015 << " at " << first_register_use - 1 << " "
1016 << (at == nullptr ? "" : at->DebugName());
1017 }
1018 AddSorted(unhandled_, split);
1019 }
1020 return false;
1021 } else {
1022 // Use this register and spill the active and inactives interval that
1023 // have that register.
1024 current->SetRegister(reg);
1025
1026 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
1027 LiveInterval* active = active_.Get(i);
1028 if (active->GetRegister() == reg) {
1029 DCHECK(!active->IsFixed());
1030 LiveInterval* split = Split(active, current->GetStart());
1031 if (split != active) {
1032 handled_.Add(active);
1033 }
1034 active_.DeleteAt(i);
1035 PotentiallyRemoveOtherHalf(active, &active_, i);
1036 AddSorted(unhandled_, split);
1037 break;
1038 }
1039 }
1040
1041 for (size_t i = 0; i < inactive_.Size(); ++i) {
1042 LiveInterval* inactive = inactive_.Get(i);
1043 if (inactive->GetRegister() == reg) {
1044 if (!current->IsSplit() && !inactive->IsFixed()) {
1045 // Neither current nor inactive are fixed.
1046 // Thanks to SSA, a non-split interval starting in a hole of an
1047 // inactive interval should never intersect with that inactive interval.
1048 // Only if it's not fixed though, because fixed intervals don't come from SSA.
1049 DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
1050 continue;
1051 }
1052 size_t next_intersection = inactive->FirstIntersectionWith(current);
1053 if (next_intersection != kNoLifetime) {
1054 if (inactive->IsFixed()) {
1055 LiveInterval* split = Split(current, next_intersection);
1056 DCHECK_NE(split, current);
1057 AddSorted(unhandled_, split);
1058 } else {
1059 // Split at the start of `current`, which will lead to splitting
1060 // at the end of the lifetime hole of `inactive`.
1061 LiveInterval* split = Split(inactive, current->GetStart());
1062 // If it's inactive, it must start before the current interval.
1063 DCHECK_NE(split, inactive);
1064 inactive_.DeleteAt(i);
1065 if (PotentiallyRemoveOtherHalf(inactive, &inactive_, i) && inactive->IsHighInterval()) {
1066 // We have removed an entry prior to `inactive`. So we need to decrement.
1067 --i;
1068 }
1069 // Decrement because we have removed `inactive` from the list.
1070 --i;
1071 handled_.Add(inactive);
1072 AddSorted(unhandled_, split);
1073 }
1074 }
1075 }
1076 }
1077
1078 return true;
1079 }
1080 }
1081
AddSorted(GrowableArray<LiveInterval * > * array,LiveInterval * interval)1082 void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval) {
1083 DCHECK(!interval->IsFixed() && !interval->HasSpillSlot());
1084 size_t insert_at = 0;
1085 for (size_t i = array->Size(); i > 0; --i) {
1086 LiveInterval* current = array->Get(i - 1);
1087 // High intervals must be processed right after their low equivalent.
1088 if (current->StartsAfter(interval) && !current->IsHighInterval()) {
1089 insert_at = i;
1090 break;
1091 } else if ((current->GetStart() == interval->GetStart()) && current->IsSlowPathSafepoint()) {
1092 // Ensure the slow path interval is the last to be processed at its location: we want the
1093 // interval to know all live registers at this location.
1094 DCHECK(i == 1 || array->Get(i - 2)->StartsAfter(current));
1095 insert_at = i;
1096 break;
1097 }
1098 }
1099
1100 array->InsertAt(insert_at, interval);
1101 // Insert the high interval before the low, to ensure the low is processed before.
1102 if (interval->HasHighInterval()) {
1103 array->InsertAt(insert_at, interval->GetHighInterval());
1104 } else if (interval->HasLowInterval()) {
1105 array->InsertAt(insert_at + 1, interval->GetLowInterval());
1106 }
1107 }
1108
SplitBetween(LiveInterval * interval,size_t from,size_t to)1109 LiveInterval* RegisterAllocator::SplitBetween(LiveInterval* interval, size_t from, size_t to) {
1110 HBasicBlock* block_from = liveness_.GetBlockFromPosition(from / 2);
1111 HBasicBlock* block_to = liveness_.GetBlockFromPosition(to / 2);
1112 DCHECK(block_from != nullptr);
1113 DCHECK(block_to != nullptr);
1114
1115 // Both locations are in the same block. We split at the given location.
1116 if (block_from == block_to) {
1117 return Split(interval, to);
1118 }
1119
1120 /*
1121 * Non-linear control flow will force moves at every branch instruction to the new location.
1122 * To avoid having all branches doing the moves, we find the next non-linear position and
1123 * split the interval at this position. Take the following example (block number is the linear
1124 * order position):
1125 *
1126 * B1
1127 * / \
1128 * B2 B3
1129 * \ /
1130 * B4
1131 *
1132 * B2 needs to split an interval, whose next use is in B4. If we were to split at the
1133 * beginning of B4, B3 would need to do a move between B3 and B4 to ensure the interval
1134 * is now in the correct location. It makes performance worst if the interval is spilled
1135 * and both B2 and B3 need to reload it before entering B4.
1136 *
1137 * By splitting at B3, we give a chance to the register allocator to allocate the
1138 * interval to the same register as in B1, and therefore avoid doing any
1139 * moves in B3.
1140 */
1141 if (block_from->GetDominator() != nullptr) {
1142 const GrowableArray<HBasicBlock*>& dominated = block_from->GetDominator()->GetDominatedBlocks();
1143 for (size_t i = 0; i < dominated.Size(); ++i) {
1144 size_t position = dominated.Get(i)->GetLifetimeStart();
1145 if ((position > from) && (block_to->GetLifetimeStart() > position)) {
1146 // Even if we found a better block, we continue iterating in case
1147 // a dominated block is closer.
1148 // Note that dominated blocks are not sorted in liveness order.
1149 block_to = dominated.Get(i);
1150 DCHECK_NE(block_to, block_from);
1151 }
1152 }
1153 }
1154
1155 // If `to` is in a loop, find the outermost loop header which does not contain `from`.
1156 for (HLoopInformationOutwardIterator it(*block_to); !it.Done(); it.Advance()) {
1157 HBasicBlock* header = it.Current()->GetHeader();
1158 if (block_from->GetLifetimeStart() >= header->GetLifetimeStart()) {
1159 break;
1160 }
1161 block_to = header;
1162 }
1163
1164 // Split at the start of the found block, to piggy back on existing moves
1165 // due to resolution if non-linear control flow (see `ConnectSplitSiblings`).
1166 return Split(interval, block_to->GetLifetimeStart());
1167 }
1168
Split(LiveInterval * interval,size_t position)1169 LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
1170 DCHECK_GE(position, interval->GetStart());
1171 DCHECK(!interval->IsDeadAt(position));
1172 if (position == interval->GetStart()) {
1173 // Spill slot will be allocated when handling `interval` again.
1174 interval->ClearRegister();
1175 if (interval->HasHighInterval()) {
1176 interval->GetHighInterval()->ClearRegister();
1177 } else if (interval->HasLowInterval()) {
1178 interval->GetLowInterval()->ClearRegister();
1179 }
1180 return interval;
1181 } else {
1182 LiveInterval* new_interval = interval->SplitAt(position);
1183 if (interval->HasHighInterval()) {
1184 LiveInterval* high = interval->GetHighInterval()->SplitAt(position);
1185 new_interval->SetHighInterval(high);
1186 high->SetLowInterval(new_interval);
1187 } else if (interval->HasLowInterval()) {
1188 LiveInterval* low = interval->GetLowInterval()->SplitAt(position);
1189 new_interval->SetLowInterval(low);
1190 low->SetHighInterval(new_interval);
1191 }
1192 return new_interval;
1193 }
1194 }
1195
AllocateSpillSlotFor(LiveInterval * interval)1196 void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
1197 if (interval->IsHighInterval()) {
1198 // The low interval will contain the spill slot.
1199 return;
1200 }
1201
1202 LiveInterval* parent = interval->GetParent();
1203
1204 // An instruction gets a spill slot for its entire lifetime. If the parent
1205 // of this interval already has a spill slot, there is nothing to do.
1206 if (parent->HasSpillSlot()) {
1207 return;
1208 }
1209
1210 HInstruction* defined_by = parent->GetDefinedBy();
1211 if (defined_by->IsParameterValue()) {
1212 // Parameters have their own stack slot.
1213 parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
1214 return;
1215 }
1216
1217 if (defined_by->IsConstant()) {
1218 // Constants don't need a spill slot.
1219 return;
1220 }
1221
1222 LiveInterval* last_sibling = interval;
1223 while (last_sibling->GetNextSibling() != nullptr) {
1224 last_sibling = last_sibling->GetNextSibling();
1225 }
1226 size_t end = last_sibling->GetEnd();
1227
1228 GrowableArray<size_t>* spill_slots = nullptr;
1229 switch (interval->GetType()) {
1230 case Primitive::kPrimDouble:
1231 spill_slots = &double_spill_slots_;
1232 break;
1233 case Primitive::kPrimLong:
1234 spill_slots = &long_spill_slots_;
1235 break;
1236 case Primitive::kPrimFloat:
1237 spill_slots = &float_spill_slots_;
1238 break;
1239 case Primitive::kPrimNot:
1240 case Primitive::kPrimInt:
1241 case Primitive::kPrimChar:
1242 case Primitive::kPrimByte:
1243 case Primitive::kPrimBoolean:
1244 case Primitive::kPrimShort:
1245 spill_slots = &int_spill_slots_;
1246 break;
1247 case Primitive::kPrimVoid:
1248 LOG(FATAL) << "Unexpected type for interval " << interval->GetType();
1249 }
1250
1251 // Find an available spill slot.
1252 size_t slot = 0;
1253 for (size_t e = spill_slots->Size(); slot < e; ++slot) {
1254 if (spill_slots->Get(slot) <= parent->GetStart()
1255 && (slot == (e - 1) || spill_slots->Get(slot + 1) <= parent->GetStart())) {
1256 break;
1257 }
1258 }
1259
1260 if (parent->NeedsTwoSpillSlots()) {
1261 if (slot == spill_slots->Size()) {
1262 // We need a new spill slot.
1263 spill_slots->Add(end);
1264 spill_slots->Add(end);
1265 } else if (slot == spill_slots->Size() - 1) {
1266 spill_slots->Put(slot, end);
1267 spill_slots->Add(end);
1268 } else {
1269 spill_slots->Put(slot, end);
1270 spill_slots->Put(slot + 1, end);
1271 }
1272 } else {
1273 if (slot == spill_slots->Size()) {
1274 // We need a new spill slot.
1275 spill_slots->Add(end);
1276 } else {
1277 spill_slots->Put(slot, end);
1278 }
1279 }
1280
1281 // Note that the exact spill slot location will be computed when we resolve,
1282 // that is when we know the number of spill slots for each type.
1283 parent->SetSpillSlot(slot);
1284 }
1285
IsValidDestination(Location destination)1286 static bool IsValidDestination(Location destination) {
1287 return destination.IsRegister()
1288 || destination.IsRegisterPair()
1289 || destination.IsFpuRegister()
1290 || destination.IsFpuRegisterPair()
1291 || destination.IsStackSlot()
1292 || destination.IsDoubleStackSlot();
1293 }
1294
AddMove(HParallelMove * move,Location source,Location destination,HInstruction * instruction,Primitive::Type type) const1295 void RegisterAllocator::AddMove(HParallelMove* move,
1296 Location source,
1297 Location destination,
1298 HInstruction* instruction,
1299 Primitive::Type type) const {
1300 if (type == Primitive::kPrimLong
1301 && codegen_->ShouldSplitLongMoves()
1302 // The parallel move resolver knows how to deal with long constants.
1303 && !source.IsConstant()) {
1304 move->AddMove(source.ToLow(), destination.ToLow(), Primitive::kPrimInt, instruction);
1305 move->AddMove(source.ToHigh(), destination.ToHigh(), Primitive::kPrimInt, nullptr);
1306 } else {
1307 move->AddMove(source, destination, type, instruction);
1308 }
1309 }
1310
AddInputMoveFor(HInstruction * input,HInstruction * user,Location source,Location destination) const1311 void RegisterAllocator::AddInputMoveFor(HInstruction* input,
1312 HInstruction* user,
1313 Location source,
1314 Location destination) const {
1315 if (source.Equals(destination)) return;
1316
1317 DCHECK(!user->IsPhi());
1318
1319 HInstruction* previous = user->GetPrevious();
1320 HParallelMove* move = nullptr;
1321 if (previous == nullptr
1322 || !previous->IsParallelMove()
1323 || previous->GetLifetimePosition() < user->GetLifetimePosition()) {
1324 move = new (allocator_) HParallelMove(allocator_);
1325 move->SetLifetimePosition(user->GetLifetimePosition());
1326 user->GetBlock()->InsertInstructionBefore(move, user);
1327 } else {
1328 move = previous->AsParallelMove();
1329 }
1330 DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition());
1331 AddMove(move, source, destination, nullptr, input->GetType());
1332 }
1333
IsInstructionStart(size_t position)1334 static bool IsInstructionStart(size_t position) {
1335 return (position & 1) == 0;
1336 }
1337
IsInstructionEnd(size_t position)1338 static bool IsInstructionEnd(size_t position) {
1339 return (position & 1) == 1;
1340 }
1341
InsertParallelMoveAt(size_t position,HInstruction * instruction,Location source,Location destination) const1342 void RegisterAllocator::InsertParallelMoveAt(size_t position,
1343 HInstruction* instruction,
1344 Location source,
1345 Location destination) const {
1346 DCHECK(IsValidDestination(destination)) << destination;
1347 if (source.Equals(destination)) return;
1348
1349 HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
1350 HParallelMove* move;
1351 if (at == nullptr) {
1352 if (IsInstructionStart(position)) {
1353 // Block boundary, don't do anything the connection of split siblings will handle it.
1354 return;
1355 } else {
1356 // Move must happen before the first instruction of the block.
1357 at = liveness_.GetInstructionFromPosition((position + 1) / 2);
1358 // Note that parallel moves may have already been inserted, so we explicitly
1359 // ask for the first instruction of the block: `GetInstructionFromPosition` does
1360 // not contain the `HParallelMove` instructions.
1361 at = at->GetBlock()->GetFirstInstruction();
1362
1363 if (at->GetLifetimePosition() < position) {
1364 // We may insert moves for split siblings and phi spills at the beginning of the block.
1365 // Since this is a different lifetime position, we need to go to the next instruction.
1366 DCHECK(at->IsParallelMove());
1367 at = at->GetNext();
1368 }
1369
1370 if (at->GetLifetimePosition() != position) {
1371 DCHECK_GT(at->GetLifetimePosition(), position);
1372 move = new (allocator_) HParallelMove(allocator_);
1373 move->SetLifetimePosition(position);
1374 at->GetBlock()->InsertInstructionBefore(move, at);
1375 } else {
1376 DCHECK(at->IsParallelMove());
1377 move = at->AsParallelMove();
1378 }
1379 }
1380 } else if (IsInstructionEnd(position)) {
1381 // Move must happen after the instruction.
1382 DCHECK(!at->IsControlFlow());
1383 move = at->GetNext()->AsParallelMove();
1384 // This is a parallel move for connecting siblings in a same block. We need to
1385 // differentiate it with moves for connecting blocks, and input moves.
1386 if (move == nullptr || move->GetLifetimePosition() > position) {
1387 move = new (allocator_) HParallelMove(allocator_);
1388 move->SetLifetimePosition(position);
1389 at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
1390 }
1391 } else {
1392 // Move must happen before the instruction.
1393 HInstruction* previous = at->GetPrevious();
1394 if (previous == nullptr
1395 || !previous->IsParallelMove()
1396 || previous->GetLifetimePosition() != position) {
1397 // If the previous is a parallel move, then its position must be lower
1398 // than the given `position`: it was added just after the non-parallel
1399 // move instruction that precedes `instruction`.
1400 DCHECK(previous == nullptr
1401 || !previous->IsParallelMove()
1402 || previous->GetLifetimePosition() < position);
1403 move = new (allocator_) HParallelMove(allocator_);
1404 move->SetLifetimePosition(position);
1405 at->GetBlock()->InsertInstructionBefore(move, at);
1406 } else {
1407 move = previous->AsParallelMove();
1408 }
1409 }
1410 DCHECK_EQ(move->GetLifetimePosition(), position);
1411 AddMove(move, source, destination, instruction, instruction->GetType());
1412 }
1413
InsertParallelMoveAtExitOf(HBasicBlock * block,HInstruction * instruction,Location source,Location destination) const1414 void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
1415 HInstruction* instruction,
1416 Location source,
1417 Location destination) const {
1418 DCHECK(IsValidDestination(destination)) << destination;
1419 if (source.Equals(destination)) return;
1420
1421 DCHECK_EQ(block->GetSuccessors().Size(), 1u);
1422 HInstruction* last = block->GetLastInstruction();
1423 // We insert moves at exit for phi predecessors and connecting blocks.
1424 // A block ending with an if cannot branch to a block with phis because
1425 // we do not allow critical edges. It can also not connect
1426 // a split interval between two blocks: the move has to happen in the successor.
1427 DCHECK(!last->IsIf());
1428 HInstruction* previous = last->GetPrevious();
1429 HParallelMove* move;
1430 // This is a parallel move for connecting blocks. We need to differentiate
1431 // it with moves for connecting siblings in a same block, and output moves.
1432 size_t position = last->GetLifetimePosition();
1433 if (previous == nullptr || !previous->IsParallelMove()
1434 || previous->AsParallelMove()->GetLifetimePosition() != position) {
1435 move = new (allocator_) HParallelMove(allocator_);
1436 move->SetLifetimePosition(position);
1437 block->InsertInstructionBefore(move, last);
1438 } else {
1439 move = previous->AsParallelMove();
1440 }
1441 AddMove(move, source, destination, instruction, instruction->GetType());
1442 }
1443
InsertParallelMoveAtEntryOf(HBasicBlock * block,HInstruction * instruction,Location source,Location destination) const1444 void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
1445 HInstruction* instruction,
1446 Location source,
1447 Location destination) const {
1448 DCHECK(IsValidDestination(destination)) << destination;
1449 if (source.Equals(destination)) return;
1450
1451 HInstruction* first = block->GetFirstInstruction();
1452 HParallelMove* move = first->AsParallelMove();
1453 size_t position = block->GetLifetimeStart();
1454 // This is a parallel move for connecting blocks. We need to differentiate
1455 // it with moves for connecting siblings in a same block, and input moves.
1456 if (move == nullptr || move->GetLifetimePosition() != position) {
1457 move = new (allocator_) HParallelMove(allocator_);
1458 move->SetLifetimePosition(position);
1459 block->InsertInstructionBefore(move, first);
1460 }
1461 AddMove(move, source, destination, instruction, instruction->GetType());
1462 }
1463
InsertMoveAfter(HInstruction * instruction,Location source,Location destination) const1464 void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
1465 Location source,
1466 Location destination) const {
1467 DCHECK(IsValidDestination(destination)) << destination;
1468 if (source.Equals(destination)) return;
1469
1470 if (instruction->IsPhi()) {
1471 InsertParallelMoveAtEntryOf(instruction->GetBlock(), instruction, source, destination);
1472 return;
1473 }
1474
1475 size_t position = instruction->GetLifetimePosition() + 1;
1476 HParallelMove* move = instruction->GetNext()->AsParallelMove();
1477 // This is a parallel move for moving the output of an instruction. We need
1478 // to differentiate with input moves, moves for connecting siblings in a
1479 // and moves for connecting blocks.
1480 if (move == nullptr || move->GetLifetimePosition() != position) {
1481 move = new (allocator_) HParallelMove(allocator_);
1482 move->SetLifetimePosition(position);
1483 instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
1484 }
1485 AddMove(move, source, destination, instruction, instruction->GetType());
1486 }
1487
ConnectSiblings(LiveInterval * interval)1488 void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
1489 LiveInterval* current = interval;
1490 if (current->HasSpillSlot() && current->HasRegister()) {
1491 // We spill eagerly, so move must be at definition.
1492 InsertMoveAfter(interval->GetDefinedBy(),
1493 interval->ToLocation(),
1494 interval->NeedsTwoSpillSlots()
1495 ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
1496 : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
1497 }
1498 UsePosition* use = current->GetFirstUse();
1499 UsePosition* env_use = current->GetFirstEnvironmentUse();
1500
1501 // Walk over all siblings, updating locations of use positions, and
1502 // connecting them when they are adjacent.
1503 do {
1504 Location source = current->ToLocation();
1505
1506 // Walk over all uses covered by this interval, and update the location
1507 // information.
1508
1509 LiveRange* range = current->GetFirstRange();
1510 while (range != nullptr) {
1511 while (use != nullptr && use->GetPosition() < range->GetStart()) {
1512 DCHECK(use->IsSynthesized());
1513 use = use->GetNext();
1514 }
1515 while (use != nullptr && use->GetPosition() <= range->GetEnd()) {
1516 DCHECK(!use->GetIsEnvironment());
1517 DCHECK(current->CoversSlow(use->GetPosition()) || (use->GetPosition() == range->GetEnd()));
1518 if (!use->IsSynthesized()) {
1519 LocationSummary* locations = use->GetUser()->GetLocations();
1520 Location expected_location = locations->InAt(use->GetInputIndex());
1521 // The expected (actual) location may be invalid in case the input is unused. Currently
1522 // this only happens for intrinsics.
1523 if (expected_location.IsValid()) {
1524 if (expected_location.IsUnallocated()) {
1525 locations->SetInAt(use->GetInputIndex(), source);
1526 } else if (!expected_location.IsConstant()) {
1527 AddInputMoveFor(interval->GetDefinedBy(), use->GetUser(), source, expected_location);
1528 }
1529 } else {
1530 DCHECK(use->GetUser()->IsInvoke());
1531 DCHECK(use->GetUser()->AsInvoke()->GetIntrinsic() != Intrinsics::kNone);
1532 }
1533 }
1534 use = use->GetNext();
1535 }
1536
1537 // Walk over the environment uses, and update their locations.
1538 while (env_use != nullptr && env_use->GetPosition() < range->GetStart()) {
1539 env_use = env_use->GetNext();
1540 }
1541
1542 while (env_use != nullptr && env_use->GetPosition() <= range->GetEnd()) {
1543 DCHECK(current->CoversSlow(env_use->GetPosition())
1544 || (env_use->GetPosition() == range->GetEnd()));
1545 HEnvironment* environment = env_use->GetUser()->GetEnvironment();
1546 environment->SetLocationAt(env_use->GetInputIndex(), source);
1547 env_use = env_use->GetNext();
1548 }
1549
1550 range = range->GetNext();
1551 }
1552
1553 // If the next interval starts just after this one, and has a register,
1554 // insert a move.
1555 LiveInterval* next_sibling = current->GetNextSibling();
1556 if (next_sibling != nullptr
1557 && next_sibling->HasRegister()
1558 && current->GetEnd() == next_sibling->GetStart()) {
1559 Location destination = next_sibling->ToLocation();
1560 InsertParallelMoveAt(current->GetEnd(), interval->GetDefinedBy(), source, destination);
1561 }
1562
1563 for (SafepointPosition* safepoint_position = current->GetFirstSafepoint();
1564 safepoint_position != nullptr;
1565 safepoint_position = safepoint_position->GetNext()) {
1566 DCHECK(current->CoversSlow(safepoint_position->GetPosition()));
1567
1568 LocationSummary* locations = safepoint_position->GetLocations();
1569 if ((current->GetType() == Primitive::kPrimNot) && current->GetParent()->HasSpillSlot()) {
1570 locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
1571 }
1572
1573 switch (source.GetKind()) {
1574 case Location::kRegister: {
1575 locations->AddLiveRegister(source);
1576 if (kIsDebugBuild && locations->OnlyCallsOnSlowPath()) {
1577 DCHECK_LE(locations->GetNumberOfLiveRegisters(),
1578 maximum_number_of_live_core_registers_ +
1579 maximum_number_of_live_fp_registers_);
1580 }
1581 if (current->GetType() == Primitive::kPrimNot) {
1582 locations->SetRegisterBit(source.reg());
1583 }
1584 break;
1585 }
1586 case Location::kFpuRegister: {
1587 locations->AddLiveRegister(source);
1588 break;
1589 }
1590
1591 case Location::kRegisterPair:
1592 case Location::kFpuRegisterPair: {
1593 locations->AddLiveRegister(source.ToLow());
1594 locations->AddLiveRegister(source.ToHigh());
1595 break;
1596 }
1597 case Location::kStackSlot: // Fall-through
1598 case Location::kDoubleStackSlot: // Fall-through
1599 case Location::kConstant: {
1600 // Nothing to do.
1601 break;
1602 }
1603 default: {
1604 LOG(FATAL) << "Unexpected location for object";
1605 }
1606 }
1607 }
1608 current = next_sibling;
1609 } while (current != nullptr);
1610
1611 if (kIsDebugBuild) {
1612 // Following uses can only be synthesized uses.
1613 while (use != nullptr) {
1614 DCHECK(use->IsSynthesized());
1615 use = use->GetNext();
1616 }
1617 }
1618 }
1619
ConnectSplitSiblings(LiveInterval * interval,HBasicBlock * from,HBasicBlock * to) const1620 void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
1621 HBasicBlock* from,
1622 HBasicBlock* to) const {
1623 if (interval->GetNextSibling() == nullptr) {
1624 // Nothing to connect. The whole range was allocated to the same location.
1625 return;
1626 }
1627
1628 // Find the intervals that cover `from` and `to`.
1629 LiveInterval* destination = interval->GetSiblingAt(to->GetLifetimeStart());
1630 LiveInterval* source = interval->GetSiblingAt(from->GetLifetimeEnd() - 1);
1631
1632 if (destination == source) {
1633 // Interval was not split.
1634 return;
1635 }
1636 DCHECK(destination != nullptr && source != nullptr);
1637
1638 if (!destination->HasRegister()) {
1639 // Values are eagerly spilled. Spill slot already contains appropriate value.
1640 return;
1641 }
1642
1643 // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
1644 // we need to put the moves at the entry of `to`.
1645 if (from->GetSuccessors().Size() == 1) {
1646 InsertParallelMoveAtExitOf(from,
1647 interval->GetParent()->GetDefinedBy(),
1648 source->ToLocation(),
1649 destination->ToLocation());
1650 } else {
1651 DCHECK_EQ(to->GetPredecessors().Size(), 1u);
1652 InsertParallelMoveAtEntryOf(to,
1653 interval->GetParent()->GetDefinedBy(),
1654 source->ToLocation(),
1655 destination->ToLocation());
1656 }
1657 }
1658
Resolve()1659 void RegisterAllocator::Resolve() {
1660 codegen_->InitializeCodeGeneration(GetNumberOfSpillSlots(),
1661 maximum_number_of_live_core_registers_,
1662 maximum_number_of_live_fp_registers_,
1663 reserved_out_slots_,
1664 codegen_->GetGraph()->GetLinearOrder());
1665
1666 // Adjust the Out Location of instructions.
1667 // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
1668 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1669 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1670 LiveInterval* current = instruction->GetLiveInterval();
1671 LocationSummary* locations = instruction->GetLocations();
1672 Location location = locations->Out();
1673 if (instruction->IsParameterValue()) {
1674 // Now that we know the frame size, adjust the parameter's location.
1675 if (location.IsStackSlot()) {
1676 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1677 current->SetSpillSlot(location.GetStackIndex());
1678 locations->UpdateOut(location);
1679 } else if (location.IsDoubleStackSlot()) {
1680 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1681 current->SetSpillSlot(location.GetStackIndex());
1682 locations->UpdateOut(location);
1683 } else if (current->HasSpillSlot()) {
1684 current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
1685 }
1686 } else if (current->HasSpillSlot()) {
1687 // Adjust the stack slot, now that we know the number of them for each type.
1688 // The way this implementation lays out the stack is the following:
1689 // [parameter slots ]
1690 // [double spill slots ]
1691 // [long spill slots ]
1692 // [float spill slots ]
1693 // [int/ref values ]
1694 // [maximum out values ] (number of arguments for calls)
1695 // [art method ].
1696 uint32_t slot = current->GetSpillSlot();
1697 switch (current->GetType()) {
1698 case Primitive::kPrimDouble:
1699 slot += long_spill_slots_.Size();
1700 FALLTHROUGH_INTENDED;
1701 case Primitive::kPrimLong:
1702 slot += float_spill_slots_.Size();
1703 FALLTHROUGH_INTENDED;
1704 case Primitive::kPrimFloat:
1705 slot += int_spill_slots_.Size();
1706 FALLTHROUGH_INTENDED;
1707 case Primitive::kPrimNot:
1708 case Primitive::kPrimInt:
1709 case Primitive::kPrimChar:
1710 case Primitive::kPrimByte:
1711 case Primitive::kPrimBoolean:
1712 case Primitive::kPrimShort:
1713 slot += reserved_out_slots_;
1714 break;
1715 case Primitive::kPrimVoid:
1716 LOG(FATAL) << "Unexpected type for interval " << current->GetType();
1717 }
1718 current->SetSpillSlot(slot * kVRegSize);
1719 }
1720
1721 Location source = current->ToLocation();
1722
1723 if (location.IsUnallocated()) {
1724 if (location.GetPolicy() == Location::kSameAsFirstInput) {
1725 if (locations->InAt(0).IsUnallocated()) {
1726 locations->SetInAt(0, source);
1727 } else {
1728 DCHECK(locations->InAt(0).Equals(source));
1729 }
1730 }
1731 locations->UpdateOut(source);
1732 } else {
1733 DCHECK(source.Equals(location));
1734 }
1735 }
1736
1737 // Connect siblings.
1738 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1739 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1740 ConnectSiblings(instruction->GetLiveInterval());
1741 }
1742
1743 // Resolve non-linear control flow across branches. Order does not matter.
1744 for (HLinearOrderIterator it(*codegen_->GetGraph()); !it.Done(); it.Advance()) {
1745 HBasicBlock* block = it.Current();
1746 BitVector* live = liveness_.GetLiveInSet(*block);
1747 for (uint32_t idx : live->Indexes()) {
1748 HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
1749 LiveInterval* interval = current->GetLiveInterval();
1750 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
1751 ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
1752 }
1753 }
1754 }
1755
1756 // Resolve phi inputs. Order does not matter.
1757 for (HLinearOrderIterator it(*codegen_->GetGraph()); !it.Done(); it.Advance()) {
1758 HBasicBlock* current = it.Current();
1759 for (HInstructionIterator inst_it(current->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
1760 HInstruction* phi = inst_it.Current();
1761 for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
1762 HBasicBlock* predecessor = current->GetPredecessors().Get(i);
1763 DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
1764 HInstruction* input = phi->InputAt(i);
1765 Location source = input->GetLiveInterval()->GetLocationAt(
1766 predecessor->GetLifetimeEnd() - 1);
1767 Location destination = phi->GetLiveInterval()->ToLocation();
1768 InsertParallelMoveAtExitOf(predecessor, phi, source, destination);
1769 }
1770 }
1771 }
1772
1773 // Assign temp locations.
1774 for (size_t i = 0; i < temp_intervals_.Size(); ++i) {
1775 LiveInterval* temp = temp_intervals_.Get(i);
1776 if (temp->IsHighInterval()) {
1777 // High intervals can be skipped, they are already handled by the low interval.
1778 continue;
1779 }
1780 HInstruction* at = liveness_.GetTempUser(temp);
1781 size_t temp_index = liveness_.GetTempIndex(temp);
1782 LocationSummary* locations = at->GetLocations();
1783 switch (temp->GetType()) {
1784 case Primitive::kPrimInt:
1785 locations->SetTempAt(temp_index, Location::RegisterLocation(temp->GetRegister()));
1786 break;
1787
1788 case Primitive::kPrimDouble:
1789 if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
1790 Location location = Location::FpuRegisterPairLocation(
1791 temp->GetRegister(), temp->GetHighInterval()->GetRegister());
1792 locations->SetTempAt(temp_index, location);
1793 } else {
1794 locations->SetTempAt(temp_index, Location::FpuRegisterLocation(temp->GetRegister()));
1795 }
1796 break;
1797
1798 default:
1799 LOG(FATAL) << "Unexpected type for temporary location "
1800 << temp->GetType();
1801 }
1802 }
1803 }
1804
1805 } // namespace art
1806