OSDN Git Service

Fix a bug in LiveInterval::FirstRegisterUseAfter.
authorNicolas Geoffray <ngeoffray@google.com>
Thu, 19 Jun 2014 16:06:46 +0000 (17:06 +0100)
committerNicolas Geoffray <ngeoffray@google.com>
Wed, 25 Jun 2014 13:12:33 +0000 (14:12 +0100)
Since the use list is shared amongst siblings, we must stop looking
for the user once we have reached the end position of the current
interval. The next uses are for the next sibling.

Change-Id: Ibba180161e94a705e2034abd0b95a29347950257

compiler/optimizing/register_allocator_test.cc
compiler/optimizing/ssa_liveness_analysis.h

index bfabc5a..a7283ab 100644 (file)
@@ -318,4 +318,42 @@ TEST(RegisterAllocatorTest, Loop3) {
   ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
 }
 
+TEST(RegisterAllocatorTest, FirstRegisterUse) {
+  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
+    Instruction::ADD_INT_LIT8 | 0 << 8, 1 << 8,
+    Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8 | 1,
+    Instruction::RETURN_VOID);
+
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HGraph* graph = BuildSSAGraph(data, &allocator);
+  CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, kArm);
+  SsaLivenessAnalysis liveness(*graph, codegen);
+  liveness.Analyze();
+
+  HAdd* first_add = graph->GetBlocks().Get(1)->GetFirstInstruction()->AsAdd();
+  HAdd* last_add = graph->GetBlocks().Get(1)->GetLastInstruction()->GetPrevious()->AsAdd();
+  ASSERT_EQ(last_add->InputAt(0), first_add);
+  LiveInterval* interval = first_add->GetLiveInterval();
+  ASSERT_EQ(interval->GetEnd(), last_add->GetLifetimePosition() + 1);
+  ASSERT_TRUE(interval->GetNextSibling() == nullptr);
+
+  // We need a register for the output of the instruction.
+  ASSERT_EQ(interval->FirstRegisterUse(), first_add->GetLifetimePosition());
+
+  // Split at the next instruction.
+  interval = interval->SplitAt(first_add->GetLifetimePosition() + 2);
+  // The user of the split is the last add.
+  ASSERT_EQ(interval->FirstRegisterUse(), last_add->GetLifetimePosition() + 1);
+
+  // Split before the last add.
+  LiveInterval* new_interval = interval->SplitAt(last_add->GetLifetimePosition() - 1);
+  // Ensure the current interval has no register use...
+  ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
+  // And the new interval has it for the last add.
+  ASSERT_EQ(new_interval->FirstRegisterUse(), last_add->GetLifetimePosition() + 1);
+}
+
 }  // namespace art
index fc3eb66..83035b5 100644 (file)
@@ -289,21 +289,23 @@ class LiveInterval : public ArenaObject {
 
   size_t FirstRegisterUseAfter(size_t position) const {
     if (position == GetStart() && defined_by_ != nullptr) {
-      Location location = defined_by_->GetLocations()->Out();
+      LocationSummary* locations = defined_by_->GetLocations();
+      Location location = locations->Out();
       // This interval is the first interval of the instruction. If the output
       // of the instruction requires a register, we return the position of that instruction
       // as the first register use.
       if (location.IsUnallocated()) {
         if ((location.GetPolicy() == Location::kRequiresRegister)
              || (location.GetPolicy() == Location::kSameAsFirstInput
-                && defined_by_->GetLocations()->InAt(0).GetPolicy() == Location::kRequiresRegister)) {
+                 && locations->InAt(0).GetPolicy() == Location::kRequiresRegister)) {
           return position;
         }
       }
     }
 
     UsePosition* use = first_use_;
-    while (use != nullptr) {
+    size_t end = GetEnd();
+    while (use != nullptr && use->GetPosition() <= end) {
       size_t use_position = use->GetPosition();
       if (use_position >= position && !use->GetIsEnvironment()) {
         Location location = use->GetUser()->GetLocations()->InAt(use->GetInputIndex());