blob: 4b45f43016aeab8c97e6b4dc630fe9b14fce49e5 [file] [log] [blame]
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "register_allocator.h"
18
Ian Rogerse77493c2014-08-20 15:08:45 -070019#include "base/bit_vector-inl.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010020#include "code_generator.h"
21#include "ssa_liveness_analysis.h"
22
23namespace art {
24
25static constexpr size_t kMaxLifetimePosition = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010026static constexpr size_t kDefaultNumberOfSpillSlots = 4;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010027
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010028RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
29 CodeGenerator* codegen,
30 const SsaLivenessAnalysis& liveness)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010031 : allocator_(allocator),
32 codegen_(codegen),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010033 liveness_(liveness),
Nicolas Geoffray39468442014-09-02 15:17:15 +010034 unhandled_core_intervals_(allocator, 0),
35 unhandled_fp_intervals_(allocator, 0),
36 unhandled_(nullptr),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010037 handled_(allocator, 0),
38 active_(allocator, 0),
39 inactive_(allocator, 0),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010040 physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
Nicolas Geoffray39468442014-09-02 15:17:15 +010041 temp_intervals_(allocator, 4),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010042 spill_slots_(allocator, kDefaultNumberOfSpillSlots),
Nicolas Geoffray39468442014-09-02 15:17:15 +010043 safepoints_(allocator, 0),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010044 processing_core_registers_(false),
45 number_of_registers_(-1),
46 registers_array_(nullptr),
Nicolas Geoffray39468442014-09-02 15:17:15 +010047 blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())),
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +010048 reserved_out_slots_(0),
49 maximum_number_of_live_registers_(0) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010050 codegen->SetupBlockedRegisters(blocked_registers_);
51 physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
Nicolas Geoffray39468442014-09-02 15:17:15 +010052 // Always reserve for the current method and the graph's max out registers.
53 // TODO: compute it instead.
54 reserved_out_slots_ = 1 + codegen->GetGraph()->GetMaximumNumberOfOutVRegs();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010055}
56
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010057bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
58 InstructionSet instruction_set) {
59 if (!Supports(instruction_set)) {
60 return false;
61 }
62 for (size_t i = 0, e = graph.GetBlocks().Size(); i < e; ++i) {
63 for (HInstructionIterator it(graph.GetBlocks().Get(i)->GetInstructions());
64 !it.Done();
65 it.Advance()) {
66 HInstruction* current = it.Current();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +010067 if (current->GetType() == Primitive::kPrimLong && instruction_set != kX86_64) return false;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010068 if (current->GetType() == Primitive::kPrimFloat) return false;
69 if (current->GetType() == Primitive::kPrimDouble) return false;
70 }
71 }
72 return true;
73}
74
75static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 if (interval == nullptr) return false;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010077 bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
78 && (interval->GetType() != Primitive::kPrimFloat);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010079 return processing_core_registers == is_core_register;
80}
81
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010082void RegisterAllocator::AllocateRegisters() {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010083 AllocateRegistersInternal();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010084 Resolve();
85
86 if (kIsDebugBuild) {
87 processing_core_registers_ = true;
88 ValidateInternal(true);
89 processing_core_registers_ = false;
90 ValidateInternal(true);
91 }
92}
93
94void RegisterAllocator::BlockRegister(Location location,
95 size_t start,
96 size_t end,
97 Primitive::Type type) {
98 int reg = location.reg().RegId();
99 LiveInterval* interval = physical_register_intervals_.Get(reg);
100 if (interval == nullptr) {
101 interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
102 physical_register_intervals_.Put(reg, interval);
103 inactive_.Add(interval);
104 }
105 DCHECK(interval->GetRegister() == reg);
106 interval->AddRange(start, end);
107}
108
109void RegisterAllocator::AllocateRegistersInternal() {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100110 // Iterate post-order, to ensure the list is sorted, and the last added interval
111 // is the one with the lowest start position.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100112 for (HLinearPostOrderIterator it(liveness_); !it.Done(); it.Advance()) {
113 HBasicBlock* block = it.Current();
114 for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
115 ProcessInstruction(it.Current());
116 }
117 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
118 ProcessInstruction(it.Current());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100119 }
120 }
121
Nicolas Geoffray39468442014-09-02 15:17:15 +0100122 number_of_registers_ = codegen_->GetNumberOfCoreRegisters();
123 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
124 processing_core_registers_ = true;
125 unhandled_ = &unhandled_core_intervals_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100126 LinearScan();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100127
128 inactive_.Reset();
129 active_.Reset();
130 handled_.Reset();
131
132 number_of_registers_ = codegen_->GetNumberOfFloatingPointRegisters();
133 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
134 processing_core_registers_ = false;
135 unhandled_ = &unhandled_fp_intervals_;
136 // TODO: Enable FP register allocation.
137 DCHECK(unhandled_->IsEmpty());
138 LinearScan();
139}
140
141void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
142 LocationSummary* locations = instruction->GetLocations();
143 size_t position = instruction->GetLifetimePosition();
144
145 if (locations == nullptr) return;
146
147 // Create synthesized intervals for temporaries.
148 for (size_t i = 0; i < locations->GetTempCount(); ++i) {
149 Location temp = locations->GetTemp(i);
150 if (temp.IsRegister()) {
151 BlockRegister(temp, position, position + 1, Primitive::kPrimInt);
152 } else {
153 LiveInterval* interval =
154 LiveInterval::MakeTempInterval(allocator_, instruction, Primitive::kPrimInt);
155 temp_intervals_.Add(interval);
156 interval->AddRange(position, position + 1);
157 unhandled_core_intervals_.Add(interval);
158 }
159 }
160
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100161 bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
162 && (instruction->GetType() != Primitive::kPrimFloat);
163
164 GrowableArray<LiveInterval*>& unhandled = core_register
165 ? unhandled_core_intervals_
166 : unhandled_fp_intervals_;
167
Nicolas Geoffray39468442014-09-02 15:17:15 +0100168 if (locations->CanCall()) {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100169 if (!instruction->IsSuspendCheck()) {
170 codegen_->MarkNotLeaf();
171 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100172 safepoints_.Add(instruction);
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100173 if (locations->OnlyCallsOnSlowPath()) {
174 // We add a synthesized range at this position to record the live registers
175 // at this position. Ideally, we could just update the safepoints when locations
176 // are updated, but we currently need to know the full stack size before updating
177 // locations (because of parameters and the fact that we don't have a frame pointer).
178 // And knowing the full stack size requires to know the maximum number of live
179 // registers at calls in slow paths.
180 // By adding the following interval in the algorithm, we can compute this
181 // maximum before updating locations.
182 LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
183 interval->AddRange(position, position + 1);
184 unhandled.Add(interval);
185 }
186 }
187
188 if (locations->WillCall()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100189 // Block all registers.
190 for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
191 BlockRegister(Location::RegisterLocation(ManagedRegister(i)),
192 position,
193 position + 1,
194 Primitive::kPrimInt);
195 }
196 }
197
198 for (size_t i = 0; i < instruction->InputCount(); ++i) {
199 Location input = locations->InAt(i);
200 if (input.IsRegister()) {
201 BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
202 }
203 }
204
Nicolas Geoffray39468442014-09-02 15:17:15 +0100205 LiveInterval* current = instruction->GetLiveInterval();
206 if (current == nullptr) return;
207
Nicolas Geoffray76905622014-09-25 14:39:26 +0100208 DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100209 // Some instructions define their output in fixed register/stack slot. We need
210 // to ensure we know these locations before doing register allocation. For a
211 // given register, we create an interval that covers these locations. The register
212 // will be unavailable at these locations when trying to allocate one for an
213 // interval.
214 //
215 // The backwards walking ensures the ranges are ordered on increasing start positions.
216 Location output = locations->Out();
217 if (output.IsRegister()) {
218 // Shift the interval's start by one to account for the blocked register.
219 current->SetFrom(position + 1);
220 current->SetRegister(output.reg().RegId());
221 BlockRegister(output, position, position + 1, instruction->GetType());
222 } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
223 current->SetSpillSlot(output.GetStackIndex());
224 }
225
226 // If needed, add interval to the list of unhandled intervals.
227 if (current->HasSpillSlot() || instruction->IsConstant()) {
228 // Split before first register use.
229 size_t first_register_use = current->FirstRegisterUse();
230 if (first_register_use != kNoLifetime) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100231 LiveInterval* split = Split(current, first_register_use);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100232 // Don't add direclty to `unhandled`, it needs to be sorted and the start
233 // of this new interval might be after intervals already in the list.
234 AddSorted(&unhandled, split);
235 } else {
236 // Nothing to do, we won't allocate a register for this value.
237 }
238 } else {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100239 DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100240 unhandled.Add(current);
241 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100242}
243
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100244class AllRangesIterator : public ValueObject {
245 public:
246 explicit AllRangesIterator(LiveInterval* interval)
247 : current_interval_(interval),
248 current_range_(interval->GetFirstRange()) {}
249
250 bool Done() const { return current_interval_ == nullptr; }
251 LiveRange* CurrentRange() const { return current_range_; }
252 LiveInterval* CurrentInterval() const { return current_interval_; }
253
254 void Advance() {
255 current_range_ = current_range_->GetNext();
256 if (current_range_ == nullptr) {
257 current_interval_ = current_interval_->GetNextSibling();
258 if (current_interval_ != nullptr) {
259 current_range_ = current_interval_->GetFirstRange();
260 }
261 }
262 }
263
264 private:
265 LiveInterval* current_interval_;
266 LiveRange* current_range_;
267
268 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
269};
270
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100271bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
272 // To simplify unit testing, we eagerly create the array of intervals, and
273 // call the helper method.
274 GrowableArray<LiveInterval*> intervals(allocator_, 0);
275 for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
276 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
277 if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
278 intervals.Add(instruction->GetLiveInterval());
279 }
280 }
281
282 for (size_t i = 0, e = physical_register_intervals_.Size(); i < e; ++i) {
283 LiveInterval* fixed = physical_register_intervals_.Get(i);
284 if (fixed != nullptr && ShouldProcess(processing_core_registers_, fixed)) {
285 intervals.Add(fixed);
286 }
287 }
288
Nicolas Geoffray39468442014-09-02 15:17:15 +0100289 for (size_t i = 0, e = temp_intervals_.Size(); i < e; ++i) {
290 LiveInterval* temp = temp_intervals_.Get(i);
291 if (ShouldProcess(processing_core_registers_, temp)) {
292 intervals.Add(temp);
293 }
294 }
295
296 return ValidateIntervals(intervals, spill_slots_.Size(), reserved_out_slots_, *codegen_,
297 allocator_, processing_core_registers_, log_fatal_on_failure);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100298}
299
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100300bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
301 size_t number_of_spill_slots,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100302 size_t number_of_out_slots,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100303 const CodeGenerator& codegen,
304 ArenaAllocator* allocator,
305 bool processing_core_registers,
306 bool log_fatal_on_failure) {
307 size_t number_of_registers = processing_core_registers
308 ? codegen.GetNumberOfCoreRegisters()
309 : codegen.GetNumberOfFloatingPointRegisters();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100310 GrowableArray<ArenaBitVector*> liveness_of_values(
311 allocator, number_of_registers + number_of_spill_slots);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100312
313 // Allocate a bit vector per register. A live interval that has a register
314 // allocated will populate the associated bit vector based on its live ranges.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100315 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
316 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100317 }
318
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100319 for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
320 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
321 LiveInterval* current = it.CurrentInterval();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100322 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
323 if (current->GetParent()->HasSpillSlot()
324 // Parameters have their own stack slot.
325 && !(defined_by != nullptr && defined_by->IsParameterValue())) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100326 BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers
327 + current->GetParent()->GetSpillSlot() / kVRegSize
328 - number_of_out_slots);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100329 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
330 if (liveness_of_spill_slot->IsBitSet(j)) {
331 if (log_fatal_on_failure) {
332 std::ostringstream message;
333 message << "Spill slot conflict at " << j;
334 LOG(FATAL) << message.str();
335 } else {
336 return false;
337 }
338 } else {
339 liveness_of_spill_slot->SetBit(j);
340 }
341 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100342 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100343
344 if (current->HasRegister()) {
345 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
346 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
347 if (liveness_of_register->IsBitSet(j)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100348 if (log_fatal_on_failure) {
349 std::ostringstream message;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100350 message << "Register conflict at " << j << " ";
351 if (defined_by != nullptr) {
352 message << "(" << defined_by->DebugName() << ")";
353 }
354 message << "for ";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100355 if (processing_core_registers) {
356 codegen.DumpCoreRegister(message, current->GetRegister());
357 } else {
358 codegen.DumpFloatingPointRegister(message, current->GetRegister());
359 }
360 LOG(FATAL) << message.str();
361 } else {
362 return false;
363 }
364 } else {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100365 liveness_of_register->SetBit(j);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100366 }
367 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100368 }
369 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100370 }
371 return true;
372}
373
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100374void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100375 interval->Dump(stream);
376 stream << ": ";
377 if (interval->HasRegister()) {
378 if (processing_core_registers_) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100379 codegen_->DumpCoreRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100380 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100381 codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100382 }
383 } else {
384 stream << "spilled";
385 }
386 stream << std::endl;
387}
388
389// By the book implementation of a linear scan register allocator.
390void RegisterAllocator::LinearScan() {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100391 while (!unhandled_->IsEmpty()) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100392 // (1) Remove interval with the lowest start position from unhandled.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100393 LiveInterval* current = unhandled_->Pop();
394 DCHECK(!current->IsFixed() && !current->HasSpillSlot());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100395 size_t position = current->GetStart();
396
397 // (2) Remove currently active intervals that are dead at this position.
398 // Move active intervals that have a lifetime hole at this position
399 // to inactive.
400 for (size_t i = 0; i < active_.Size(); ++i) {
401 LiveInterval* interval = active_.Get(i);
402 if (interval->IsDeadAt(position)) {
403 active_.Delete(interval);
404 --i;
405 handled_.Add(interval);
406 } else if (!interval->Covers(position)) {
407 active_.Delete(interval);
408 --i;
409 inactive_.Add(interval);
410 }
411 }
412
413 // (3) Remove currently inactive intervals that are dead at this position.
414 // Move inactive intervals that cover this position to active.
415 for (size_t i = 0; i < inactive_.Size(); ++i) {
416 LiveInterval* interval = inactive_.Get(i);
417 if (interval->IsDeadAt(position)) {
418 inactive_.Delete(interval);
419 --i;
420 handled_.Add(interval);
421 } else if (interval->Covers(position)) {
422 inactive_.Delete(interval);
423 --i;
424 active_.Add(interval);
425 }
426 }
427
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100428 if (current->IsSlowPathSafepoint()) {
429 // Synthesized interval to record the maximum number of live registers
430 // at safepoints. No need to allocate a register for it.
431 maximum_number_of_live_registers_ =
432 std::max(maximum_number_of_live_registers_, active_.Size());
433 continue;
434 }
435
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100436 // (4) Try to find an available register.
437 bool success = TryAllocateFreeReg(current);
438
439 // (5) If no register could be found, we need to spill.
440 if (!success) {
441 success = AllocateBlockedReg(current);
442 }
443
444 // (6) If the interval had a register allocated, add it to the list of active
445 // intervals.
446 if (success) {
447 active_.Add(current);
448 }
449 }
450}
451
452// Find a free register. If multiple are found, pick the register that
453// is free the longest.
454bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
455 size_t* free_until = registers_array_;
456
457 // First set all registers to be free.
458 for (size_t i = 0; i < number_of_registers_; ++i) {
459 free_until[i] = kMaxLifetimePosition;
460 }
461
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100462 // For each inactive interval, set its register to be free until
463 // the next intersection with `current`.
464 // Thanks to SSA, this should only be needed for intervals
465 // that are the result of a split.
466 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
467 LiveInterval* inactive = inactive_.Get(i);
468 DCHECK(inactive->HasRegister());
469 size_t next_intersection = inactive->FirstIntersectionWith(current);
470 if (next_intersection != kNoLifetime) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100471 free_until[inactive->GetRegister()] =
472 std::min(free_until[inactive->GetRegister()], next_intersection);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100473 }
474 }
475
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100476 // For each active interval, set its register to not free.
477 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
478 LiveInterval* interval = active_.Get(i);
479 DCHECK(interval->HasRegister());
480 free_until[interval->GetRegister()] = 0;
481 }
482
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100483 int reg = -1;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100484 if (current->HasRegister()) {
485 // Some instructions have a fixed register output.
486 reg = current->GetRegister();
487 DCHECK_NE(free_until[reg], 0u);
488 } else {
489 // Pick the register that is free the longest.
490 for (size_t i = 0; i < number_of_registers_; ++i) {
491 if (IsBlocked(i)) continue;
492 if (reg == -1 || free_until[i] > free_until[reg]) {
493 reg = i;
494 if (free_until[i] == kMaxLifetimePosition) break;
495 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100496 }
497 }
498
499 // If we could not find a register, we need to spill.
500 if (reg == -1 || free_until[reg] == 0) {
501 return false;
502 }
503
504 current->SetRegister(reg);
505 if (!current->IsDeadAt(free_until[reg])) {
506 // If the register is only available for a subset of live ranges
507 // covered by `current`, split `current` at the position where
508 // the register is not available anymore.
509 LiveInterval* split = Split(current, free_until[reg]);
510 DCHECK(split != nullptr);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100511 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100512 }
513 return true;
514}
515
516bool RegisterAllocator::IsBlocked(int reg) const {
517 // TODO: This only works for core registers and needs to be adjusted for
518 // floating point registers.
519 DCHECK(processing_core_registers_);
520 return blocked_registers_[reg];
521}
522
523// Find the register that is used the last, and spill the interval
524// that holds it. If the first use of `current` is after that register
525// we spill `current` instead.
526bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
527 size_t first_register_use = current->FirstRegisterUse();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100528 if (first_register_use == kNoLifetime) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100529 AllocateSpillSlotFor(current);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100530 return false;
531 }
532
533 // First set all registers as not being used.
534 size_t* next_use = registers_array_;
535 for (size_t i = 0; i < number_of_registers_; ++i) {
536 next_use[i] = kMaxLifetimePosition;
537 }
538
539 // For each active interval, find the next use of its register after the
540 // start of current.
541 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
542 LiveInterval* active = active_.Get(i);
543 DCHECK(active->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100544 if (active->IsFixed()) {
545 next_use[active->GetRegister()] = current->GetStart();
546 } else {
547 size_t use = active->FirstRegisterUseAfter(current->GetStart());
548 if (use != kNoLifetime) {
549 next_use[active->GetRegister()] = use;
550 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100551 }
552 }
553
554 // For each inactive interval, find the next use of its register after the
555 // start of current.
556 // Thanks to SSA, this should only be needed for intervals
557 // that are the result of a split.
558 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
559 LiveInterval* inactive = inactive_.Get(i);
560 DCHECK(inactive->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100561 size_t next_intersection = inactive->FirstIntersectionWith(current);
562 if (next_intersection != kNoLifetime) {
563 if (inactive->IsFixed()) {
564 next_use[inactive->GetRegister()] =
565 std::min(next_intersection, next_use[inactive->GetRegister()]);
566 } else {
567 size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
568 if (use != kNoLifetime) {
569 next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
570 }
571 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100572 }
573 }
574
575 // Pick the register that is used the last.
576 int reg = -1;
577 for (size_t i = 0; i < number_of_registers_; ++i) {
578 if (IsBlocked(i)) continue;
579 if (reg == -1 || next_use[i] > next_use[reg]) {
580 reg = i;
581 if (next_use[i] == kMaxLifetimePosition) break;
582 }
583 }
584
585 if (first_register_use >= next_use[reg]) {
586 // If the first use of that instruction is after the last use of the found
587 // register, we split this interval just before its first register use.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100588 AllocateSpillSlotFor(current);
Nicolas Geoffray76905622014-09-25 14:39:26 +0100589 LiveInterval* split = Split(current, first_register_use);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100590 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100591 return false;
592 } else {
593 // Use this register and spill the active and inactives interval that
594 // have that register.
595 current->SetRegister(reg);
596
597 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
598 LiveInterval* active = active_.Get(i);
599 if (active->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100600 DCHECK(!active->IsFixed());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100601 LiveInterval* split = Split(active, current->GetStart());
602 active_.DeleteAt(i);
603 handled_.Add(active);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100604 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100605 break;
606 }
607 }
608
609 for (size_t i = 0; i < inactive_.Size(); ++i) {
610 LiveInterval* inactive = inactive_.Get(i);
611 if (inactive->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100612 size_t next_intersection = inactive->FirstIntersectionWith(current);
613 if (next_intersection != kNoLifetime) {
614 if (inactive->IsFixed()) {
615 LiveInterval* split = Split(current, next_intersection);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100616 AddSorted(unhandled_, split);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100617 } else {
618 LiveInterval* split = Split(inactive, current->GetStart());
619 inactive_.DeleteAt(i);
620 handled_.Add(inactive);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100621 AddSorted(unhandled_, split);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100622 --i;
623 }
624 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100625 }
626 }
627
628 return true;
629 }
630}
631
Nicolas Geoffray39468442014-09-02 15:17:15 +0100632void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100633 size_t insert_at = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100634 for (size_t i = array->Size(); i > 0; --i) {
635 LiveInterval* current = array->Get(i - 1);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100636 if (current->StartsAfter(interval)) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100637 insert_at = i;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100638 break;
639 }
640 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100641 array->InsertAt(insert_at, interval);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100642}
643
644LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
645 DCHECK(position >= interval->GetStart());
646 DCHECK(!interval->IsDeadAt(position));
647 if (position == interval->GetStart()) {
648 // Spill slot will be allocated when handling `interval` again.
649 interval->ClearRegister();
650 return interval;
651 } else {
652 LiveInterval* new_interval = interval->SplitAt(position);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100653 return new_interval;
654 }
655}
656
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100657static bool NeedTwoSpillSlot(Primitive::Type type) {
658 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
659}
660
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100661void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
662 LiveInterval* parent = interval->GetParent();
663
664 // An instruction gets a spill slot for its entire lifetime. If the parent
665 // of this interval already has a spill slot, there is nothing to do.
666 if (parent->HasSpillSlot()) {
667 return;
668 }
669
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100670 HInstruction* defined_by = parent->GetDefinedBy();
671 if (defined_by->IsParameterValue()) {
672 // Parameters have their own stack slot.
673 parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
674 return;
675 }
676
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100677 if (defined_by->IsConstant()) {
678 // Constants don't need a spill slot.
679 return;
680 }
681
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100682 LiveInterval* last_sibling = interval;
683 while (last_sibling->GetNextSibling() != nullptr) {
684 last_sibling = last_sibling->GetNextSibling();
685 }
686 size_t end = last_sibling->GetEnd();
687
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100688 // Find an available spill slot.
689 size_t slot = 0;
690 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
691 // We check if it is less rather than less or equal because the parallel move
692 // resolver does not work when a single spill slot needs to be exchanged with
693 // a double spill slot. The strict comparison avoids needing to exchange these
694 // locations at the same lifetime position.
695 if (spill_slots_.Get(slot) < parent->GetStart()
696 && (slot == (e - 1) || spill_slots_.Get(slot + 1) < parent->GetStart())) {
697 break;
698 }
699 }
700
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100701 if (NeedTwoSpillSlot(parent->GetType())) {
702 if (slot == spill_slots_.Size()) {
703 // We need a new spill slot.
704 spill_slots_.Add(end);
705 spill_slots_.Add(end);
706 } else if (slot == spill_slots_.Size() - 1) {
707 spill_slots_.Put(slot, end);
708 spill_slots_.Add(end);
709 } else {
710 spill_slots_.Put(slot, end);
711 spill_slots_.Put(slot + 1, end);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100712 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100713 } else {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100714 if (slot == spill_slots_.Size()) {
715 // We need a new spill slot.
716 spill_slots_.Add(end);
717 } else {
718 spill_slots_.Put(slot, end);
719 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100720 }
721
Nicolas Geoffray39468442014-09-02 15:17:15 +0100722 parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100723}
724
725static Location ConvertToLocation(LiveInterval* interval) {
726 if (interval->HasRegister()) {
727 return Location::RegisterLocation(ManagedRegister(interval->GetRegister()));
728 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100729 HInstruction* defined_by = interval->GetParent()->GetDefinedBy();
730 if (defined_by->IsConstant()) {
731 return defined_by->GetLocations()->Out();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100732 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100733 DCHECK(interval->GetParent()->HasSpillSlot());
734 if (NeedTwoSpillSlot(interval->GetType())) {
735 return Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot());
736 } else {
737 return Location::StackSlot(interval->GetParent()->GetSpillSlot());
738 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100739 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100740 }
741}
742
743// We create a special marker for inputs moves to differentiate them from
744// moves created during resolution. They must be different instructions
745// because the input moves work on the assumption that the interval moves
746// have been executed.
747static constexpr size_t kInputMoveLifetimePosition = 0;
748static bool IsInputMove(HInstruction* instruction) {
749 return instruction->GetLifetimePosition() == kInputMoveLifetimePosition;
750}
751
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100752static bool IsValidDestination(Location destination) {
753 return destination.IsRegister() || destination.IsStackSlot() || destination.IsDoubleStackSlot();
754}
755
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100756void RegisterAllocator::AddInputMoveFor(HInstruction* instruction,
757 Location source,
758 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100759 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100760 if (source.Equals(destination)) return;
761
762 DCHECK(instruction->AsPhi() == nullptr);
763
764 HInstruction* previous = instruction->GetPrevious();
765 HParallelMove* move = nullptr;
766 if (previous == nullptr
767 || previous->AsParallelMove() == nullptr
768 || !IsInputMove(previous)) {
769 move = new (allocator_) HParallelMove(allocator_);
770 move->SetLifetimePosition(kInputMoveLifetimePosition);
771 instruction->GetBlock()->InsertInstructionBefore(move, instruction);
772 } else {
773 move = previous->AsParallelMove();
774 }
775 DCHECK(IsInputMove(move));
776 move->AddMove(new (allocator_) MoveOperands(source, destination));
777}
778
779void RegisterAllocator::InsertParallelMoveAt(size_t position,
780 Location source,
781 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100782 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100783 if (source.Equals(destination)) return;
784
785 HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
786 if (at == nullptr) {
787 // Block boundary, don't no anything the connection of split siblings will handle it.
788 return;
789 }
790 HParallelMove* move;
791 if ((position & 1) == 1) {
792 // Move must happen after the instruction.
793 DCHECK(!at->IsControlFlow());
794 move = at->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100795 // This is a parallel move for connecting siblings in a same block. We need to
796 // differentiate it with moves for connecting blocks, and input moves.
797 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100798 move = new (allocator_) HParallelMove(allocator_);
799 move->SetLifetimePosition(position);
800 at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
801 }
802 } else {
803 // Move must happen before the instruction.
804 HInstruction* previous = at->GetPrevious();
805 if (previous != nullptr && previous->AsParallelMove() != nullptr) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100806 // This is a parallel move for connecting siblings in a same block. We need to
807 // differentiate it with moves for connecting blocks, and input moves.
808 if (previous->GetLifetimePosition() != position) {
Nicolas Geoffray145f0ca2014-09-22 11:51:51 +0100809 // If the previous instruction of the previous instruction is not a parallel
810 // move, we have to insert the new parallel move before the input or connecting
811 // block moves.
812 at = previous;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100813 previous = previous->GetPrevious();
814 }
815 }
816 if (previous == nullptr || previous->AsParallelMove() == nullptr) {
817 move = new (allocator_) HParallelMove(allocator_);
818 move->SetLifetimePosition(position);
819 at->GetBlock()->InsertInstructionBefore(move, at);
820 } else {
821 move = previous->AsParallelMove();
822 }
823 }
824 move->AddMove(new (allocator_) MoveOperands(source, destination));
825}
826
827void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
828 Location source,
829 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100830 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100831 if (source.Equals(destination)) return;
832
833 DCHECK_EQ(block->GetSuccessors().Size(), 1u);
834 HInstruction* last = block->GetLastInstruction();
835 HInstruction* previous = last->GetPrevious();
836 HParallelMove* move;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100837 // This is a parallel move for connecting blocks. We need to differentiate
838 // it with moves for connecting siblings in a same block, and output moves.
839 if (previous == nullptr || previous->AsParallelMove() == nullptr
840 || previous->AsParallelMove()->GetLifetimePosition() != block->GetLifetimeEnd()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100841 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100842 move->SetLifetimePosition(block->GetLifetimeEnd());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100843 block->InsertInstructionBefore(move, last);
844 } else {
845 move = previous->AsParallelMove();
846 }
847 move->AddMove(new (allocator_) MoveOperands(source, destination));
848}
849
850void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
851 Location source,
852 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100853 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100854 if (source.Equals(destination)) return;
855
856 HInstruction* first = block->GetFirstInstruction();
857 HParallelMove* move = first->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100858 // This is a parallel move for connecting blocks. We need to differentiate
859 // it with moves for connecting siblings in a same block, and input moves.
860 if (move == nullptr || move->GetLifetimePosition() != block->GetLifetimeStart()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100861 move = new (allocator_) HParallelMove(allocator_);
862 move->SetLifetimePosition(block->GetLifetimeStart());
863 block->InsertInstructionBefore(move, first);
864 }
865 move->AddMove(new (allocator_) MoveOperands(source, destination));
866}
867
868void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
869 Location source,
870 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100871 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100872 if (source.Equals(destination)) return;
873
874 if (instruction->AsPhi() != nullptr) {
875 InsertParallelMoveAtEntryOf(instruction->GetBlock(), source, destination);
876 return;
877 }
878
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100879 size_t position = instruction->GetLifetimePosition() + 1;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100880 HParallelMove* move = instruction->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100881 // This is a parallel move for moving the output of an instruction. We need
882 // to differentiate with input moves, moves for connecting siblings in a
883 // and moves for connecting blocks.
884 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100885 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100886 move->SetLifetimePosition(position);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100887 instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
888 }
889 move->AddMove(new (allocator_) MoveOperands(source, destination));
890}
891
892void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
893 LiveInterval* current = interval;
894 if (current->HasSpillSlot() && current->HasRegister()) {
895 // We spill eagerly, so move must be at definition.
896 InsertMoveAfter(interval->GetDefinedBy(),
897 Location::RegisterLocation(ManagedRegister(interval->GetRegister())),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100898 NeedTwoSpillSlot(interval->GetType())
899 ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
900 : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100901 }
902 UsePosition* use = current->GetFirstUse();
903
904 // Walk over all siblings, updating locations of use positions, and
905 // connecting them when they are adjacent.
906 do {
907 Location source = ConvertToLocation(current);
908
909 // Walk over all uses covered by this interval, and update the location
910 // information.
911 while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100912 LocationSummary* locations = use->GetUser()->GetLocations();
913 if (use->GetIsEnvironment()) {
914 locations->SetEnvironmentAt(use->GetInputIndex(), source);
915 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100916 Location expected_location = locations->InAt(use->GetInputIndex());
917 if (expected_location.IsUnallocated()) {
918 locations->SetInAt(use->GetInputIndex(), source);
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100919 } else if (!expected_location.IsConstant()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100920 AddInputMoveFor(use->GetUser(), source, expected_location);
921 }
922 }
923 use = use->GetNext();
924 }
925
926 // If the next interval starts just after this one, and has a register,
927 // insert a move.
928 LiveInterval* next_sibling = current->GetNextSibling();
929 if (next_sibling != nullptr
930 && next_sibling->HasRegister()
931 && current->GetEnd() == next_sibling->GetStart()) {
932 Location destination = ConvertToLocation(next_sibling);
933 InsertParallelMoveAt(current->GetEnd(), source, destination);
934 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100935
936 // At each safepoint, we record stack and register information.
937 for (size_t i = 0, e = safepoints_.Size(); i < e; ++i) {
938 HInstruction* safepoint = safepoints_.Get(i);
939 size_t position = safepoint->GetLifetimePosition();
940 LocationSummary* locations = safepoint->GetLocations();
941 if (!current->Covers(position)) continue;
942
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100943 if ((current->GetType() == Primitive::kPrimNot) && current->GetParent()->HasSpillSlot()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100944 locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
945 }
946
947 switch (source.GetKind()) {
948 case Location::kRegister: {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100949 locations->AddLiveRegister(source);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100950 if (current->GetType() == Primitive::kPrimNot) {
951 locations->SetRegisterBit(source.reg().RegId());
952 }
953 break;
954 }
955 case Location::kStackSlot: // Fall-through
956 case Location::kDoubleStackSlot: // Fall-through
957 case Location::kConstant: {
958 // Nothing to do.
959 break;
960 }
961 default: {
962 LOG(FATAL) << "Unexpected location for object";
963 }
964 }
965 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100966 current = next_sibling;
967 } while (current != nullptr);
968 DCHECK(use == nullptr);
969}
970
971void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
972 HBasicBlock* from,
973 HBasicBlock* to) const {
974 if (interval->GetNextSibling() == nullptr) {
975 // Nothing to connect. The whole range was allocated to the same location.
976 return;
977 }
978
979 size_t from_position = from->GetLifetimeEnd() - 1;
Nicolas Geoffray76905622014-09-25 14:39:26 +0100980 // When an instructions dies at entry of another, and the latter is the beginning
981 // of a block, the register allocator ensures the former has a register
982 // at block->GetLifetimeStart() + 1. Since this is at a block boundary, it must
983 // must be handled in this method.
984 size_t to_position = to->GetLifetimeStart() + 1;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100985
986 LiveInterval* destination = nullptr;
987 LiveInterval* source = nullptr;
988
989 LiveInterval* current = interval;
990
991 // Check the intervals that cover `from` and `to`.
992 while ((current != nullptr) && (source == nullptr || destination == nullptr)) {
993 if (current->Covers(from_position)) {
994 DCHECK(source == nullptr);
995 source = current;
996 }
997 if (current->Covers(to_position)) {
998 DCHECK(destination == nullptr);
999 destination = current;
1000 }
1001
1002 current = current->GetNextSibling();
1003 }
1004
1005 if (destination == source) {
1006 // Interval was not split.
1007 return;
1008 }
1009
1010 if (!destination->HasRegister()) {
1011 // Values are eagerly spilled. Spill slot already contains appropriate value.
1012 return;
1013 }
1014
1015 // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
1016 // we need to put the moves at the entry of `to`.
1017 if (from->GetSuccessors().Size() == 1) {
1018 InsertParallelMoveAtExitOf(from, ConvertToLocation(source), ConvertToLocation(destination));
1019 } else {
1020 DCHECK_EQ(to->GetPredecessors().Size(), 1u);
1021 InsertParallelMoveAtEntryOf(to, ConvertToLocation(source), ConvertToLocation(destination));
1022 }
1023}
1024
1025// Returns the location of `interval`, or siblings of `interval`, at `position`.
1026static Location FindLocationAt(LiveInterval* interval, size_t position) {
1027 LiveInterval* current = interval;
1028 while (!current->Covers(position)) {
1029 current = current->GetNextSibling();
1030 DCHECK(current != nullptr);
1031 }
1032 return ConvertToLocation(current);
1033}
1034
1035void RegisterAllocator::Resolve() {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001036 codegen_->ComputeFrameSize(
1037 spill_slots_.Size(), maximum_number_of_live_registers_, reserved_out_slots_);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001038
1039 // Adjust the Out Location of instructions.
1040 // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
1041 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1042 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1043 LiveInterval* current = instruction->GetLiveInterval();
1044 LocationSummary* locations = instruction->GetLocations();
1045 Location location = locations->Out();
1046 if (instruction->AsParameterValue() != nullptr) {
1047 // Now that we know the frame size, adjust the parameter's location.
1048 if (location.IsStackSlot()) {
1049 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1050 current->SetSpillSlot(location.GetStackIndex());
1051 locations->SetOut(location);
1052 } else if (location.IsDoubleStackSlot()) {
1053 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1054 current->SetSpillSlot(location.GetStackIndex());
1055 locations->SetOut(location);
1056 } else if (current->HasSpillSlot()) {
1057 current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
1058 }
1059 }
1060
1061 Location source = ConvertToLocation(current);
1062
1063 if (location.IsUnallocated()) {
1064 if (location.GetPolicy() == Location::kSameAsFirstInput) {
1065 locations->SetInAt(0, source);
1066 }
1067 locations->SetOut(source);
1068 } else {
1069 DCHECK(source.Equals(location));
1070 }
1071 }
1072
1073 // Connect siblings.
1074 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1075 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1076 ConnectSiblings(instruction->GetLiveInterval());
1077 }
1078
1079 // Resolve non-linear control flow across branches. Order does not matter.
1080 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
1081 HBasicBlock* block = it.Current();
1082 BitVector* live = liveness_.GetLiveInSet(*block);
1083 for (uint32_t idx : live->Indexes()) {
1084 HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
1085 LiveInterval* interval = current->GetLiveInterval();
1086 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
1087 ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
1088 }
1089 }
1090 }
1091
1092 // Resolve phi inputs. Order does not matter.
1093 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
1094 HBasicBlock* current = it.Current();
1095 for (HInstructionIterator it(current->GetPhis()); !it.Done(); it.Advance()) {
1096 HInstruction* phi = it.Current();
1097 for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
1098 HBasicBlock* predecessor = current->GetPredecessors().Get(i);
1099 DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
1100 HInstruction* input = phi->InputAt(i);
1101 Location source = FindLocationAt(input->GetLiveInterval(),
1102 predecessor->GetLastInstruction()->GetLifetimePosition());
1103 Location destination = ConvertToLocation(phi->GetLiveInterval());
1104 InsertParallelMoveAtExitOf(predecessor, source, destination);
1105 }
1106 }
1107 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001108
1109 // Assign temp locations.
1110 HInstruction* current = nullptr;
1111 size_t temp_index = 0;
1112 for (size_t i = 0; i < temp_intervals_.Size(); ++i) {
1113 LiveInterval* temp = temp_intervals_.Get(i);
1114 if (temp->GetDefinedBy() != current) {
1115 temp_index = 0;
1116 current = temp->GetDefinedBy();
1117 }
1118 LocationSummary* locations = current->GetLocations();
1119 locations->SetTempAt(
1120 temp_index++, Location::RegisterLocation(ManagedRegister(temp->GetRegister())));
1121 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001122}
1123
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001124} // namespace art