register_allocator.cc revision 31d76b42ef5165351499da3f8ee0ac147428c5ed
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "register_allocator.h" 18 19#include "code_generator.h" 20#include "ssa_liveness_analysis.h" 21 22namespace art { 23 24static constexpr size_t kMaxLifetimePosition = -1; 25static constexpr size_t kDefaultNumberOfSpillSlots = 4; 26 27RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator, const CodeGenerator& codegen) 28 : allocator_(allocator), 29 codegen_(codegen), 30 unhandled_(allocator, 0), 31 handled_(allocator, 0), 32 active_(allocator, 0), 33 inactive_(allocator, 0), 34 spill_slots_(allocator, kDefaultNumberOfSpillSlots), 35 processing_core_registers_(false), 36 number_of_registers_(-1), 37 registers_array_(nullptr), 38 blocked_registers_(allocator->AllocArray<bool>(codegen.GetNumberOfRegisters())) { 39 codegen.SetupBlockedRegisters(blocked_registers_); 40} 41 42static bool ShouldProcess(bool processing_core_registers, HInstruction* instruction) { 43 bool is_core_register = (instruction->GetType() != Primitive::kPrimDouble) 44 && (instruction->GetType() != Primitive::kPrimFloat); 45 return processing_core_registers == is_core_register; 46} 47 48void RegisterAllocator::AllocateRegistersInternal(const SsaLivenessAnalysis& liveness) { 49 number_of_registers_ = processing_core_registers_ 50 ? codegen_.GetNumberOfCoreRegisters() 51 : codegen_.GetNumberOfFloatingPointRegisters(); 52 53 registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_); 54 55 // Iterate post-order, to ensure the list is sorted, and the last added interval 56 // is the one with the lowest start position. 57 for (size_t i = liveness.GetNumberOfSsaValues(); i > 0; --i) { 58 HInstruction* instruction = liveness.GetInstructionFromSsaIndex(i - 1); 59 if (ShouldProcess(processing_core_registers_, instruction)) { 60 LiveInterval* current = instruction->GetLiveInterval(); 61 DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek())); 62 unhandled_.Add(current); 63 } 64 } 65 66 LinearScan(); 67 if (kIsDebugBuild) { 68 ValidateInternal(liveness, true); 69 } 70} 71 72bool RegisterAllocator::ValidateInternal(const SsaLivenessAnalysis& liveness, 73 bool log_fatal_on_failure) const { 74 // To simplify unit testing, we eagerly create the array of intervals, and 75 // call the helper method. 76 GrowableArray<LiveInterval*> intervals(allocator_, 0); 77 for (size_t i = 0; i < liveness.GetNumberOfSsaValues(); ++i) { 78 HInstruction* instruction = liveness.GetInstructionFromSsaIndex(i); 79 if (ShouldProcess(processing_core_registers_, instruction)) { 80 intervals.Add(instruction->GetLiveInterval()); 81 } 82 } 83 return ValidateIntervals(intervals, spill_slots_.Size(), codegen_, allocator_, 84 processing_core_registers_, log_fatal_on_failure); 85} 86 87class AllRangesIterator : public ValueObject { 88 public: 89 explicit AllRangesIterator(LiveInterval* interval) 90 : current_interval_(interval), 91 current_range_(interval->GetFirstRange()) {} 92 93 bool Done() const { return current_interval_ == nullptr; } 94 LiveRange* CurrentRange() const { return current_range_; } 95 LiveInterval* CurrentInterval() const { return current_interval_; } 96 97 void Advance() { 98 current_range_ = current_range_->GetNext(); 99 if (current_range_ == nullptr) { 100 current_interval_ = current_interval_->GetNextSibling(); 101 if (current_interval_ != nullptr) { 102 current_range_ = current_interval_->GetFirstRange(); 103 } 104 } 105 } 106 107 private: 108 LiveInterval* current_interval_; 109 LiveRange* current_range_; 110 111 DISALLOW_COPY_AND_ASSIGN(AllRangesIterator); 112}; 113 114bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals, 115 size_t number_of_spill_slots, 116 const CodeGenerator& codegen, 117 ArenaAllocator* allocator, 118 bool processing_core_registers, 119 bool log_fatal_on_failure) { 120 size_t number_of_registers = processing_core_registers 121 ? codegen.GetNumberOfCoreRegisters() 122 : codegen.GetNumberOfFloatingPointRegisters(); 123 GrowableArray<ArenaBitVector*> liveness_of_values( 124 allocator, number_of_registers + number_of_spill_slots); 125 126 // Allocate a bit vector per register. A live interval that has a register 127 // allocated will populate the associated bit vector based on its live ranges. 128 for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) { 129 liveness_of_values.Add(new (allocator) ArenaBitVector(allocator, 0, true)); 130 } 131 132 for (size_t i = 0, e = intervals.Size(); i < e; ++i) { 133 for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) { 134 LiveInterval* current = it.CurrentInterval(); 135 if (current->GetParent()->HasSpillSlot()) { 136 BitVector* liveness_of_spill_slot = liveness_of_values.Get( 137 number_of_registers + current->GetParent()->GetSpillSlot() / kVRegSize); 138 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) { 139 if (liveness_of_spill_slot->IsBitSet(j)) { 140 if (log_fatal_on_failure) { 141 std::ostringstream message; 142 message << "Spill slot conflict at " << j; 143 LOG(FATAL) << message.str(); 144 } else { 145 return false; 146 } 147 } else { 148 liveness_of_spill_slot->SetBit(j); 149 } 150 } 151 } 152 153 if (current->HasRegister()) { 154 BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister()); 155 for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) { 156 if (liveness_of_register->IsBitSet(j)) { 157 if (log_fatal_on_failure) { 158 std::ostringstream message; 159 message << "Register conflict at " << j << " for "; 160 if (processing_core_registers) { 161 codegen.DumpCoreRegister(message, current->GetRegister()); 162 } else { 163 codegen.DumpFloatingPointRegister(message, current->GetRegister()); 164 } 165 LOG(FATAL) << message.str(); 166 } else { 167 return false; 168 } 169 } else { 170 liveness_of_register->SetBit(j); 171 } 172 } 173 } 174 } 175 } 176 return true; 177} 178 179void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) { 180 interval->Dump(stream); 181 stream << ": "; 182 if (interval->HasRegister()) { 183 if (processing_core_registers_) { 184 codegen_.DumpCoreRegister(stream, interval->GetRegister()); 185 } else { 186 codegen_.DumpFloatingPointRegister(stream, interval->GetRegister()); 187 } 188 } else { 189 stream << "spilled"; 190 } 191 stream << std::endl; 192} 193 194// By the book implementation of a linear scan register allocator. 195void RegisterAllocator::LinearScan() { 196 while (!unhandled_.IsEmpty()) { 197 // (1) Remove interval with the lowest start position from unhandled. 198 LiveInterval* current = unhandled_.Pop(); 199 size_t position = current->GetStart(); 200 201 // (2) Remove currently active intervals that are dead at this position. 202 // Move active intervals that have a lifetime hole at this position 203 // to inactive. 204 for (size_t i = 0; i < active_.Size(); ++i) { 205 LiveInterval* interval = active_.Get(i); 206 if (interval->IsDeadAt(position)) { 207 active_.Delete(interval); 208 --i; 209 handled_.Add(interval); 210 } else if (!interval->Covers(position)) { 211 active_.Delete(interval); 212 --i; 213 inactive_.Add(interval); 214 } 215 } 216 217 // (3) Remove currently inactive intervals that are dead at this position. 218 // Move inactive intervals that cover this position to active. 219 for (size_t i = 0; i < inactive_.Size(); ++i) { 220 LiveInterval* interval = inactive_.Get(i); 221 if (interval->IsDeadAt(position)) { 222 inactive_.Delete(interval); 223 --i; 224 handled_.Add(interval); 225 } else if (interval->Covers(position)) { 226 inactive_.Delete(interval); 227 --i; 228 active_.Add(interval); 229 } 230 } 231 232 // (4) Try to find an available register. 233 bool success = TryAllocateFreeReg(current); 234 235 // (5) If no register could be found, we need to spill. 236 if (!success) { 237 success = AllocateBlockedReg(current); 238 } 239 240 // (6) If the interval had a register allocated, add it to the list of active 241 // intervals. 242 if (success) { 243 active_.Add(current); 244 } 245 } 246} 247 248// Find a free register. If multiple are found, pick the register that 249// is free the longest. 250bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) { 251 size_t* free_until = registers_array_; 252 253 // First set all registers to be free. 254 for (size_t i = 0; i < number_of_registers_; ++i) { 255 free_until[i] = kMaxLifetimePosition; 256 } 257 258 // For each active interval, set its register to not free. 259 for (size_t i = 0, e = active_.Size(); i < e; ++i) { 260 LiveInterval* interval = active_.Get(i); 261 DCHECK(interval->HasRegister()); 262 free_until[interval->GetRegister()] = 0; 263 } 264 265 // For each inactive interval, set its register to be free until 266 // the next intersection with `current`. 267 // Thanks to SSA, this should only be needed for intervals 268 // that are the result of a split. 269 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) { 270 LiveInterval* inactive = inactive_.Get(i); 271 DCHECK(inactive->HasRegister()); 272 size_t next_intersection = inactive->FirstIntersectionWith(current); 273 if (next_intersection != kNoLifetime) { 274 free_until[inactive->GetRegister()] = next_intersection; 275 } 276 } 277 278 // Pick the register that is free the longest. 279 int reg = -1; 280 for (size_t i = 0; i < number_of_registers_; ++i) { 281 if (IsBlocked(i)) continue; 282 if (reg == -1 || free_until[i] > free_until[reg]) { 283 reg = i; 284 if (free_until[i] == kMaxLifetimePosition) break; 285 } 286 } 287 288 // If we could not find a register, we need to spill. 289 if (reg == -1 || free_until[reg] == 0) { 290 return false; 291 } 292 293 current->SetRegister(reg); 294 if (!current->IsDeadAt(free_until[reg])) { 295 // If the register is only available for a subset of live ranges 296 // covered by `current`, split `current` at the position where 297 // the register is not available anymore. 298 LiveInterval* split = Split(current, free_until[reg]); 299 DCHECK(split != nullptr); 300 AddToUnhandled(split); 301 } 302 return true; 303} 304 305bool RegisterAllocator::IsBlocked(int reg) const { 306 // TODO: This only works for core registers and needs to be adjusted for 307 // floating point registers. 308 DCHECK(processing_core_registers_); 309 return blocked_registers_[reg]; 310} 311 312// Find the register that is used the last, and spill the interval 313// that holds it. If the first use of `current` is after that register 314// we spill `current` instead. 315bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) { 316 size_t first_register_use = current->FirstRegisterUse(); 317 if (current->FirstRegisterUse() == kNoLifetime) { 318 AllocateSpillSlotFor(current); 319 return false; 320 } 321 322 // First set all registers as not being used. 323 size_t* next_use = registers_array_; 324 for (size_t i = 0; i < number_of_registers_; ++i) { 325 next_use[i] = kMaxLifetimePosition; 326 } 327 328 // For each active interval, find the next use of its register after the 329 // start of current. 330 for (size_t i = 0, e = active_.Size(); i < e; ++i) { 331 LiveInterval* active = active_.Get(i); 332 DCHECK(active->HasRegister()); 333 size_t use = active->FirstRegisterUseAfter(current->GetStart()); 334 if (use != kNoLifetime) { 335 next_use[active->GetRegister()] = use; 336 } 337 } 338 339 // For each inactive interval, find the next use of its register after the 340 // start of current. 341 // Thanks to SSA, this should only be needed for intervals 342 // that are the result of a split. 343 for (size_t i = 0, e = inactive_.Size(); i < e; ++i) { 344 LiveInterval* inactive = inactive_.Get(i); 345 DCHECK(inactive->HasRegister()); 346 size_t use = inactive->FirstRegisterUseAfter(current->GetStart()); 347 if (use != kNoLifetime) { 348 next_use[inactive->GetRegister()] = use; 349 } 350 } 351 352 // Pick the register that is used the last. 353 int reg = -1; 354 for (size_t i = 0; i < number_of_registers_; ++i) { 355 if (IsBlocked(i)) continue; 356 if (reg == -1 || next_use[i] > next_use[reg]) { 357 reg = i; 358 if (next_use[i] == kMaxLifetimePosition) break; 359 } 360 } 361 362 if (first_register_use >= next_use[reg]) { 363 // If the first use of that instruction is after the last use of the found 364 // register, we split this interval just before its first register use. 365 AllocateSpillSlotFor(current); 366 LiveInterval* split = Split(current, first_register_use - 1); 367 AddToUnhandled(split); 368 return false; 369 } else { 370 // Use this register and spill the active and inactives interval that 371 // have that register. 372 current->SetRegister(reg); 373 374 for (size_t i = 0, e = active_.Size(); i < e; ++i) { 375 LiveInterval* active = active_.Get(i); 376 if (active->GetRegister() == reg) { 377 LiveInterval* split = Split(active, current->GetStart()); 378 active_.DeleteAt(i); 379 handled_.Add(active); 380 AddToUnhandled(split); 381 break; 382 } 383 } 384 385 for (size_t i = 0; i < inactive_.Size(); ++i) { 386 LiveInterval* inactive = inactive_.Get(i); 387 if (inactive->GetRegister() == reg) { 388 LiveInterval* split = Split(inactive, current->GetStart()); 389 inactive_.DeleteAt(i); 390 handled_.Add(inactive); 391 AddToUnhandled(split); 392 --i; 393 } 394 } 395 396 return true; 397 } 398} 399 400void RegisterAllocator::AddToUnhandled(LiveInterval* interval) { 401 for (size_t i = unhandled_.Size(); i > 0; --i) { 402 LiveInterval* current = unhandled_.Get(i - 1); 403 if (current->StartsAfter(interval)) { 404 unhandled_.InsertAt(i, interval); 405 break; 406 } 407 } 408} 409 410LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) { 411 DCHECK(position >= interval->GetStart()); 412 DCHECK(!interval->IsDeadAt(position)); 413 if (position == interval->GetStart()) { 414 // Spill slot will be allocated when handling `interval` again. 415 interval->ClearRegister(); 416 return interval; 417 } else { 418 LiveInterval* new_interval = interval->SplitAt(position); 419 return new_interval; 420 } 421} 422 423void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) { 424 LiveInterval* parent = interval->GetParent(); 425 426 // An instruction gets a spill slot for its entire lifetime. If the parent 427 // of this interval already has a spill slot, there is nothing to do. 428 if (parent->HasSpillSlot()) { 429 return; 430 } 431 432 // Find when this instruction dies. 433 LiveInterval* last_sibling = interval; 434 while (last_sibling->GetNextSibling() != nullptr) { 435 last_sibling = last_sibling->GetNextSibling(); 436 } 437 size_t end = last_sibling->GetEnd(); 438 439 // Find an available spill slot. 440 size_t slot = 0; 441 for (size_t e = spill_slots_.Size(); slot < e; ++slot) { 442 if (spill_slots_.Get(slot) <= parent->GetStart()) { 443 break; 444 } 445 } 446 447 if (slot == spill_slots_.Size()) { 448 // We need a new spill slot. 449 spill_slots_.Add(end); 450 } else { 451 spill_slots_.Put(slot, end); 452 } 453 454 interval->GetParent()->SetSpillSlot(slot * kVRegSize); 455} 456 457} // namespace art 458