blob: ece990442653ee5b73f4a40c1643900196f22d75 [file] [log] [blame]
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "register_allocator.h"
18
19#include <iostream>
20#include <sstream>
21
Vladimir Markoe764d2e2017-10-05 14:35:55 +010022#include "base/scoped_arena_allocator.h"
23#include "base/scoped_arena_containers.h"
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070024#include "base/bit_vector-inl.h"
25#include "code_generator.h"
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -070026#include "register_allocator_graph_color.h"
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070027#include "register_allocator_linear_scan.h"
28#include "ssa_liveness_analysis.h"
29
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070030namespace art {
31
Vladimir Markoe764d2e2017-10-05 14:35:55 +010032RegisterAllocator::RegisterAllocator(ScopedArenaAllocator* allocator,
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070033 CodeGenerator* codegen,
34 const SsaLivenessAnalysis& liveness)
35 : allocator_(allocator),
36 codegen_(codegen),
37 liveness_(liveness) {}
38
Vladimir Markoe764d2e2017-10-05 14:35:55 +010039std::unique_ptr<RegisterAllocator> RegisterAllocator::Create(ScopedArenaAllocator* allocator,
40 CodeGenerator* codegen,
41 const SsaLivenessAnalysis& analysis,
42 Strategy strategy) {
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070043 switch (strategy) {
44 case kRegisterAllocatorLinearScan:
Vladimir Markoe764d2e2017-10-05 14:35:55 +010045 return std::unique_ptr<RegisterAllocator>(
46 new (allocator) RegisterAllocatorLinearScan(allocator, codegen, analysis));
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -070047 case kRegisterAllocatorGraphColor:
Vladimir Markoe764d2e2017-10-05 14:35:55 +010048 return std::unique_ptr<RegisterAllocator>(
49 new (allocator) RegisterAllocatorGraphColor(allocator, codegen, analysis));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070050 default:
51 LOG(FATAL) << "Invalid register allocation strategy: " << strategy;
52 UNREACHABLE();
53 }
54}
55
56bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph ATTRIBUTE_UNUSED,
57 InstructionSet instruction_set) {
58 return instruction_set == kArm
59 || instruction_set == kArm64
60 || instruction_set == kMips
61 || instruction_set == kMips64
62 || instruction_set == kThumb2
63 || instruction_set == kX86
64 || instruction_set == kX86_64;
65}
66
67class AllRangesIterator : public ValueObject {
68 public:
69 explicit AllRangesIterator(LiveInterval* interval)
70 : current_interval_(interval),
71 current_range_(interval->GetFirstRange()) {}
72
73 bool Done() const { return current_interval_ == nullptr; }
74 LiveRange* CurrentRange() const { return current_range_; }
75 LiveInterval* CurrentInterval() const { return current_interval_; }
76
77 void Advance() {
78 current_range_ = current_range_->GetNext();
79 if (current_range_ == nullptr) {
80 current_interval_ = current_interval_->GetNextSibling();
81 if (current_interval_ != nullptr) {
82 current_range_ = current_interval_->GetFirstRange();
83 }
84 }
85 }
86
87 private:
88 LiveInterval* current_interval_;
89 LiveRange* current_range_;
90
91 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
92};
93
Vladimir Markoe764d2e2017-10-05 14:35:55 +010094bool RegisterAllocator::ValidateIntervals(ArrayRef<LiveInterval* const> intervals,
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070095 size_t number_of_spill_slots,
96 size_t number_of_out_slots,
97 const CodeGenerator& codegen,
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070098 bool processing_core_registers,
99 bool log_fatal_on_failure) {
100 size_t number_of_registers = processing_core_registers
101 ? codegen.GetNumberOfCoreRegisters()
102 : codegen.GetNumberOfFloatingPointRegisters();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100103 ScopedArenaAllocator allocator(codegen.GetGraph()->GetArenaStack());
104 ScopedArenaVector<ArenaBitVector*> liveness_of_values(
105 allocator.Adapter(kArenaAllocRegisterAllocatorValidate));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700106 liveness_of_values.reserve(number_of_registers + number_of_spill_slots);
107
108 size_t max_end = 0u;
109 for (LiveInterval* start_interval : intervals) {
110 for (AllRangesIterator it(start_interval); !it.Done(); it.Advance()) {
111 max_end = std::max(max_end, it.CurrentRange()->GetEnd());
112 }
113 }
114
115 // Allocate a bit vector per register. A live interval that has a register
116 // allocated will populate the associated bit vector based on its live ranges.
117 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
118 liveness_of_values.push_back(
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100119 ArenaBitVector::Create(&allocator, max_end, false, kArenaAllocRegisterAllocatorValidate));
120 liveness_of_values.back()->ClearAllBits();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700121 }
122
123 for (LiveInterval* start_interval : intervals) {
124 for (AllRangesIterator it(start_interval); !it.Done(); it.Advance()) {
125 LiveInterval* current = it.CurrentInterval();
126 HInstruction* defined_by = current->GetParent()->GetDefinedBy();
127 if (current->GetParent()->HasSpillSlot()
128 // Parameters and current method have their own stack slot.
129 && !(defined_by != nullptr && (defined_by->IsParameterValue()
130 || defined_by->IsCurrentMethod()))) {
131 BitVector* liveness_of_spill_slot = liveness_of_values[number_of_registers
132 + current->GetParent()->GetSpillSlot() / kVRegSize
133 - number_of_out_slots];
134 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
135 if (liveness_of_spill_slot->IsBitSet(j)) {
136 if (log_fatal_on_failure) {
137 std::ostringstream message;
138 message << "Spill slot conflict at " << j;
139 LOG(FATAL) << message.str();
140 } else {
141 return false;
142 }
143 } else {
144 liveness_of_spill_slot->SetBit(j);
145 }
146 }
147 }
148
149 if (current->HasRegister()) {
150 if (kIsDebugBuild && log_fatal_on_failure && !current->IsFixed()) {
151 // Only check when an error is fatal. Only tests code ask for non-fatal failures
152 // and test code may not properly fill the right information to the code generator.
153 CHECK(codegen.HasAllocatedRegister(processing_core_registers, current->GetRegister()));
154 }
155 BitVector* liveness_of_register = liveness_of_values[current->GetRegister()];
156 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
157 if (liveness_of_register->IsBitSet(j)) {
158 if (current->IsUsingInputRegister() && current->CanUseInputRegister()) {
159 continue;
160 }
161 if (log_fatal_on_failure) {
162 std::ostringstream message;
163 message << "Register conflict at " << j << " ";
164 if (defined_by != nullptr) {
165 message << "(" << defined_by->DebugName() << ")";
166 }
167 message << "for ";
168 if (processing_core_registers) {
169 codegen.DumpCoreRegister(message, current->GetRegister());
170 } else {
171 codegen.DumpFloatingPointRegister(message, current->GetRegister());
172 }
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700173 for (LiveInterval* interval : intervals) {
174 if (interval->HasRegister()
175 && interval->GetRegister() == current->GetRegister()
176 && interval->CoversSlow(j)) {
177 message << std::endl;
178 if (interval->GetDefinedBy() != nullptr) {
179 message << interval->GetDefinedBy()->GetKind() << " ";
180 } else {
181 message << "physical ";
182 }
183 interval->Dump(message);
184 }
185 }
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700186 LOG(FATAL) << message.str();
187 } else {
188 return false;
189 }
190 } else {
191 liveness_of_register->SetBit(j);
192 }
193 }
194 }
195 }
196 }
197 return true;
198}
199
200LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
201 DCHECK_GE(position, interval->GetStart());
202 DCHECK(!interval->IsDeadAt(position));
203 if (position == interval->GetStart()) {
204 // Spill slot will be allocated when handling `interval` again.
205 interval->ClearRegister();
206 if (interval->HasHighInterval()) {
207 interval->GetHighInterval()->ClearRegister();
208 } else if (interval->HasLowInterval()) {
209 interval->GetLowInterval()->ClearRegister();
210 }
211 return interval;
212 } else {
213 LiveInterval* new_interval = interval->SplitAt(position);
214 if (interval->HasHighInterval()) {
215 LiveInterval* high = interval->GetHighInterval()->SplitAt(position);
216 new_interval->SetHighInterval(high);
217 high->SetLowInterval(new_interval);
218 } else if (interval->HasLowInterval()) {
219 LiveInterval* low = interval->GetLowInterval()->SplitAt(position);
220 new_interval->SetLowInterval(low);
221 low->SetHighInterval(new_interval);
222 }
223 return new_interval;
224 }
225}
226
227LiveInterval* RegisterAllocator::SplitBetween(LiveInterval* interval, size_t from, size_t to) {
228 HBasicBlock* block_from = liveness_.GetBlockFromPosition(from / 2);
229 HBasicBlock* block_to = liveness_.GetBlockFromPosition(to / 2);
230 DCHECK(block_from != nullptr);
231 DCHECK(block_to != nullptr);
232
233 // Both locations are in the same block. We split at the given location.
234 if (block_from == block_to) {
235 return Split(interval, to);
236 }
237
238 /*
239 * Non-linear control flow will force moves at every branch instruction to the new location.
240 * To avoid having all branches doing the moves, we find the next non-linear position and
241 * split the interval at this position. Take the following example (block number is the linear
242 * order position):
243 *
244 * B1
245 * / \
246 * B2 B3
247 * \ /
248 * B4
249 *
250 * B2 needs to split an interval, whose next use is in B4. If we were to split at the
251 * beginning of B4, B3 would need to do a move between B3 and B4 to ensure the interval
252 * is now in the correct location. It makes performance worst if the interval is spilled
253 * and both B2 and B3 need to reload it before entering B4.
254 *
255 * By splitting at B3, we give a chance to the register allocator to allocate the
256 * interval to the same register as in B1, and therefore avoid doing any
257 * moves in B3.
258 */
259 if (block_from->GetDominator() != nullptr) {
260 for (HBasicBlock* dominated : block_from->GetDominator()->GetDominatedBlocks()) {
261 size_t position = dominated->GetLifetimeStart();
262 if ((position > from) && (block_to->GetLifetimeStart() > position)) {
263 // Even if we found a better block, we continue iterating in case
264 // a dominated block is closer.
265 // Note that dominated blocks are not sorted in liveness order.
266 block_to = dominated;
267 DCHECK_NE(block_to, block_from);
268 }
269 }
270 }
271
272 // If `to` is in a loop, find the outermost loop header which does not contain `from`.
273 for (HLoopInformationOutwardIterator it(*block_to); !it.Done(); it.Advance()) {
274 HBasicBlock* header = it.Current()->GetHeader();
275 if (block_from->GetLifetimeStart() >= header->GetLifetimeStart()) {
276 break;
277 }
278 block_to = header;
279 }
280
281 // Split at the start of the found block, to piggy back on existing moves
282 // due to resolution if non-linear control flow (see `ConnectSplitSiblings`).
283 return Split(interval, block_to->GetLifetimeStart());
284}
285
286} // namespace art