Merge "Fix test-art-target error"
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index bfabc5a..a7283ab 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -318,4 +318,42 @@
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 fc3eb66..83035b5 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -289,21 +289,23 @@
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());