diff options
-rw-r--r-- | compiler/optimizing/register_allocator_test.cc | 38 | ||||
-rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.h | 8 |
2 files changed, 43 insertions, 3 deletions
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index bfabc5ad27..a7283ab329 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -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 diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index fc3eb660d5..83035b52f6 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -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()); |