OSDN Git Service

Change 1/2 spill slots to more general number of spill slots.
authorAart Bik <ajcbik@google.com>
Tue, 21 Mar 2017 17:55:15 +0000 (10:55 -0700)
committerAart Bik <ajcbik@google.com>
Wed, 22 Mar 2017 23:41:21 +0000 (23:41 +0000)
Rationale:
This prepares requesting a different number of spill slots
during SIMD vectorization.

Bug: 34083438
Test: test-art-host, test-art-host-gtest-register_allocator_test
Change-Id: I6d22966ba483deec72b5eea5061c403c12b2ada7

compiler/optimizing/register_allocation_resolver.cc
compiler/optimizing/register_allocator_graph_color.cc
compiler/optimizing/register_allocator_linear_scan.cc
compiler/optimizing/ssa_liveness_analysis.cc
compiler/optimizing/ssa_liveness_analysis.h

index 8a9c1cc..0d33b49 100644 (file)
@@ -299,11 +299,13 @@ void RegisterAllocationResolver::ConnectSiblings(LiveInterval* interval) {
       // Currently, we spill unconditionnally the current method in the code generators.
       && !interval->GetDefinedBy()->IsCurrentMethod()) {
     // We spill eagerly, so move must be at definition.
-    InsertMoveAfter(interval->GetDefinedBy(),
-                    interval->ToLocation(),
-                    interval->NeedsTwoSpillSlots()
-                        ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
-                        : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
+    Location loc;
+    switch (interval->NumberOfSpillSlotsNeeded()) {
+      case 1: loc = Location::StackSlot(interval->GetParent()->GetSpillSlot()); break;
+      case 2: loc = Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot()); break;
+      default: LOG(FATAL) << "Unexpected number of spill slots"; UNREACHABLE();
+    }
+    InsertMoveAfter(interval->GetDefinedBy(), interval->ToLocation(), loc);
   }
   UsePosition* use = current->GetFirstUse();
   EnvUsePosition* env_use = current->GetFirstEnvironmentUse();
@@ -459,9 +461,11 @@ void RegisterAllocationResolver::ConnectSplitSiblings(LiveInterval* interval,
       location_source = defined_by->GetLocations()->Out();
     } else {
       DCHECK(defined_by->IsCurrentMethod());
-      location_source = parent->NeedsTwoSpillSlots()
-          ? Location::DoubleStackSlot(parent->GetSpillSlot())
-          : Location::StackSlot(parent->GetSpillSlot());
+      switch (parent->NumberOfSpillSlotsNeeded()) {
+        case 1: location_source = Location::StackSlot(parent->GetSpillSlot()); break;
+        case 2: location_source = Location::DoubleStackSlot(parent->GetSpillSlot()); break;
+        default: LOG(FATAL) << "Unexpected number of spill slots"; UNREACHABLE();
+      }
     }
   } else {
     DCHECK(source != nullptr);
index 9064f86..87f709f 100644 (file)
@@ -1029,7 +1029,7 @@ void RegisterAllocatorGraphColor::AllocateSpillSlotForCatchPhi(HInstruction* ins
       interval->SetSpillSlot(previous_phi->GetLiveInterval()->GetSpillSlot());
     } else {
       interval->SetSpillSlot(catch_phi_spill_slot_counter_);
-      catch_phi_spill_slot_counter_ += interval->NeedsTwoSpillSlots() ? 2 : 1;
+      catch_phi_spill_slot_counter_ += interval->NumberOfSpillSlotsNeeded();
     }
   }
 }
@@ -1996,43 +1996,48 @@ void RegisterAllocatorGraphColor::ColorSpillSlots(ArenaVector<LiveInterval*>* in
     bool is_interval_beginning;
     size_t position;
     std::tie(position, is_interval_beginning, parent_interval) = *it;
-
-    bool needs_two_slots = parent_interval->NeedsTwoSpillSlots();
+    size_t number_of_spill_slots_needed = parent_interval->NumberOfSpillSlotsNeeded();
 
     if (is_interval_beginning) {
       DCHECK(!parent_interval->HasSpillSlot());
       DCHECK_EQ(position, parent_interval->GetStart());
 
-      // Find a free stack slot.
+      // Find first available free stack slot(s).
       size_t slot = 0;
-      for (; taken.IsBitSet(slot) || (needs_two_slots && taken.IsBitSet(slot + 1)); ++slot) {
-        // Skip taken slots.
+      for (; ; ++slot) {
+        bool found = true;
+        for (size_t s = slot, u = slot + number_of_spill_slots_needed; s < u; s++) {
+          if (taken.IsBitSet(s)) {
+            found = false;
+            break;  // failure
+          }
+        }
+        if (found) {
+          break;  // success
+        }
       }
+
       parent_interval->SetSpillSlot(slot);
 
-      *num_stack_slots_used = std::max(*num_stack_slots_used,
-                                       needs_two_slots ? slot + 1 : slot + 2);
-      if (needs_two_slots && *num_stack_slots_used % 2 != 0) {
+      *num_stack_slots_used = std::max(*num_stack_slots_used, slot + number_of_spill_slots_needed);
+      if (number_of_spill_slots_needed > 1 && *num_stack_slots_used % 2 != 0) {
         // The parallel move resolver requires that there be an even number of spill slots
         // allocated for pair value types.
         ++(*num_stack_slots_used);
       }
 
-      taken.SetBit(slot);
-      if (needs_two_slots) {
-        taken.SetBit(slot + 1);
+      for (size_t s = slot, u = slot + number_of_spill_slots_needed; s < u; s++) {
+        taken.SetBit(s);
       }
     } else {
       DCHECK_EQ(position, parent_interval->GetLastSibling()->GetEnd());
       DCHECK(parent_interval->HasSpillSlot());
 
-      // Free up the stack slot used by this interval.
+      // Free up the stack slot(s) used by this interval.
       size_t slot = parent_interval->GetSpillSlot();
-      DCHECK(taken.IsBitSet(slot));
-      DCHECK(!needs_two_slots || taken.IsBitSet(slot + 1));
-      taken.ClearBit(slot);
-      if (needs_two_slots) {
-        taken.ClearBit(slot + 1);
+      for (size_t s = slot, u = slot + number_of_spill_slots_needed; s < u; s++) {
+        DCHECK(taken.IsBitSet(s));
+        taken.ClearBit(s);
       }
     }
   }
index 6354e76..ab8d540 100644 (file)
@@ -1125,36 +1125,31 @@ void RegisterAllocatorLinearScan::AllocateSpillSlotFor(LiveInterval* interval) {
       LOG(FATAL) << "Unexpected type for interval " << interval->GetType();
   }
 
-  // Find an available spill slot.
+  // Find first available spill slots.
+  size_t number_of_spill_slots_needed = parent->NumberOfSpillSlotsNeeded();
   size_t slot = 0;
   for (size_t e = spill_slots->size(); slot < e; ++slot) {
-    if ((*spill_slots)[slot] <= parent->GetStart()) {
-      if (!parent->NeedsTwoSpillSlots()) {
-        // One spill slot is sufficient.
-        break;
-      }
-      if (slot == e - 1 || (*spill_slots)[slot + 1] <= parent->GetStart()) {
-        // Two spill slots are available.
+    bool found = true;
+    for (size_t s = slot, u = std::min(slot + number_of_spill_slots_needed, e); s < u; s++) {
+      if ((*spill_slots)[s] > parent->GetStart()) {
+        found = false;  // failure
         break;
       }
     }
+    if (found) {
+      break;  // success
+    }
   }
 
+  // Need new spill slots?
+  size_t upper = slot + number_of_spill_slots_needed;
+  if (upper > spill_slots->size()) {
+    spill_slots->resize(upper);
+  }
+  // Set slots to end.
   size_t end = interval->GetLastSibling()->GetEnd();
-  if (parent->NeedsTwoSpillSlots()) {
-    if (slot + 2u > spill_slots->size()) {
-      // We need a new spill slot.
-      spill_slots->resize(slot + 2u, end);
-    }
-    (*spill_slots)[slot] = end;
-    (*spill_slots)[slot + 1] = end;
-  } else {
-    if (slot == spill_slots->size()) {
-      // We need a new spill slot.
-      spill_slots->push_back(end);
-    } else {
-      (*spill_slots)[slot] = end;
-    }
+  for (size_t s = slot; s < upper; s++) {
+    (*spill_slots)[s] = end;
   }
 
   // Note that the exact spill slot location will be computed when we resolve,
@@ -1180,7 +1175,7 @@ void RegisterAllocatorLinearScan::AllocateSpillSlotForCatchPhi(HPhi* phi) {
     // TODO: Reuse spill slots when intervals of phis from different catch
     //       blocks do not overlap.
     interval->SetSpillSlot(catch_phi_spill_slots_);
-    catch_phi_spill_slots_ += interval->NeedsTwoSpillSlots() ? 2 : 1;
+    catch_phi_spill_slots_ += interval->NumberOfSpillSlotsNeeded();
   }
 }
 
index e8e12e1..c0a045c 100644 (file)
@@ -469,8 +469,8 @@ bool LiveInterval::SameRegisterKind(Location other) const {
   }
 }
 
-bool LiveInterval::NeedsTwoSpillSlots() const {
-  return type_ == Primitive::kPrimLong || type_ == Primitive::kPrimDouble;
+size_t LiveInterval::NumberOfSpillSlotsNeeded() const {
+  return (type_ == Primitive::kPrimLong || type_ == Primitive::kPrimDouble) ? 2 : 1;
 }
 
 Location LiveInterval::ToLocation() const {
@@ -494,10 +494,10 @@ Location LiveInterval::ToLocation() const {
     if (defined_by->IsConstant()) {
       return defined_by->GetLocations()->Out();
     } else if (GetParent()->HasSpillSlot()) {
-      if (NeedsTwoSpillSlots()) {
-        return Location::DoubleStackSlot(GetParent()->GetSpillSlot());
-      } else {
-        return Location::StackSlot(GetParent()->GetSpillSlot());
+      switch (NumberOfSpillSlotsNeeded()) {
+        case 1: return Location::StackSlot(GetParent()->GetSpillSlot());
+        case 2: return Location::DoubleStackSlot(GetParent()->GetSpillSlot());
+        default: LOG(FATAL) << "Unexpected number of spill slots"; UNREACHABLE();
       }
     } else {
       return Location();
index 340d0cc..e9dffc1 100644 (file)
@@ -762,9 +762,9 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> {
   // Returns kNoRegister otherwise.
   int FindHintAtDefinition() const;
 
-  // Returns whether the interval needs two (Dex virtual register size `kVRegSize`)
-  // slots for spilling.
-  bool NeedsTwoSpillSlots() const;
+  // Returns the number of required spilling slots (measured as a multiple of the
+  // Dex virtual register size `kVRegSize`).
+  size_t NumberOfSpillSlotsNeeded() const;
 
   bool IsFloatingPoint() const {
     return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;