Home | History | Annotate | Download | only in optimizing
      1 /*
      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 
     22 #include "base/scoped_arena_allocator.h"
     23 #include "base/scoped_arena_containers.h"
     24 #include "base/bit_vector-inl.h"
     25 #include "code_generator.h"
     26 #include "register_allocator_graph_color.h"
     27 #include "register_allocator_linear_scan.h"
     28 #include "ssa_liveness_analysis.h"
     29 
     30 namespace art {
     31 
     32 RegisterAllocator::RegisterAllocator(ScopedArenaAllocator* allocator,
     33                                      CodeGenerator* codegen,
     34                                      const SsaLivenessAnalysis& liveness)
     35     : allocator_(allocator),
     36       codegen_(codegen),
     37       liveness_(liveness) {}
     38 
     39 std::unique_ptr<RegisterAllocator> RegisterAllocator::Create(ScopedArenaAllocator* allocator,
     40                                                              CodeGenerator* codegen,
     41                                                              const SsaLivenessAnalysis& analysis,
     42                                                              Strategy strategy) {
     43   switch (strategy) {
     44     case kRegisterAllocatorLinearScan:
     45       return std::unique_ptr<RegisterAllocator>(
     46           new (allocator) RegisterAllocatorLinearScan(allocator, codegen, analysis));
     47     case kRegisterAllocatorGraphColor:
     48       return std::unique_ptr<RegisterAllocator>(
     49           new (allocator) RegisterAllocatorGraphColor(allocator, codegen, analysis));
     50     default:
     51       LOG(FATAL) << "Invalid register allocation strategy: " << strategy;
     52       UNREACHABLE();
     53   }
     54 }
     55 
     56 RegisterAllocator::~RegisterAllocator() {
     57   if (kIsDebugBuild) {
     58     // Poison live interval pointers with "Error: BAD 71ve1nt3rval."
     59     LiveInterval* bad_live_interval = reinterpret_cast<LiveInterval*>(0xebad7113u);
     60     for (HBasicBlock* block : codegen_->GetGraph()->GetLinearOrder()) {
     61       for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     62         it.Current()->SetLiveInterval(bad_live_interval);
     63       }
     64       for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     65         it.Current()->SetLiveInterval(bad_live_interval);
     66       }
     67     }
     68   }
     69 }
     70 
     71 bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph ATTRIBUTE_UNUSED,
     72                                                 InstructionSet instruction_set) {
     73   return instruction_set == InstructionSet::kArm
     74       || instruction_set == InstructionSet::kArm64
     75       || instruction_set == InstructionSet::kMips
     76       || instruction_set == InstructionSet::kMips64
     77       || instruction_set == InstructionSet::kThumb2
     78       || instruction_set == InstructionSet::kX86
     79       || instruction_set == InstructionSet::kX86_64;
     80 }
     81 
     82 class AllRangesIterator : public ValueObject {
     83  public:
     84   explicit AllRangesIterator(LiveInterval* interval)
     85       : current_interval_(interval),
     86         current_range_(interval->GetFirstRange()) {}
     87 
     88   bool Done() const { return current_interval_ == nullptr; }
     89   LiveRange* CurrentRange() const { return current_range_; }
     90   LiveInterval* CurrentInterval() const { return current_interval_; }
     91 
     92   void Advance() {
     93     current_range_ = current_range_->GetNext();
     94     if (current_range_ == nullptr) {
     95       current_interval_ = current_interval_->GetNextSibling();
     96       if (current_interval_ != nullptr) {
     97         current_range_ = current_interval_->GetFirstRange();
     98       }
     99     }
    100   }
    101 
    102  private:
    103   LiveInterval* current_interval_;
    104   LiveRange* current_range_;
    105 
    106   DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
    107 };
    108 
    109 bool RegisterAllocator::ValidateIntervals(ArrayRef<LiveInterval* const> intervals,
    110                                           size_t number_of_spill_slots,
    111                                           size_t number_of_out_slots,
    112                                           const CodeGenerator& codegen,
    113                                           bool processing_core_registers,
    114                                           bool log_fatal_on_failure) {
    115   size_t number_of_registers = processing_core_registers
    116       ? codegen.GetNumberOfCoreRegisters()
    117       : codegen.GetNumberOfFloatingPointRegisters();
    118   ScopedArenaAllocator allocator(codegen.GetGraph()->GetArenaStack());
    119   ScopedArenaVector<ArenaBitVector*> liveness_of_values(
    120       allocator.Adapter(kArenaAllocRegisterAllocatorValidate));
    121   liveness_of_values.reserve(number_of_registers + number_of_spill_slots);
    122 
    123   size_t max_end = 0u;
    124   for (LiveInterval* start_interval : intervals) {
    125     for (AllRangesIterator it(start_interval); !it.Done(); it.Advance()) {
    126       max_end = std::max(max_end, it.CurrentRange()->GetEnd());
    127     }
    128   }
    129 
    130   // Allocate a bit vector per register. A live interval that has a register
    131   // allocated will populate the associated bit vector based on its live ranges.
    132   for (size_t i = 0; i < number_of_registers + number_of_spill_slots; ++i) {
    133     liveness_of_values.push_back(
    134         ArenaBitVector::Create(&allocator, max_end, false, kArenaAllocRegisterAllocatorValidate));
    135     liveness_of_values.back()->ClearAllBits();
    136   }
    137 
    138   for (LiveInterval* start_interval : intervals) {
    139     for (AllRangesIterator it(start_interval); !it.Done(); it.Advance()) {
    140       LiveInterval* current = it.CurrentInterval();
    141       HInstruction* defined_by = current->GetParent()->GetDefinedBy();
    142       if (current->GetParent()->HasSpillSlot()
    143            // Parameters and current method have their own stack slot.
    144            && !(defined_by != nullptr && (defined_by->IsParameterValue()
    145                                           || defined_by->IsCurrentMethod()))) {
    146         BitVector* liveness_of_spill_slot = liveness_of_values[number_of_registers
    147             + current->GetParent()->GetSpillSlot() / kVRegSize
    148             - number_of_out_slots];
    149         for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
    150           if (liveness_of_spill_slot->IsBitSet(j)) {
    151             if (log_fatal_on_failure) {
    152               std::ostringstream message;
    153               message << "Spill slot conflict at " << j;
    154               LOG(FATAL) << message.str();
    155             } else {
    156               return false;
    157             }
    158           } else {
    159             liveness_of_spill_slot->SetBit(j);
    160           }
    161         }
    162       }
    163 
    164       if (current->HasRegister()) {
    165         if (kIsDebugBuild && log_fatal_on_failure && !current->IsFixed()) {
    166           // Only check when an error is fatal. Only tests code ask for non-fatal failures
    167           // and test code may not properly fill the right information to the code generator.
    168           CHECK(codegen.HasAllocatedRegister(processing_core_registers, current->GetRegister()));
    169         }
    170         BitVector* liveness_of_register = liveness_of_values[current->GetRegister()];
    171         for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
    172           if (liveness_of_register->IsBitSet(j)) {
    173             if (current->IsUsingInputRegister() && current->CanUseInputRegister()) {
    174               continue;
    175             }
    176             if (log_fatal_on_failure) {
    177               std::ostringstream message;
    178               message << "Register conflict at " << j << " ";
    179               if (defined_by != nullptr) {
    180                 message << "(" << defined_by->DebugName() << ")";
    181               }
    182               message << "for ";
    183               if (processing_core_registers) {
    184                 codegen.DumpCoreRegister(message, current->GetRegister());
    185               } else {
    186                 codegen.DumpFloatingPointRegister(message, current->GetRegister());
    187               }
    188               for (LiveInterval* interval : intervals) {
    189                 if (interval->HasRegister()
    190                     && interval->GetRegister() == current->GetRegister()
    191                     && interval->CoversSlow(j)) {
    192                   message << std::endl;
    193                   if (interval->GetDefinedBy() != nullptr) {
    194                     message << interval->GetDefinedBy()->GetKind() << " ";
    195                   } else {
    196                     message << "physical ";
    197                   }
    198                   interval->Dump(message);
    199                 }
    200               }
    201               LOG(FATAL) << message.str();
    202             } else {
    203               return false;
    204             }
    205           } else {
    206             liveness_of_register->SetBit(j);
    207           }
    208         }
    209       }
    210     }
    211   }
    212   return true;
    213 }
    214 
    215 LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
    216   DCHECK_GE(position, interval->GetStart());
    217   DCHECK(!interval->IsDeadAt(position));
    218   if (position == interval->GetStart()) {
    219     // Spill slot will be allocated when handling `interval` again.
    220     interval->ClearRegister();
    221     if (interval->HasHighInterval()) {
    222       interval->GetHighInterval()->ClearRegister();
    223     } else if (interval->HasLowInterval()) {
    224       interval->GetLowInterval()->ClearRegister();
    225     }
    226     return interval;
    227   } else {
    228     LiveInterval* new_interval = interval->SplitAt(position);
    229     if (interval->HasHighInterval()) {
    230       LiveInterval* high = interval->GetHighInterval()->SplitAt(position);
    231       new_interval->SetHighInterval(high);
    232       high->SetLowInterval(new_interval);
    233     } else if (interval->HasLowInterval()) {
    234       LiveInterval* low = interval->GetLowInterval()->SplitAt(position);
    235       new_interval->SetLowInterval(low);
    236       low->SetHighInterval(new_interval);
    237     }
    238     return new_interval;
    239   }
    240 }
    241 
    242 LiveInterval* RegisterAllocator::SplitBetween(LiveInterval* interval, size_t from, size_t to) {
    243   HBasicBlock* block_from = liveness_.GetBlockFromPosition(from / 2);
    244   HBasicBlock* block_to = liveness_.GetBlockFromPosition(to / 2);
    245   DCHECK(block_from != nullptr);
    246   DCHECK(block_to != nullptr);
    247 
    248   // Both locations are in the same block. We split at the given location.
    249   if (block_from == block_to) {
    250     return Split(interval, to);
    251   }
    252 
    253   /*
    254    * Non-linear control flow will force moves at every branch instruction to the new location.
    255    * To avoid having all branches doing the moves, we find the next non-linear position and
    256    * split the interval at this position. Take the following example (block number is the linear
    257    * order position):
    258    *
    259    *     B1
    260    *    /  \
    261    *   B2  B3
    262    *    \  /
    263    *     B4
    264    *
    265    * B2 needs to split an interval, whose next use is in B4. If we were to split at the
    266    * beginning of B4, B3 would need to do a move between B3 and B4 to ensure the interval
    267    * is now in the correct location. It makes performance worst if the interval is spilled
    268    * and both B2 and B3 need to reload it before entering B4.
    269    *
    270    * By splitting at B3, we give a chance to the register allocator to allocate the
    271    * interval to the same register as in B1, and therefore avoid doing any
    272    * moves in B3.
    273    */
    274   if (block_from->GetDominator() != nullptr) {
    275     for (HBasicBlock* dominated : block_from->GetDominator()->GetDominatedBlocks()) {
    276       size_t position = dominated->GetLifetimeStart();
    277       if ((position > from) && (block_to->GetLifetimeStart() > position)) {
    278         // Even if we found a better block, we continue iterating in case
    279         // a dominated block is closer.
    280         // Note that dominated blocks are not sorted in liveness order.
    281         block_to = dominated;
    282         DCHECK_NE(block_to, block_from);
    283       }
    284     }
    285   }
    286 
    287   // If `to` is in a loop, find the outermost loop header which does not contain `from`.
    288   for (HLoopInformationOutwardIterator it(*block_to); !it.Done(); it.Advance()) {
    289     HBasicBlock* header = it.Current()->GetHeader();
    290     if (block_from->GetLifetimeStart() >= header->GetLifetimeStart()) {
    291       break;
    292     }
    293     block_to = header;
    294   }
    295 
    296   // Split at the start of the found block, to piggy back on existing moves
    297   // due to resolution if non-linear control flow (see `ConnectSplitSiblings`).
    298   return Split(interval, block_to->GetLifetimeStart());
    299 }
    300 
    301 }  // namespace art
    302