blob: a6c06359a0d514972c93de18507d1fa12b53fe63 [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 Rogersc7dd2952014-10-21 23:31:19 -070019#include <sstream>
20
Ian Rogerse77493c2014-08-20 15:08:45 -070021#include "base/bit_vector-inl.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010022#include "code_generator.h"
23#include "ssa_liveness_analysis.h"
24
25namespace art {
26
27static constexpr size_t kMaxLifetimePosition = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010028static constexpr size_t kDefaultNumberOfSpillSlots = 4;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010029
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010030RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
31 CodeGenerator* codegen,
32 const SsaLivenessAnalysis& liveness)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010033 : allocator_(allocator),
34 codegen_(codegen),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010035 liveness_(liveness),
Nicolas Geoffray39468442014-09-02 15:17:15 +010036 unhandled_core_intervals_(allocator, 0),
37 unhandled_fp_intervals_(allocator, 0),
38 unhandled_(nullptr),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010039 handled_(allocator, 0),
40 active_(allocator, 0),
41 inactive_(allocator, 0),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010042 physical_core_register_intervals_(allocator, codegen->GetNumberOfCoreRegisters()),
43 physical_fp_register_intervals_(allocator, codegen->GetNumberOfFloatingPointRegisters()),
Nicolas Geoffray39468442014-09-02 15:17:15 +010044 temp_intervals_(allocator, 4),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010045 spill_slots_(allocator, kDefaultNumberOfSpillSlots),
Nicolas Geoffray39468442014-09-02 15:17:15 +010046 safepoints_(allocator, 0),
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010047 processing_core_registers_(false),
48 number_of_registers_(-1),
49 registers_array_(nullptr),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010050 blocked_core_registers_(codegen->GetBlockedCoreRegisters()),
51 blocked_fp_registers_(codegen->GetBlockedFloatingPointRegisters()),
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +010052 reserved_out_slots_(0),
53 maximum_number_of_live_registers_(0) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +010054 codegen->SetupBlockedRegisters();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010055 physical_core_register_intervals_.SetSize(codegen->GetNumberOfCoreRegisters());
56 physical_fp_register_intervals_.SetSize(codegen->GetNumberOfFloatingPointRegisters());
Nicolas Geoffray39468442014-09-02 15:17:15 +010057 // Always reserve for the current method and the graph's max out registers.
58 // TODO: compute it instead.
59 reserved_out_slots_ = 1 + codegen->GetGraph()->GetMaximumNumberOfOutVRegs();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010060}
61
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010062bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
63 InstructionSet instruction_set) {
64 if (!Supports(instruction_set)) {
65 return false;
66 }
67 for (size_t i = 0, e = graph.GetBlocks().Size(); i < e; ++i) {
68 for (HInstructionIterator it(graph.GetBlocks().Get(i)->GetInstructions());
69 !it.Done();
70 it.Advance()) {
71 HInstruction* current = it.Current();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +010072 if (current->GetType() == Primitive::kPrimLong && instruction_set != kX86_64) return false;
Roland Levillain199f3362014-11-27 17:15:16 +000073 if ((current->GetType() == Primitive::kPrimFloat
74 || current->GetType() == Primitive::kPrimDouble)
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010075 && instruction_set != kX86_64) {
76 return false;
77 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010078 }
79 }
80 return true;
81}
82
83static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
Nicolas Geoffray39468442014-09-02 15:17:15 +010084 if (interval == nullptr) return false;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010085 bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
86 && (interval->GetType() != Primitive::kPrimFloat);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010087 return processing_core_registers == is_core_register;
88}
89
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010090void RegisterAllocator::AllocateRegisters() {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010091 AllocateRegistersInternal();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010092 Resolve();
93
94 if (kIsDebugBuild) {
95 processing_core_registers_ = true;
96 ValidateInternal(true);
97 processing_core_registers_ = false;
98 ValidateInternal(true);
Nicolas Geoffray59768572014-12-01 09:50:04 +000099 // Check that the linear order is still correct with regards to lifetime positions.
100 // Since only parallel moves have been inserted during the register allocation,
101 // these checks are mostly for making sure these moves have been added correctly.
102 size_t current_liveness = 0;
103 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
104 HBasicBlock* block = it.Current();
105 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
106 HInstruction* instruction = inst_it.Current();
107 DCHECK_LE(current_liveness, instruction->GetLifetimePosition());
108 current_liveness = instruction->GetLifetimePosition();
109 }
110 for (HInstructionIterator inst_it(block->GetInstructions());
111 !inst_it.Done();
112 inst_it.Advance()) {
113 HInstruction* instruction = inst_it.Current();
114 DCHECK_LE(current_liveness, instruction->GetLifetimePosition()) << instruction->DebugName();
115 current_liveness = instruction->GetLifetimePosition();
116 }
117 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100118 }
119}
120
121void RegisterAllocator::BlockRegister(Location location,
122 size_t start,
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100123 size_t end) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100124 int reg = location.reg();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100125 DCHECK(location.IsRegister() || location.IsFpuRegister());
126 LiveInterval* interval = location.IsRegister()
127 ? physical_core_register_intervals_.Get(reg)
128 : physical_fp_register_intervals_.Get(reg);
129 Primitive::Type type = location.IsRegister()
130 ? Primitive::kPrimInt
131 : Primitive::kPrimDouble;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100132 if (interval == nullptr) {
133 interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100134 if (location.IsRegister()) {
135 physical_core_register_intervals_.Put(reg, interval);
136 } else {
137 physical_fp_register_intervals_.Put(reg, interval);
138 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100139 }
140 DCHECK(interval->GetRegister() == reg);
141 interval->AddRange(start, end);
142}
143
144void RegisterAllocator::AllocateRegistersInternal() {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100145 // Iterate post-order, to ensure the list is sorted, and the last added interval
146 // is the one with the lowest start position.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100147 for (HLinearPostOrderIterator it(liveness_); !it.Done(); it.Advance()) {
148 HBasicBlock* block = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800149 for (HBackwardInstructionIterator back_it(block->GetInstructions()); !back_it.Done();
150 back_it.Advance()) {
151 ProcessInstruction(back_it.Current());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100152 }
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800153 for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
154 ProcessInstruction(inst_it.Current());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100155 }
156 }
157
Nicolas Geoffray39468442014-09-02 15:17:15 +0100158 number_of_registers_ = codegen_->GetNumberOfCoreRegisters();
159 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
160 processing_core_registers_ = true;
161 unhandled_ = &unhandled_core_intervals_;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100162 for (size_t i = 0, e = physical_core_register_intervals_.Size(); i < e; ++i) {
163 LiveInterval* fixed = physical_core_register_intervals_.Get(i);
164 if (fixed != nullptr) {
Mingyao Yang296bd602014-10-06 16:47:28 -0700165 // Fixed interval is added to inactive_ instead of unhandled_.
166 // It's also the only type of inactive interval whose start position
167 // can be after the current interval during linear scan.
168 // Fixed interval is never split and never moves to unhandled_.
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100169 inactive_.Add(fixed);
170 }
171 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100172 LinearScan();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100173
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100174 size_t saved_maximum_number_of_live_registers = maximum_number_of_live_registers_;
175 maximum_number_of_live_registers_ = 0;
176
Nicolas Geoffray39468442014-09-02 15:17:15 +0100177 inactive_.Reset();
178 active_.Reset();
179 handled_.Reset();
180
181 number_of_registers_ = codegen_->GetNumberOfFloatingPointRegisters();
182 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
183 processing_core_registers_ = false;
184 unhandled_ = &unhandled_fp_intervals_;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100185 for (size_t i = 0, e = physical_fp_register_intervals_.Size(); i < e; ++i) {
186 LiveInterval* fixed = physical_fp_register_intervals_.Get(i);
187 if (fixed != nullptr) {
Mingyao Yang296bd602014-10-06 16:47:28 -0700188 // Fixed interval is added to inactive_ instead of unhandled_.
189 // It's also the only type of inactive interval whose start position
190 // can be after the current interval during linear scan.
191 // Fixed interval is never split and never moves to unhandled_.
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100192 inactive_.Add(fixed);
193 }
194 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100195 LinearScan();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100196 maximum_number_of_live_registers_ += saved_maximum_number_of_live_registers;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100197}
198
199void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
200 LocationSummary* locations = instruction->GetLocations();
201 size_t position = instruction->GetLifetimePosition();
202
203 if (locations == nullptr) return;
204
205 // Create synthesized intervals for temporaries.
206 for (size_t i = 0; i < locations->GetTempCount(); ++i) {
207 Location temp = locations->GetTemp(i);
Nicolas Geoffray52839d12014-11-07 17:47:25 +0000208 if (temp.IsRegister() || temp.IsFpuRegister()) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100209 BlockRegister(temp, position, position + 1);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100210 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100211 DCHECK(temp.IsUnallocated());
Roland Levillain5368c212014-11-27 15:03:41 +0000212 switch (temp.GetPolicy()) {
213 case Location::kRequiresRegister: {
214 LiveInterval* interval =
215 LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
216 temp_intervals_.Add(interval);
217 interval->AddRange(position, position + 1);
218 unhandled_core_intervals_.Add(interval);
219 break;
220 }
221
222 case Location::kRequiresFpuRegister: {
223 LiveInterval* interval =
224 LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
225 temp_intervals_.Add(interval);
226 interval->AddRange(position, position + 1);
227 unhandled_fp_intervals_.Add(interval);
228 break;
229 }
230
231 default:
232 LOG(FATAL) << "Unexpected policy for temporary location "
233 << temp.GetPolicy();
234 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100235 }
236 }
237
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100238 bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
239 && (instruction->GetType() != Primitive::kPrimFloat);
240
Nicolas Geoffray39468442014-09-02 15:17:15 +0100241 if (locations->CanCall()) {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100242 if (!instruction->IsSuspendCheck()) {
243 codegen_->MarkNotLeaf();
244 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100245 safepoints_.Add(instruction);
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100246 if (locations->OnlyCallsOnSlowPath()) {
247 // We add a synthesized range at this position to record the live registers
248 // at this position. Ideally, we could just update the safepoints when locations
249 // are updated, but we currently need to know the full stack size before updating
250 // locations (because of parameters and the fact that we don't have a frame pointer).
251 // And knowing the full stack size requires to know the maximum number of live
252 // registers at calls in slow paths.
253 // By adding the following interval in the algorithm, we can compute this
254 // maximum before updating locations.
255 LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
Nicolas Geoffrayacd03392014-11-26 15:46:52 +0000256 interval->AddRange(position, position + 1);
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000257 AddSorted(&unhandled_core_intervals_, interval);
258 AddSorted(&unhandled_fp_intervals_, interval);
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100259 }
260 }
261
262 if (locations->WillCall()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100263 // Block all registers.
264 for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100265 BlockRegister(Location::RegisterLocation(i),
Nicolas Geoffray39468442014-09-02 15:17:15 +0100266 position,
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100267 position + 1);
268 }
269 for (size_t i = 0; i < codegen_->GetNumberOfFloatingPointRegisters(); ++i) {
270 BlockRegister(Location::FpuRegisterLocation(i),
271 position,
272 position + 1);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100273 }
274 }
275
276 for (size_t i = 0; i < instruction->InputCount(); ++i) {
277 Location input = locations->InAt(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100278 if (input.IsRegister() || input.IsFpuRegister()) {
279 BlockRegister(input, position, position + 1);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100280 }
281 }
282
Nicolas Geoffray39468442014-09-02 15:17:15 +0100283 LiveInterval* current = instruction->GetLiveInterval();
284 if (current == nullptr) return;
285
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100286 GrowableArray<LiveInterval*>& unhandled = core_register
287 ? unhandled_core_intervals_
288 : unhandled_fp_intervals_;
289
Nicolas Geoffray76905622014-09-25 14:39:26 +0100290 DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000291
Nicolas Geoffray39468442014-09-02 15:17:15 +0100292 // Some instructions define their output in fixed register/stack slot. We need
293 // to ensure we know these locations before doing register allocation. For a
294 // given register, we create an interval that covers these locations. The register
295 // will be unavailable at these locations when trying to allocate one for an
296 // interval.
297 //
298 // The backwards walking ensures the ranges are ordered on increasing start positions.
299 Location output = locations->Out();
Calin Juravled0d48522014-11-04 16:40:20 +0000300 if (output.IsUnallocated() && output.GetPolicy() == Location::kSameAsFirstInput) {
301 Location first = locations->InAt(0);
302 if (first.IsRegister() || first.IsFpuRegister()) {
303 current->SetFrom(position + 1);
304 current->SetRegister(first.reg());
305 }
306 } else if (output.IsRegister() || output.IsFpuRegister()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100307 // Shift the interval's start by one to account for the blocked register.
308 current->SetFrom(position + 1);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100309 current->SetRegister(output.reg());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100310 BlockRegister(output, position, position + 1);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100311 } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
312 current->SetSpillSlot(output.GetStackIndex());
313 }
314
315 // If needed, add interval to the list of unhandled intervals.
316 if (current->HasSpillSlot() || instruction->IsConstant()) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100317 // Split just before first register use.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100318 size_t first_register_use = current->FirstRegisterUse();
319 if (first_register_use != kNoLifetime) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100320 LiveInterval* split = Split(current, first_register_use - 1);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000321 // Don't add directly to `unhandled`, it needs to be sorted and the start
Nicolas Geoffray39468442014-09-02 15:17:15 +0100322 // of this new interval might be after intervals already in the list.
323 AddSorted(&unhandled, split);
324 } else {
325 // Nothing to do, we won't allocate a register for this value.
326 }
327 } else {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000328 // Don't add directly to `unhandled`, temp or safepoint intervals
329 // for this instruction may have been added, and those can be
330 // processed first.
331 AddSorted(&unhandled, current);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100332 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100333}
334
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100335class AllRangesIterator : public ValueObject {
336 public:
337 explicit AllRangesIterator(LiveInterval* interval)
338 : current_interval_(interval),
339 current_range_(interval->GetFirstRange()) {}
340
341 bool Done() const { return current_interval_ == nullptr; }
342 LiveRange* CurrentRange() const { return current_range_; }
343 LiveInterval* CurrentInterval() const { return current_interval_; }
344
345 void Advance() {
346 current_range_ = current_range_->GetNext();
347 if (current_range_ == nullptr) {
348 current_interval_ = current_interval_->GetNextSibling();
349 if (current_interval_ != nullptr) {
350 current_range_ = current_interval_->GetFirstRange();
351 }
352 }
353 }
354
355 private:
356 LiveInterval* current_interval_;
357 LiveRange* current_range_;
358
359 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
360};
361
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100362bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
363 // To simplify unit testing, we eagerly create the array of intervals, and
364 // call the helper method.
365 GrowableArray<LiveInterval*> intervals(allocator_, 0);
366 for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
367 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
368 if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
369 intervals.Add(instruction->GetLiveInterval());
370 }
371 }
372
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100373 if (processing_core_registers_) {
374 for (size_t i = 0, e = physical_core_register_intervals_.Size(); i < e; ++i) {
375 LiveInterval* fixed = physical_core_register_intervals_.Get(i);
376 if (fixed != nullptr) {
377 intervals.Add(fixed);
378 }
379 }
380 } else {
381 for (size_t i = 0, e = physical_fp_register_intervals_.Size(); i < e; ++i) {
382 LiveInterval* fixed = physical_fp_register_intervals_.Get(i);
383 if (fixed != nullptr) {
384 intervals.Add(fixed);
385 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100386 }
387 }
388
Nicolas Geoffray39468442014-09-02 15:17:15 +0100389 for (size_t i = 0, e = temp_intervals_.Size(); i < e; ++i) {
390 LiveInterval* temp = temp_intervals_.Get(i);
391 if (ShouldProcess(processing_core_registers_, temp)) {
392 intervals.Add(temp);
393 }
394 }
395
396 return ValidateIntervals(intervals, spill_slots_.Size(), reserved_out_slots_, *codegen_,
397 allocator_, processing_core_registers_, log_fatal_on_failure);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100398}
399
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100400bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
401 size_t number_of_spill_slots,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100402 size_t number_of_out_slots,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100403 const CodeGenerator& codegen,
404 ArenaAllocator* allocator,
405 bool processing_core_registers,
406 bool log_fatal_on_failure) {
407 size_t number_of_registers = processing_core_registers
408 ? codegen.GetNumberOfCoreRegisters()
409 : codegen.GetNumberOfFloatingPointRegisters();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100410 GrowableArray<ArenaBitVector*> liveness_of_values(
411 allocator, number_of_registers + number_of_spill_slots);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100412
413 // Allocate a bit vector per register. A live interval that has a register
414 // allocated will populate the associated bit vector based on its live ranges.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100415 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
416 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100417 }
418
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100419 for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
420 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
421 LiveInterval* current = it.CurrentInterval();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100422 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
423 if (current->GetParent()->HasSpillSlot()
424 // Parameters have their own stack slot.
425 && !(defined_by != nullptr && defined_by->IsParameterValue())) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100426 BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers
427 + current->GetParent()->GetSpillSlot() / kVRegSize
428 - number_of_out_slots);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100429 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
430 if (liveness_of_spill_slot->IsBitSet(j)) {
431 if (log_fatal_on_failure) {
432 std::ostringstream message;
433 message << "Spill slot conflict at " << j;
434 LOG(FATAL) << message.str();
435 } else {
436 return false;
437 }
438 } else {
439 liveness_of_spill_slot->SetBit(j);
440 }
441 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100442 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100443
444 if (current->HasRegister()) {
445 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
446 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
447 if (liveness_of_register->IsBitSet(j)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100448 if (log_fatal_on_failure) {
449 std::ostringstream message;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100450 message << "Register conflict at " << j << " ";
451 if (defined_by != nullptr) {
452 message << "(" << defined_by->DebugName() << ")";
453 }
454 message << "for ";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100455 if (processing_core_registers) {
456 codegen.DumpCoreRegister(message, current->GetRegister());
457 } else {
458 codegen.DumpFloatingPointRegister(message, current->GetRegister());
459 }
460 LOG(FATAL) << message.str();
461 } else {
462 return false;
463 }
464 } else {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100465 liveness_of_register->SetBit(j);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100466 }
467 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100468 }
469 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100470 }
471 return true;
472}
473
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100474void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100475 interval->Dump(stream);
476 stream << ": ";
477 if (interval->HasRegister()) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100478 if (interval->IsFloatingPoint()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100479 codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100480 } else {
481 codegen_->DumpCoreRegister(stream, interval->GetRegister());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100482 }
483 } else {
484 stream << "spilled";
485 }
486 stream << std::endl;
487}
488
Mingyao Yang296bd602014-10-06 16:47:28 -0700489void RegisterAllocator::DumpAllIntervals(std::ostream& stream) const {
490 stream << "inactive: " << std::endl;
491 for (size_t i = 0; i < inactive_.Size(); i ++) {
492 DumpInterval(stream, inactive_.Get(i));
493 }
494 stream << "active: " << std::endl;
495 for (size_t i = 0; i < active_.Size(); i ++) {
496 DumpInterval(stream, active_.Get(i));
497 }
498 stream << "unhandled: " << std::endl;
499 auto unhandled = (unhandled_ != nullptr) ?
500 unhandled_ : &unhandled_core_intervals_;
501 for (size_t i = 0; i < unhandled->Size(); i ++) {
502 DumpInterval(stream, unhandled->Get(i));
503 }
504 stream << "handled: " << std::endl;
505 for (size_t i = 0; i < handled_.Size(); i ++) {
506 DumpInterval(stream, handled_.Get(i));
507 }
508}
509
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100510// By the book implementation of a linear scan register allocator.
511void RegisterAllocator::LinearScan() {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100512 while (!unhandled_->IsEmpty()) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100513 // (1) Remove interval with the lowest start position from unhandled.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100514 LiveInterval* current = unhandled_->Pop();
515 DCHECK(!current->IsFixed() && !current->HasSpillSlot());
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100516 DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart());
Nicolas Geoffray87d03762014-11-19 15:17:56 +0000517
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100518 size_t position = current->GetStart();
519
Mingyao Yang296bd602014-10-06 16:47:28 -0700520 // Remember the inactive_ size here since the ones moved to inactive_ from
521 // active_ below shouldn't need to be re-checked.
522 size_t inactive_intervals_to_handle = inactive_.Size();
523
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100524 // (2) Remove currently active intervals that are dead at this position.
525 // Move active intervals that have a lifetime hole at this position
526 // to inactive.
527 for (size_t i = 0; i < active_.Size(); ++i) {
528 LiveInterval* interval = active_.Get(i);
529 if (interval->IsDeadAt(position)) {
530 active_.Delete(interval);
531 --i;
532 handled_.Add(interval);
533 } else if (!interval->Covers(position)) {
534 active_.Delete(interval);
535 --i;
536 inactive_.Add(interval);
537 }
538 }
539
540 // (3) Remove currently inactive intervals that are dead at this position.
541 // Move inactive intervals that cover this position to active.
Mingyao Yang296bd602014-10-06 16:47:28 -0700542 for (size_t i = 0; i < inactive_intervals_to_handle; ++i) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100543 LiveInterval* interval = inactive_.Get(i);
Mingyao Yang296bd602014-10-06 16:47:28 -0700544 DCHECK(interval->GetStart() < position || interval->IsFixed());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100545 if (interval->IsDeadAt(position)) {
546 inactive_.Delete(interval);
547 --i;
Mingyao Yang296bd602014-10-06 16:47:28 -0700548 --inactive_intervals_to_handle;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100549 handled_.Add(interval);
550 } else if (interval->Covers(position)) {
551 inactive_.Delete(interval);
552 --i;
Mingyao Yang296bd602014-10-06 16:47:28 -0700553 --inactive_intervals_to_handle;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100554 active_.Add(interval);
555 }
556 }
557
Nicolas Geoffrayacd03392014-11-26 15:46:52 +0000558 if (current->IsSlowPathSafepoint()) {
559 // Synthesized interval to record the maximum number of live registers
560 // at safepoints. No need to allocate a register for it.
561 maximum_number_of_live_registers_ =
562 std::max(maximum_number_of_live_registers_, active_.Size());
563 DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() > current->GetStart());
564 continue;
565 }
566
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100567 // (4) Try to find an available register.
568 bool success = TryAllocateFreeReg(current);
569
570 // (5) If no register could be found, we need to spill.
571 if (!success) {
572 success = AllocateBlockedReg(current);
573 }
574
575 // (6) If the interval had a register allocated, add it to the list of active
576 // intervals.
577 if (success) {
578 active_.Add(current);
579 }
580 }
581}
582
583// Find a free register. If multiple are found, pick the register that
584// is free the longest.
585bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
586 size_t* free_until = registers_array_;
587
588 // First set all registers to be free.
589 for (size_t i = 0; i < number_of_registers_; ++i) {
590 free_until[i] = kMaxLifetimePosition;
591 }
592
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100593 // For each active interval, set its register to not free.
594 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
595 LiveInterval* interval = active_.Get(i);
596 DCHECK(interval->HasRegister());
597 free_until[interval->GetRegister()] = 0;
598 }
599
Mingyao Yang296bd602014-10-06 16:47:28 -0700600 // For each inactive interval, set its register to be free until
601 // the next intersection with `current`.
602 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
603 LiveInterval* inactive = inactive_.Get(i);
604 // Temp/Slow-path-safepoint interval has no holes.
605 DCHECK(!inactive->IsTemp() && !inactive->IsSlowPathSafepoint());
606 if (!current->IsSplit() && !inactive->IsFixed()) {
607 // Neither current nor inactive are fixed.
608 // Thanks to SSA, a non-split interval starting in a hole of an
609 // inactive interval should never intersect with that inactive interval.
610 // Only if it's not fixed though, because fixed intervals don't come from SSA.
611 DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
612 continue;
613 }
614
615 DCHECK(inactive->HasRegister());
616 if (free_until[inactive->GetRegister()] == 0) {
617 // Already used by some active interval. No need to intersect.
618 continue;
619 }
620 size_t next_intersection = inactive->FirstIntersectionWith(current);
621 if (next_intersection != kNoLifetime) {
622 free_until[inactive->GetRegister()] =
623 std::min(free_until[inactive->GetRegister()], next_intersection);
624 }
625 }
626
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100627 int reg = -1;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100628 if (current->HasRegister()) {
629 // Some instructions have a fixed register output.
630 reg = current->GetRegister();
631 DCHECK_NE(free_until[reg], 0u);
632 } else {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100633 int hint = current->FindFirstRegisterHint(free_until);
634 if (hint != kNoRegister) {
635 DCHECK(!IsBlocked(hint));
636 reg = hint;
637 } else {
638 // Pick the register that is free the longest.
639 for (size_t i = 0; i < number_of_registers_; ++i) {
640 if (IsBlocked(i)) continue;
641 if (reg == -1 || free_until[i] > free_until[reg]) {
642 reg = i;
643 if (free_until[i] == kMaxLifetimePosition) break;
644 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100645 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100646 }
647 }
648
649 // If we could not find a register, we need to spill.
650 if (reg == -1 || free_until[reg] == 0) {
651 return false;
652 }
653
654 current->SetRegister(reg);
655 if (!current->IsDeadAt(free_until[reg])) {
656 // If the register is only available for a subset of live ranges
657 // covered by `current`, split `current` at the position where
658 // the register is not available anymore.
659 LiveInterval* split = Split(current, free_until[reg]);
660 DCHECK(split != nullptr);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100661 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100662 }
663 return true;
664}
665
666bool RegisterAllocator::IsBlocked(int reg) const {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100667 return processing_core_registers_
668 ? blocked_core_registers_[reg]
669 : blocked_fp_registers_[reg];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100670}
671
672// Find the register that is used the last, and spill the interval
673// that holds it. If the first use of `current` is after that register
674// we spill `current` instead.
675bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
676 size_t first_register_use = current->FirstRegisterUse();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100677 if (first_register_use == kNoLifetime) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100678 AllocateSpillSlotFor(current);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100679 return false;
680 }
681
682 // First set all registers as not being used.
683 size_t* next_use = registers_array_;
684 for (size_t i = 0; i < number_of_registers_; ++i) {
685 next_use[i] = kMaxLifetimePosition;
686 }
687
688 // For each active interval, find the next use of its register after the
689 // start of current.
690 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
691 LiveInterval* active = active_.Get(i);
692 DCHECK(active->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100693 if (active->IsFixed()) {
694 next_use[active->GetRegister()] = current->GetStart();
695 } else {
696 size_t use = active->FirstRegisterUseAfter(current->GetStart());
697 if (use != kNoLifetime) {
698 next_use[active->GetRegister()] = use;
699 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100700 }
701 }
702
703 // For each inactive interval, find the next use of its register after the
704 // start of current.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100705 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
706 LiveInterval* inactive = inactive_.Get(i);
Mingyao Yang296bd602014-10-06 16:47:28 -0700707 // Temp/Slow-path-safepoint interval has no holes.
708 DCHECK(!inactive->IsTemp() && !inactive->IsSlowPathSafepoint());
709 if (!current->IsSplit() && !inactive->IsFixed()) {
710 // Neither current nor inactive are fixed.
711 // Thanks to SSA, a non-split interval starting in a hole of an
712 // inactive interval should never intersect with that inactive interval.
713 // Only if it's not fixed though, because fixed intervals don't come from SSA.
714 DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
715 continue;
716 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100717 DCHECK(inactive->HasRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100718 size_t next_intersection = inactive->FirstIntersectionWith(current);
719 if (next_intersection != kNoLifetime) {
720 if (inactive->IsFixed()) {
721 next_use[inactive->GetRegister()] =
722 std::min(next_intersection, next_use[inactive->GetRegister()]);
723 } else {
724 size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
725 if (use != kNoLifetime) {
726 next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
727 }
728 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100729 }
730 }
731
732 // Pick the register that is used the last.
733 int reg = -1;
734 for (size_t i = 0; i < number_of_registers_; ++i) {
735 if (IsBlocked(i)) continue;
736 if (reg == -1 || next_use[i] > next_use[reg]) {
737 reg = i;
738 if (next_use[i] == kMaxLifetimePosition) break;
739 }
740 }
741
742 if (first_register_use >= next_use[reg]) {
743 // If the first use of that instruction is after the last use of the found
744 // register, we split this interval just before its first register use.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100745 AllocateSpillSlotFor(current);
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100746 LiveInterval* split = Split(current, first_register_use - 1);
747 DCHECK_NE(current, split) << "There is not enough registers available for "
748 << split->GetParent()->GetDefinedBy()->DebugName();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100749 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100750 return false;
751 } else {
752 // Use this register and spill the active and inactives interval that
753 // have that register.
754 current->SetRegister(reg);
755
756 for (size_t i = 0, e = active_.Size(); i < e; ++i) {
757 LiveInterval* active = active_.Get(i);
758 if (active->GetRegister() == reg) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100759 DCHECK(!active->IsFixed());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100760 LiveInterval* split = Split(active, current->GetStart());
761 active_.DeleteAt(i);
762 handled_.Add(active);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100763 AddSorted(unhandled_, split);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100764 break;
765 }
766 }
767
Mingyao Yang296bd602014-10-06 16:47:28 -0700768 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100769 LiveInterval* inactive = inactive_.Get(i);
770 if (inactive->GetRegister() == reg) {
Mingyao Yang296bd602014-10-06 16:47:28 -0700771 if (!current->IsSplit() && !inactive->IsFixed()) {
772 // Neither current nor inactive are fixed.
773 // Thanks to SSA, a non-split interval starting in a hole of an
774 // inactive interval should never intersect with that inactive interval.
775 // Only if it's not fixed though, because fixed intervals don't come from SSA.
776 DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
777 continue;
778 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100779 size_t next_intersection = inactive->FirstIntersectionWith(current);
780 if (next_intersection != kNoLifetime) {
781 if (inactive->IsFixed()) {
782 LiveInterval* split = Split(current, next_intersection);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100783 AddSorted(unhandled_, split);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100784 } else {
Mingyao Yang296bd602014-10-06 16:47:28 -0700785 LiveInterval* split = Split(inactive, next_intersection);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100786 inactive_.DeleteAt(i);
Mingyao Yang296bd602014-10-06 16:47:28 -0700787 --i;
788 --e;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100789 handled_.Add(inactive);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100790 AddSorted(unhandled_, split);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100791 }
792 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100793 }
794 }
795
796 return true;
797 }
798}
799
Nicolas Geoffray39468442014-09-02 15:17:15 +0100800void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100801 DCHECK(!interval->IsFixed() && !interval->HasSpillSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100802 size_t insert_at = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100803 for (size_t i = array->Size(); i > 0; --i) {
804 LiveInterval* current = array->Get(i - 1);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100805 if (current->StartsAfter(interval)) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100806 insert_at = i;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100807 break;
Nicolas Geoffrayacd03392014-11-26 15:46:52 +0000808 } else if ((current->GetStart() == interval->GetStart()) && current->IsSlowPathSafepoint()) {
809 // Ensure the slow path interval is the last to be processed at its location: we want the
810 // interval to know all live registers at this location.
811 DCHECK(i == 1 || array->Get(i - 2)->StartsAfter(current));
812 insert_at = i;
813 break;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100814 }
815 }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100816 array->InsertAt(insert_at, interval);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100817}
818
819LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
820 DCHECK(position >= interval->GetStart());
821 DCHECK(!interval->IsDeadAt(position));
822 if (position == interval->GetStart()) {
823 // Spill slot will be allocated when handling `interval` again.
824 interval->ClearRegister();
825 return interval;
826 } else {
827 LiveInterval* new_interval = interval->SplitAt(position);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100828 return new_interval;
829 }
830}
831
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100832void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
833 LiveInterval* parent = interval->GetParent();
834
835 // An instruction gets a spill slot for its entire lifetime. If the parent
836 // of this interval already has a spill slot, there is nothing to do.
837 if (parent->HasSpillSlot()) {
838 return;
839 }
840
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100841 HInstruction* defined_by = parent->GetDefinedBy();
842 if (defined_by->IsParameterValue()) {
843 // Parameters have their own stack slot.
844 parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
845 return;
846 }
847
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100848 if (defined_by->IsConstant()) {
849 // Constants don't need a spill slot.
850 return;
851 }
852
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100853 LiveInterval* last_sibling = interval;
854 while (last_sibling->GetNextSibling() != nullptr) {
855 last_sibling = last_sibling->GetNextSibling();
856 }
857 size_t end = last_sibling->GetEnd();
858
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100859 // Find an available spill slot.
860 size_t slot = 0;
861 for (size_t e = spill_slots_.Size(); slot < e; ++slot) {
862 // We check if it is less rather than less or equal because the parallel move
863 // resolver does not work when a single spill slot needs to be exchanged with
864 // a double spill slot. The strict comparison avoids needing to exchange these
865 // locations at the same lifetime position.
866 if (spill_slots_.Get(slot) < parent->GetStart()
867 && (slot == (e - 1) || spill_slots_.Get(slot + 1) < parent->GetStart())) {
868 break;
869 }
870 }
871
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100872 if (parent->NeedsTwoSpillSlots()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100873 if (slot == spill_slots_.Size()) {
874 // We need a new spill slot.
875 spill_slots_.Add(end);
876 spill_slots_.Add(end);
877 } else if (slot == spill_slots_.Size() - 1) {
878 spill_slots_.Put(slot, end);
879 spill_slots_.Add(end);
880 } else {
881 spill_slots_.Put(slot, end);
882 spill_slots_.Put(slot + 1, end);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100883 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100884 } else {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100885 if (slot == spill_slots_.Size()) {
886 // We need a new spill slot.
887 spill_slots_.Add(end);
888 } else {
889 spill_slots_.Put(slot, end);
890 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100891 }
892
Nicolas Geoffray39468442014-09-02 15:17:15 +0100893 parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100894}
895
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100896static bool IsValidDestination(Location destination) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100897 return destination.IsRegister()
898 || destination.IsFpuRegister()
899 || destination.IsStackSlot()
900 || destination.IsDoubleStackSlot();
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100901}
902
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100903void RegisterAllocator::AddInputMoveFor(HInstruction* user,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100904 Location source,
905 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100906 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100907 if (source.Equals(destination)) return;
908
Roland Levillain476df552014-10-09 17:51:36 +0100909 DCHECK(!user->IsPhi());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100910
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100911 HInstruction* previous = user->GetPrevious();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100912 HParallelMove* move = nullptr;
913 if (previous == nullptr
Roland Levillain476df552014-10-09 17:51:36 +0100914 || !previous->IsParallelMove()
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100915 || previous->GetLifetimePosition() < user->GetLifetimePosition()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100916 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100917 move->SetLifetimePosition(user->GetLifetimePosition());
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100918 user->GetBlock()->InsertInstructionBefore(move, user);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100919 } else {
920 move = previous->AsParallelMove();
921 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100922 DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition());
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100923 move->AddMove(new (allocator_) MoveOperands(source, destination, nullptr));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100924}
925
Nicolas Geoffray46fbaab2014-11-26 18:30:23 +0000926static bool IsInstructionStart(size_t position) {
927 return (position & 1) == 0;
928}
929
930static bool IsInstructionEnd(size_t position) {
931 return (position & 1) == 1;
932}
933
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100934void RegisterAllocator::InsertParallelMoveAt(size_t position,
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100935 HInstruction* instruction,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100936 Location source,
937 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +0100938 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100939 if (source.Equals(destination)) return;
940
941 HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100942 HParallelMove* move;
Nicolas Geoffray46fbaab2014-11-26 18:30:23 +0000943 if (at == nullptr) {
944 if (IsInstructionStart(position)) {
945 // Block boundary, don't do anything the connection of split siblings will handle it.
946 return;
947 } else {
948 // Move must happen before the first instruction of the block.
949 at = liveness_.GetInstructionFromPosition((position + 1) / 2);
Nicolas Geoffray59768572014-12-01 09:50:04 +0000950 // Note that parallel moves may have already been inserted, so we explicitly
951 // ask for the first instruction of the block: `GetInstructionFromPosition` does
952 // not contain the moves.
953 at = at->GetBlock()->GetFirstInstruction();
954 if (at->GetLifetimePosition() != position) {
955 DCHECK_GT(at->GetLifetimePosition(), position);
Nicolas Geoffray46fbaab2014-11-26 18:30:23 +0000956 move = new (allocator_) HParallelMove(allocator_);
957 move->SetLifetimePosition(position);
958 at->GetBlock()->InsertInstructionBefore(move, at);
Nicolas Geoffray59768572014-12-01 09:50:04 +0000959 } else {
960 DCHECK(at->IsParallelMove());
961 move = at->AsParallelMove();
Nicolas Geoffray46fbaab2014-11-26 18:30:23 +0000962 }
963 }
964 } else if (IsInstructionEnd(position)) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100965 // Move must happen after the instruction.
966 DCHECK(!at->IsControlFlow());
967 move = at->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100968 // This is a parallel move for connecting siblings in a same block. We need to
969 // differentiate it with moves for connecting blocks, and input moves.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100970 if (move == nullptr || move->GetLifetimePosition() > position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100971 move = new (allocator_) HParallelMove(allocator_);
972 move->SetLifetimePosition(position);
973 at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
974 }
975 } else {
976 // Move must happen before the instruction.
977 HInstruction* previous = at->GetPrevious();
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100978 if (previous == nullptr
979 || !previous->IsParallelMove()
980 || previous->GetLifetimePosition() != position) {
981 // If the previous is a parallel move, then its position must be lower
982 // than the given `position`: it was added just after the non-parallel
983 // move instruction that precedes `instruction`.
984 DCHECK(previous == nullptr
985 || !previous->IsParallelMove()
986 || previous->GetLifetimePosition() < position);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100987 move = new (allocator_) HParallelMove(allocator_);
988 move->SetLifetimePosition(position);
989 at->GetBlock()->InsertInstructionBefore(move, at);
990 } else {
991 move = previous->AsParallelMove();
992 }
993 }
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100994 DCHECK_EQ(move->GetLifetimePosition(), position);
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100995 move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100996}
997
998void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
Nicolas Geoffray740475d2014-09-29 10:33:25 +0100999 HInstruction* instruction,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001000 Location source,
1001 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +01001002 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001003 if (source.Equals(destination)) return;
1004
1005 DCHECK_EQ(block->GetSuccessors().Size(), 1u);
1006 HInstruction* last = block->GetLastInstruction();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001007 // We insert moves at exit for phi predecessors and connecting blocks.
1008 // A block ending with an if cannot branch to a block with phis because
1009 // we do not allow critical edges. It can also not connect
1010 // a split interval between two blocks: the move has to happen in the successor.
1011 DCHECK(!last->IsIf());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001012 HInstruction* previous = last->GetPrevious();
1013 HParallelMove* move;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001014 // This is a parallel move for connecting blocks. We need to differentiate
1015 // it with moves for connecting siblings in a same block, and output moves.
Nicolas Geoffray59768572014-12-01 09:50:04 +00001016 size_t position = last->GetLifetimePosition();
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001017 if (previous == nullptr || !previous->IsParallelMove()
Nicolas Geoffray59768572014-12-01 09:50:04 +00001018 || previous->AsParallelMove()->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001019 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffray59768572014-12-01 09:50:04 +00001020 move->SetLifetimePosition(position);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001021 block->InsertInstructionBefore(move, last);
1022 } else {
1023 move = previous->AsParallelMove();
1024 }
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001025 move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001026}
1027
1028void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001029 HInstruction* instruction,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001030 Location source,
1031 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +01001032 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001033 if (source.Equals(destination)) return;
1034
1035 HInstruction* first = block->GetFirstInstruction();
1036 HParallelMove* move = first->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001037 // This is a parallel move for connecting blocks. We need to differentiate
1038 // it with moves for connecting siblings in a same block, and input moves.
1039 if (move == nullptr || move->GetLifetimePosition() != block->GetLifetimeStart()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001040 move = new (allocator_) HParallelMove(allocator_);
1041 move->SetLifetimePosition(block->GetLifetimeStart());
1042 block->InsertInstructionBefore(move, first);
1043 }
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001044 move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001045}
1046
1047void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
1048 Location source,
1049 Location destination) const {
Nicolas Geoffray2a877f32014-09-10 10:49:34 +01001050 DCHECK(IsValidDestination(destination));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001051 if (source.Equals(destination)) return;
1052
Roland Levillain476df552014-10-09 17:51:36 +01001053 if (instruction->IsPhi()) {
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001054 InsertParallelMoveAtEntryOf(instruction->GetBlock(), instruction, source, destination);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001055 return;
1056 }
1057
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001058 size_t position = instruction->GetLifetimePosition() + 1;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001059 HParallelMove* move = instruction->GetNext()->AsParallelMove();
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001060 // This is a parallel move for moving the output of an instruction. We need
1061 // to differentiate with input moves, moves for connecting siblings in a
1062 // and moves for connecting blocks.
1063 if (move == nullptr || move->GetLifetimePosition() != position) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001064 move = new (allocator_) HParallelMove(allocator_);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001065 move->SetLifetimePosition(position);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001066 instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
1067 }
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001068 move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001069}
1070
1071void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
1072 LiveInterval* current = interval;
1073 if (current->HasSpillSlot() && current->HasRegister()) {
1074 // We spill eagerly, so move must be at definition.
1075 InsertMoveAfter(interval->GetDefinedBy(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001076 interval->IsFloatingPoint()
1077 ? Location::FpuRegisterLocation(interval->GetRegister())
1078 : Location::RegisterLocation(interval->GetRegister()),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001079 interval->NeedsTwoSpillSlots()
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001080 ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
1081 : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001082 }
1083 UsePosition* use = current->GetFirstUse();
1084
1085 // Walk over all siblings, updating locations of use positions, and
1086 // connecting them when they are adjacent.
1087 do {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001088 Location source = current->ToLocation();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001089
1090 // Walk over all uses covered by this interval, and update the location
1091 // information.
1092 while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001093 LocationSummary* locations = use->GetUser()->GetLocations();
1094 if (use->GetIsEnvironment()) {
1095 locations->SetEnvironmentAt(use->GetInputIndex(), source);
1096 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001097 Location expected_location = locations->InAt(use->GetInputIndex());
1098 if (expected_location.IsUnallocated()) {
1099 locations->SetInAt(use->GetInputIndex(), source);
Nicolas Geoffray2a877f32014-09-10 10:49:34 +01001100 } else if (!expected_location.IsConstant()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001101 AddInputMoveFor(use->GetUser(), source, expected_location);
1102 }
1103 }
1104 use = use->GetNext();
1105 }
1106
1107 // If the next interval starts just after this one, and has a register,
1108 // insert a move.
1109 LiveInterval* next_sibling = current->GetNextSibling();
1110 if (next_sibling != nullptr
1111 && next_sibling->HasRegister()
1112 && current->GetEnd() == next_sibling->GetStart()) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001113 Location destination = next_sibling->ToLocation();
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001114 InsertParallelMoveAt(current->GetEnd(), interval->GetDefinedBy(), source, destination);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001115 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001116
1117 // At each safepoint, we record stack and register information.
1118 for (size_t i = 0, e = safepoints_.Size(); i < e; ++i) {
1119 HInstruction* safepoint = safepoints_.Get(i);
1120 size_t position = safepoint->GetLifetimePosition();
1121 LocationSummary* locations = safepoint->GetLocations();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00001122 if (!current->Covers(position)) {
1123 continue;
1124 }
1125 if (interval->GetStart() == position) {
1126 // The safepoint is for this instruction, so the location of the instruction
1127 // does not need to be saved.
1128 continue;
1129 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001130
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001131 if ((current->GetType() == Primitive::kPrimNot) && current->GetParent()->HasSpillSlot()) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001132 locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
1133 }
1134
1135 switch (source.GetKind()) {
1136 case Location::kRegister: {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001137 locations->AddLiveRegister(source);
Nicolas Geoffray87d03762014-11-19 15:17:56 +00001138 DCHECK_LE(locations->GetNumberOfLiveRegisters(), maximum_number_of_live_registers_);
Nicolas Geoffrayacd03392014-11-26 15:46:52 +00001139
Nicolas Geoffray39468442014-09-02 15:17:15 +01001140 if (current->GetType() == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001141 locations->SetRegisterBit(source.reg());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001142 }
1143 break;
1144 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001145 case Location::kFpuRegister: {
1146 locations->AddLiveRegister(source);
1147 break;
1148 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001149 case Location::kStackSlot: // Fall-through
1150 case Location::kDoubleStackSlot: // Fall-through
1151 case Location::kConstant: {
1152 // Nothing to do.
1153 break;
1154 }
1155 default: {
1156 LOG(FATAL) << "Unexpected location for object";
1157 }
1158 }
1159 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001160 current = next_sibling;
1161 } while (current != nullptr);
1162 DCHECK(use == nullptr);
1163}
1164
1165void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
1166 HBasicBlock* from,
1167 HBasicBlock* to) const {
1168 if (interval->GetNextSibling() == nullptr) {
1169 // Nothing to connect. The whole range was allocated to the same location.
1170 return;
1171 }
1172
Nicolas Geoffray46fbaab2014-11-26 18:30:23 +00001173 // Intervals end at the lifetime end of a block. The decrement by one
1174 // ensures the `Cover` call will return true.
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001175 size_t from_position = from->GetLifetimeEnd() - 1;
Nicolas Geoffray46fbaab2014-11-26 18:30:23 +00001176 size_t to_position = to->GetLifetimeStart();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001177
1178 LiveInterval* destination = nullptr;
1179 LiveInterval* source = nullptr;
1180
1181 LiveInterval* current = interval;
1182
1183 // Check the intervals that cover `from` and `to`.
1184 while ((current != nullptr) && (source == nullptr || destination == nullptr)) {
1185 if (current->Covers(from_position)) {
1186 DCHECK(source == nullptr);
1187 source = current;
1188 }
1189 if (current->Covers(to_position)) {
1190 DCHECK(destination == nullptr);
1191 destination = current;
1192 }
1193
1194 current = current->GetNextSibling();
1195 }
1196
1197 if (destination == source) {
1198 // Interval was not split.
1199 return;
1200 }
1201
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +01001202 DCHECK(destination != nullptr && source != nullptr);
1203
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001204 if (!destination->HasRegister()) {
1205 // Values are eagerly spilled. Spill slot already contains appropriate value.
1206 return;
1207 }
1208
1209 // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
1210 // we need to put the moves at the entry of `to`.
1211 if (from->GetSuccessors().Size() == 1) {
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001212 InsertParallelMoveAtExitOf(from,
1213 interval->GetParent()->GetDefinedBy(),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001214 source->ToLocation(),
1215 destination->ToLocation());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001216 } else {
1217 DCHECK_EQ(to->GetPredecessors().Size(), 1u);
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001218 InsertParallelMoveAtEntryOf(to,
1219 interval->GetParent()->GetDefinedBy(),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001220 source->ToLocation(),
1221 destination->ToLocation());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001222 }
1223}
1224
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001225void RegisterAllocator::Resolve() {
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001226 codegen_->ComputeFrameSize(
1227 spill_slots_.Size(), maximum_number_of_live_registers_, reserved_out_slots_);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001228
1229 // Adjust the Out Location of instructions.
1230 // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
1231 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1232 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1233 LiveInterval* current = instruction->GetLiveInterval();
1234 LocationSummary* locations = instruction->GetLocations();
1235 Location location = locations->Out();
Roland Levillain476df552014-10-09 17:51:36 +01001236 if (instruction->IsParameterValue()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001237 // Now that we know the frame size, adjust the parameter's location.
1238 if (location.IsStackSlot()) {
1239 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1240 current->SetSpillSlot(location.GetStackIndex());
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001241 locations->UpdateOut(location);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001242 } else if (location.IsDoubleStackSlot()) {
1243 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1244 current->SetSpillSlot(location.GetStackIndex());
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001245 locations->UpdateOut(location);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001246 } else if (current->HasSpillSlot()) {
1247 current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
1248 }
1249 }
1250
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001251 Location source = current->ToLocation();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001252
1253 if (location.IsUnallocated()) {
1254 if (location.GetPolicy() == Location::kSameAsFirstInput) {
Calin Juravled0d48522014-11-04 16:40:20 +00001255 if (locations->InAt(0).IsUnallocated()) {
1256 locations->SetInAt(0, source);
1257 } else {
1258 DCHECK(locations->InAt(0).Equals(source));
1259 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001260 }
1261 locations->SetOut(source);
1262 } else {
1263 DCHECK(source.Equals(location));
1264 }
1265 }
1266
1267 // Connect siblings.
1268 for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
1269 HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
1270 ConnectSiblings(instruction->GetLiveInterval());
1271 }
1272
1273 // Resolve non-linear control flow across branches. Order does not matter.
1274 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
1275 HBasicBlock* block = it.Current();
1276 BitVector* live = liveness_.GetLiveInSet(*block);
1277 for (uint32_t idx : live->Indexes()) {
1278 HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
1279 LiveInterval* interval = current->GetLiveInterval();
1280 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
1281 ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
1282 }
1283 }
1284 }
1285
1286 // Resolve phi inputs. Order does not matter.
1287 for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
1288 HBasicBlock* current = it.Current();
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001289 for (HInstructionIterator inst_it(current->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
1290 HInstruction* phi = inst_it.Current();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001291 for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
1292 HBasicBlock* predecessor = current->GetPredecessors().Get(i);
1293 DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
1294 HInstruction* input = phi->InputAt(i);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001295 Location source = input->GetLiveInterval()->GetLocationAt(
1296 predecessor->GetLifetimeEnd() - 1);
1297 Location destination = phi->GetLiveInterval()->ToLocation();
Nicolas Geoffray740475d2014-09-29 10:33:25 +01001298 InsertParallelMoveAtExitOf(predecessor, nullptr, source, destination);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001299 }
1300 }
1301 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001302
1303 // Assign temp locations.
1304 HInstruction* current = nullptr;
1305 size_t temp_index = 0;
1306 for (size_t i = 0; i < temp_intervals_.Size(); ++i) {
1307 LiveInterval* temp = temp_intervals_.Get(i);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001308 HInstruction* at = liveness_.GetTempUser(temp);
1309 if (at != current) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001310 temp_index = 0;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001311 current = at;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001312 }
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001313 LocationSummary* locations = at->GetLocations();
Roland Levillain5368c212014-11-27 15:03:41 +00001314 switch (temp->GetType()) {
1315 case Primitive::kPrimInt:
1316 locations->SetTempAt(
1317 temp_index++, Location::RegisterLocation(temp->GetRegister()));
1318 break;
1319
1320 case Primitive::kPrimDouble:
1321 // TODO: Support the case of ARM, where a double value
1322 // requires an FPU register pair (note that the ARM back end
1323 // does not yet use this register allocator when a method uses
1324 // floats or doubles).
1325 DCHECK(codegen_->GetInstructionSet() != kArm
1326 && codegen_->GetInstructionSet() != kThumb2);
1327 locations->SetTempAt(
1328 temp_index++, Location::FpuRegisterLocation(temp->GetRegister()));
1329 break;
1330
1331 default:
1332 LOG(FATAL) << "Unexpected type for temporary location "
1333 << temp->GetType();
1334 }
Nicolas Geoffray39468442014-09-02 15:17:15 +01001335 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001336}
1337
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001338} // namespace art