1 /* 2 * Copyright (C) 2014 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 "arch/x86/instruction_set_features_x86.h" 20 #include "base/arena_allocator.h" 21 #include "builder.h" 22 #include "code_generator.h" 23 #include "code_generator_x86.h" 24 #include "dex/dex_file.h" 25 #include "dex/dex_file_types.h" 26 #include "dex/dex_instruction.h" 27 #include "driver/compiler_options.h" 28 #include "nodes.h" 29 #include "optimizing_unit_test.h" 30 #include "register_allocator_linear_scan.h" 31 #include "ssa_liveness_analysis.h" 32 #include "ssa_phi_elimination.h" 33 34 namespace art { 35 36 using Strategy = RegisterAllocator::Strategy; 37 38 // Note: the register allocator tests rely on the fact that constants have live 39 // intervals and registers get allocated to them. 40 41 class RegisterAllocatorTest : public OptimizingUnitTest { 42 protected: 43 // These functions need to access private variables of LocationSummary, so we declare it 44 // as a member of RegisterAllocatorTest, which we make a friend class. 45 void SameAsFirstInputHint(Strategy strategy); 46 void ExpectedInRegisterHint(Strategy strategy); 47 48 // Helper functions that make use of the OptimizingUnitTest's members. 49 bool Check(const std::vector<uint16_t>& data, Strategy strategy); 50 void CFG1(Strategy strategy); 51 void Loop1(Strategy strategy); 52 void Loop2(Strategy strategy); 53 void Loop3(Strategy strategy); 54 void DeadPhi(Strategy strategy); 55 HGraph* BuildIfElseWithPhi(HPhi** phi, HInstruction** input1, HInstruction** input2); 56 void PhiHint(Strategy strategy); 57 HGraph* BuildFieldReturn(HInstruction** field, HInstruction** ret); 58 HGraph* BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub); 59 HGraph* BuildDiv(HInstruction** div); 60 void ExpectedExactInRegisterAndSameOutputHint(Strategy strategy); 61 62 bool ValidateIntervals(const ScopedArenaVector<LiveInterval*>& intervals, 63 const CodeGenerator& codegen) { 64 return RegisterAllocator::ValidateIntervals(ArrayRef<LiveInterval* const>(intervals), 65 /* number_of_spill_slots */ 0u, 66 /* number_of_out_slots */ 0u, 67 codegen, 68 /* processing_core_registers */ true, 69 /* log_fatal_on_failure */ false); 70 } 71 }; 72 73 // This macro should include all register allocation strategies that should be tested. 74 #define TEST_ALL_STRATEGIES(test_name)\ 75 TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\ 76 test_name(Strategy::kRegisterAllocatorLinearScan);\ 77 }\ 78 TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\ 79 test_name(Strategy::kRegisterAllocatorGraphColor);\ 80 } 81 82 bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) { 83 HGraph* graph = CreateCFG(data); 84 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 85 X86InstructionSetFeatures::FromCppDefines()); 86 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 87 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 88 liveness.Analyze(); 89 std::unique_ptr<RegisterAllocator> register_allocator = 90 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 91 register_allocator->AllocateRegisters(); 92 return register_allocator->Validate(false); 93 } 94 95 /** 96 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator 97 * tests are based on this validation method. 98 */ 99 TEST_F(RegisterAllocatorTest, ValidateIntervals) { 100 HGraph* graph = CreateGraph(); 101 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 102 X86InstructionSetFeatures::FromCppDefines()); 103 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 104 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter()); 105 106 // Test with two intervals of the same range. 107 { 108 static constexpr size_t ranges[][2] = {{0, 42}}; 109 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 0)); 110 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 1)); 111 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 112 113 intervals[1]->SetRegister(0); 114 ASSERT_FALSE(ValidateIntervals(intervals, codegen)); 115 intervals.clear(); 116 } 117 118 // Test with two non-intersecting intervals. 119 { 120 static constexpr size_t ranges1[][2] = {{0, 42}}; 121 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0)); 122 static constexpr size_t ranges2[][2] = {{42, 43}}; 123 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1)); 124 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 125 126 intervals[1]->SetRegister(0); 127 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 128 intervals.clear(); 129 } 130 131 // Test with two non-intersecting intervals, with one with a lifetime hole. 132 { 133 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}}; 134 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0)); 135 static constexpr size_t ranges2[][2] = {{42, 43}}; 136 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1)); 137 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 138 139 intervals[1]->SetRegister(0); 140 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 141 intervals.clear(); 142 } 143 144 // Test with intersecting intervals. 145 { 146 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}}; 147 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0)); 148 static constexpr size_t ranges2[][2] = {{42, 47}}; 149 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1)); 150 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 151 152 intervals[1]->SetRegister(0); 153 ASSERT_FALSE(ValidateIntervals(intervals, codegen)); 154 intervals.clear(); 155 } 156 157 // Test with siblings. 158 { 159 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}}; 160 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0)); 161 intervals[0]->SplitAt(43); 162 static constexpr size_t ranges2[][2] = {{42, 47}}; 163 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1)); 164 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 165 166 intervals[1]->SetRegister(0); 167 // Sibling of the first interval has no register allocated to it. 168 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 169 170 intervals[0]->GetNextSibling()->SetRegister(0); 171 ASSERT_FALSE(ValidateIntervals(intervals, codegen)); 172 } 173 } 174 175 void RegisterAllocatorTest::CFG1(Strategy strategy) { 176 /* 177 * Test the following snippet: 178 * return 0; 179 * 180 * Which becomes the following graph: 181 * constant0 182 * goto 183 * | 184 * return 185 * | 186 * exit 187 */ 188 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM( 189 Instruction::CONST_4 | 0 | 0, 190 Instruction::RETURN); 191 192 ASSERT_TRUE(Check(data, strategy)); 193 } 194 195 TEST_ALL_STRATEGIES(CFG1); 196 197 void RegisterAllocatorTest::Loop1(Strategy strategy) { 198 /* 199 * Test the following snippet: 200 * int a = 0; 201 * while (a == a) { 202 * a = 4; 203 * } 204 * return 5; 205 * 206 * Which becomes the following graph: 207 * constant0 208 * constant4 209 * constant5 210 * goto 211 * | 212 * goto 213 * | 214 * phi 215 * equal 216 * if +++++ 217 * | \ + 218 * | goto 219 * | 220 * return 221 * | 222 * exit 223 */ 224 225 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( 226 Instruction::CONST_4 | 0 | 0, 227 Instruction::IF_EQ, 4, 228 Instruction::CONST_4 | 4 << 12 | 0, 229 Instruction::GOTO | 0xFD00, 230 Instruction::CONST_4 | 5 << 12 | 1 << 8, 231 Instruction::RETURN | 1 << 8); 232 233 ASSERT_TRUE(Check(data, strategy)); 234 } 235 236 TEST_ALL_STRATEGIES(Loop1); 237 238 void RegisterAllocatorTest::Loop2(Strategy strategy) { 239 /* 240 * Test the following snippet: 241 * int a = 0; 242 * while (a == 8) { 243 * a = 4 + 5; 244 * } 245 * return 6 + 7; 246 * 247 * Which becomes the following graph: 248 * constant0 249 * constant4 250 * constant5 251 * constant6 252 * constant7 253 * constant8 254 * goto 255 * | 256 * goto 257 * | 258 * phi 259 * equal 260 * if +++++ 261 * | \ + 262 * | 4 + 5 263 * | goto 264 * | 265 * 6 + 7 266 * return 267 * | 268 * exit 269 */ 270 271 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( 272 Instruction::CONST_4 | 0 | 0, 273 Instruction::CONST_4 | 8 << 12 | 1 << 8, 274 Instruction::IF_EQ | 1 << 8, 7, 275 Instruction::CONST_4 | 4 << 12 | 0 << 8, 276 Instruction::CONST_4 | 5 << 12 | 1 << 8, 277 Instruction::ADD_INT, 1 << 8 | 0, 278 Instruction::GOTO | 0xFA00, 279 Instruction::CONST_4 | 6 << 12 | 1 << 8, 280 Instruction::CONST_4 | 7 << 12 | 1 << 8, 281 Instruction::ADD_INT, 1 << 8 | 0, 282 Instruction::RETURN | 1 << 8); 283 284 ASSERT_TRUE(Check(data, strategy)); 285 } 286 287 TEST_ALL_STRATEGIES(Loop2); 288 289 void RegisterAllocatorTest::Loop3(Strategy strategy) { 290 /* 291 * Test the following snippet: 292 * int a = 0 293 * do { 294 * b = a; 295 * a++; 296 * } while (a != 5) 297 * return b; 298 * 299 * Which becomes the following graph: 300 * constant0 301 * constant1 302 * constant5 303 * goto 304 * | 305 * goto 306 * |++++++++++++ 307 * phi + 308 * a++ + 309 * equals + 310 * if + 311 * |++++++++++++ 312 * return 313 * | 314 * exit 315 */ 316 317 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM( 318 Instruction::CONST_4 | 0 | 0, 319 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8, 320 Instruction::CONST_4 | 5 << 12 | 2 << 8, 321 Instruction::IF_NE | 1 << 8 | 2 << 12, 3, 322 Instruction::RETURN | 0 << 8, 323 Instruction::MOVE | 1 << 12 | 0 << 8, 324 Instruction::GOTO | 0xF900); 325 326 HGraph* graph = CreateCFG(data); 327 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 328 X86InstructionSetFeatures::FromCppDefines()); 329 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 330 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 331 liveness.Analyze(); 332 std::unique_ptr<RegisterAllocator> register_allocator = 333 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 334 register_allocator->AllocateRegisters(); 335 ASSERT_TRUE(register_allocator->Validate(false)); 336 337 HBasicBlock* loop_header = graph->GetBlocks()[2]; 338 HPhi* phi = loop_header->GetFirstPhi()->AsPhi(); 339 340 LiveInterval* phi_interval = phi->GetLiveInterval(); 341 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval(); 342 ASSERT_TRUE(phi_interval->HasRegister()); 343 ASSERT_TRUE(loop_update->HasRegister()); 344 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister()); 345 346 HBasicBlock* return_block = graph->GetBlocks()[3]; 347 HReturn* ret = return_block->GetLastInstruction()->AsReturn(); 348 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister()); 349 } 350 351 TEST_ALL_STRATEGIES(Loop3); 352 353 TEST_F(RegisterAllocatorTest, FirstRegisterUse) { 354 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM( 355 Instruction::CONST_4 | 0 | 0, 356 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8, 357 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8, 358 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1, 359 Instruction::RETURN_VOID); 360 361 HGraph* graph = CreateCFG(data); 362 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 363 X86InstructionSetFeatures::FromCppDefines()); 364 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 365 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 366 liveness.Analyze(); 367 368 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor(); 369 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor(); 370 ASSERT_EQ(last_xor->InputAt(0), first_xor); 371 LiveInterval* interval = first_xor->GetLiveInterval(); 372 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition()); 373 ASSERT_TRUE(interval->GetNextSibling() == nullptr); 374 375 // We need a register for the output of the instruction. 376 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition()); 377 378 // Split at the next instruction. 379 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2); 380 // The user of the split is the last add. 381 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition()); 382 383 // Split before the last add. 384 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1); 385 // Ensure the current interval has no register use... 386 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime); 387 // And the new interval has it for the last add. 388 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition()); 389 } 390 391 void RegisterAllocatorTest::DeadPhi(Strategy strategy) { 392 /* Test for a dead loop phi taking as back-edge input a phi that also has 393 * this loop phi as input. Walking backwards in SsaDeadPhiElimination 394 * does not solve the problem because the loop phi will be visited last. 395 * 396 * Test the following snippet: 397 * int a = 0 398 * do { 399 * if (true) { 400 * a = 2; 401 * } 402 * } while (true); 403 */ 404 405 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( 406 Instruction::CONST_4 | 0 | 0, 407 Instruction::CONST_4 | 1 << 8 | 0, 408 Instruction::IF_NE | 1 << 8 | 1 << 12, 3, 409 Instruction::CONST_4 | 2 << 12 | 0 << 8, 410 Instruction::GOTO | 0xFD00, 411 Instruction::RETURN_VOID); 412 413 HGraph* graph = CreateCFG(data); 414 SsaDeadPhiElimination(graph).Run(); 415 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 416 X86InstructionSetFeatures::FromCppDefines()); 417 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 418 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 419 liveness.Analyze(); 420 std::unique_ptr<RegisterAllocator> register_allocator = 421 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 422 register_allocator->AllocateRegisters(); 423 ASSERT_TRUE(register_allocator->Validate(false)); 424 } 425 426 TEST_ALL_STRATEGIES(DeadPhi); 427 428 /** 429 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals 430 * that share the same register. It should split the interval it is currently 431 * allocating for at the minimum lifetime position between the two inactive intervals. 432 * This test only applies to the linear scan allocator. 433 */ 434 TEST_F(RegisterAllocatorTest, FreeUntil) { 435 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( 436 Instruction::CONST_4 | 0 | 0, 437 Instruction::RETURN); 438 439 HGraph* graph = CreateCFG(data); 440 SsaDeadPhiElimination(graph).Run(); 441 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 442 X86InstructionSetFeatures::FromCppDefines()); 443 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 444 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 445 liveness.Analyze(); 446 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness); 447 448 // Add an artifical range to cover the temps that will be put in the unhandled list. 449 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval(); 450 unhandled->AddLoopRange(0, 60); 451 452 // Populate the instructions in the liveness object, to please the register allocator. 453 for (size_t i = 0; i < 60; ++i) { 454 liveness.instructions_from_lifetime_position_.push_back( 455 graph->GetEntryBlock()->GetFirstInstruction()); 456 } 457 458 // For SSA value intervals, only an interval resulted from a split may intersect 459 // with inactive intervals. 460 unhandled = register_allocator.Split(unhandled, 5); 461 462 // Add three temps holding the same register, and starting at different positions. 463 // Put the one that should be picked in the middle of the inactive list to ensure 464 // we do not depend on an order. 465 LiveInterval* interval = 466 LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32); 467 interval->AddRange(40, 50); 468 register_allocator.inactive_.push_back(interval); 469 470 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32); 471 interval->AddRange(20, 30); 472 register_allocator.inactive_.push_back(interval); 473 474 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32); 475 interval->AddRange(60, 70); 476 register_allocator.inactive_.push_back(interval); 477 478 register_allocator.number_of_registers_ = 1; 479 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1); 480 register_allocator.processing_core_registers_ = true; 481 register_allocator.unhandled_ = ®ister_allocator.unhandled_core_intervals_; 482 483 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled)); 484 485 // Check that we have split the interval. 486 ASSERT_EQ(1u, register_allocator.unhandled_->size()); 487 // Check that we know need to find a new register where the next interval 488 // that uses the register starts. 489 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart()); 490 } 491 492 HGraph* RegisterAllocatorTest::BuildIfElseWithPhi(HPhi** phi, 493 HInstruction** input1, 494 HInstruction** input2) { 495 HGraph* graph = CreateGraph(); 496 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph); 497 graph->AddBlock(entry); 498 graph->SetEntryBlock(entry); 499 HInstruction* parameter = new (GetAllocator()) HParameterValue( 500 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); 501 entry->AddInstruction(parameter); 502 503 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph); 504 graph->AddBlock(block); 505 entry->AddSuccessor(block); 506 507 HInstruction* test = new (GetAllocator()) HInstanceFieldGet(parameter, 508 nullptr, 509 DataType::Type::kBool, 510 MemberOffset(22), 511 false, 512 kUnknownFieldIndex, 513 kUnknownClassDefIndex, 514 graph->GetDexFile(), 515 0); 516 block->AddInstruction(test); 517 block->AddInstruction(new (GetAllocator()) HIf(test)); 518 HBasicBlock* then = new (GetAllocator()) HBasicBlock(graph); 519 HBasicBlock* else_ = new (GetAllocator()) HBasicBlock(graph); 520 HBasicBlock* join = new (GetAllocator()) HBasicBlock(graph); 521 graph->AddBlock(then); 522 graph->AddBlock(else_); 523 graph->AddBlock(join); 524 525 block->AddSuccessor(then); 526 block->AddSuccessor(else_); 527 then->AddSuccessor(join); 528 else_->AddSuccessor(join); 529 then->AddInstruction(new (GetAllocator()) HGoto()); 530 else_->AddInstruction(new (GetAllocator()) HGoto()); 531 532 *phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32); 533 join->AddPhi(*phi); 534 *input1 = new (GetAllocator()) HInstanceFieldGet(parameter, 535 nullptr, 536 DataType::Type::kInt32, 537 MemberOffset(42), 538 false, 539 kUnknownFieldIndex, 540 kUnknownClassDefIndex, 541 graph->GetDexFile(), 542 0); 543 *input2 = new (GetAllocator()) HInstanceFieldGet(parameter, 544 nullptr, 545 DataType::Type::kInt32, 546 MemberOffset(42), 547 false, 548 kUnknownFieldIndex, 549 kUnknownClassDefIndex, 550 graph->GetDexFile(), 551 0); 552 then->AddInstruction(*input1); 553 else_->AddInstruction(*input2); 554 join->AddInstruction(new (GetAllocator()) HExit()); 555 (*phi)->AddInput(*input1); 556 (*phi)->AddInput(*input2); 557 558 graph->BuildDominatorTree(); 559 graph->AnalyzeLoops(); 560 return graph; 561 } 562 563 void RegisterAllocatorTest::PhiHint(Strategy strategy) { 564 HPhi *phi; 565 HInstruction *input1, *input2; 566 567 { 568 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); 569 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 570 X86InstructionSetFeatures::FromCppDefines()); 571 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 572 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 573 liveness.Analyze(); 574 575 // Check that the register allocator is deterministic. 576 std::unique_ptr<RegisterAllocator> register_allocator = 577 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 578 register_allocator->AllocateRegisters(); 579 580 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0); 581 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0); 582 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0); 583 } 584 585 { 586 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); 587 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 588 X86InstructionSetFeatures::FromCppDefines()); 589 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 590 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 591 liveness.Analyze(); 592 593 // Set the phi to a specific register, and check that the inputs get allocated 594 // the same register. 595 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2)); 596 std::unique_ptr<RegisterAllocator> register_allocator = 597 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 598 register_allocator->AllocateRegisters(); 599 600 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2); 601 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2); 602 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2); 603 } 604 605 { 606 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); 607 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 608 X86InstructionSetFeatures::FromCppDefines()); 609 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 610 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 611 liveness.Analyze(); 612 613 // Set input1 to a specific register, and check that the phi and other input get allocated 614 // the same register. 615 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2)); 616 std::unique_ptr<RegisterAllocator> register_allocator = 617 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 618 register_allocator->AllocateRegisters(); 619 620 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2); 621 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2); 622 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2); 623 } 624 625 { 626 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); 627 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 628 X86InstructionSetFeatures::FromCppDefines()); 629 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 630 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 631 liveness.Analyze(); 632 633 // Set input2 to a specific register, and check that the phi and other input get allocated 634 // the same register. 635 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2)); 636 std::unique_ptr<RegisterAllocator> register_allocator = 637 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 638 register_allocator->AllocateRegisters(); 639 640 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2); 641 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2); 642 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2); 643 } 644 } 645 646 // TODO: Enable this test for graph coloring register allocation when iterative move 647 // coalescing is merged. 648 TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) { 649 PhiHint(Strategy::kRegisterAllocatorLinearScan); 650 } 651 652 HGraph* RegisterAllocatorTest::BuildFieldReturn(HInstruction** field, HInstruction** ret) { 653 HGraph* graph = CreateGraph(); 654 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph); 655 graph->AddBlock(entry); 656 graph->SetEntryBlock(entry); 657 HInstruction* parameter = new (GetAllocator()) HParameterValue( 658 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); 659 entry->AddInstruction(parameter); 660 661 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph); 662 graph->AddBlock(block); 663 entry->AddSuccessor(block); 664 665 *field = new (GetAllocator()) HInstanceFieldGet(parameter, 666 nullptr, 667 DataType::Type::kInt32, 668 MemberOffset(42), 669 false, 670 kUnknownFieldIndex, 671 kUnknownClassDefIndex, 672 graph->GetDexFile(), 673 0); 674 block->AddInstruction(*field); 675 *ret = new (GetAllocator()) HReturn(*field); 676 block->AddInstruction(*ret); 677 678 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph); 679 graph->AddBlock(exit); 680 block->AddSuccessor(exit); 681 exit->AddInstruction(new (GetAllocator()) HExit()); 682 683 graph->BuildDominatorTree(); 684 return graph; 685 } 686 687 void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) { 688 HInstruction *field, *ret; 689 690 { 691 HGraph* graph = BuildFieldReturn(&field, &ret); 692 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 693 X86InstructionSetFeatures::FromCppDefines()); 694 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 695 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 696 liveness.Analyze(); 697 698 std::unique_ptr<RegisterAllocator> register_allocator = 699 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 700 register_allocator->AllocateRegisters(); 701 702 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX). 703 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0); 704 } 705 706 { 707 HGraph* graph = BuildFieldReturn(&field, &ret); 708 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 709 X86InstructionSetFeatures::FromCppDefines()); 710 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 711 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 712 liveness.Analyze(); 713 714 // Check that the field gets put in the register expected by its use. 715 // Don't use SetInAt because we are overriding an already allocated location. 716 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2); 717 718 std::unique_ptr<RegisterAllocator> register_allocator = 719 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 720 register_allocator->AllocateRegisters(); 721 722 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2); 723 } 724 } 725 726 // TODO: Enable this test for graph coloring register allocation when iterative move 727 // coalescing is merged. 728 TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) { 729 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan); 730 } 731 732 HGraph* RegisterAllocatorTest::BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub) { 733 HGraph* graph = CreateGraph(); 734 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph); 735 graph->AddBlock(entry); 736 graph->SetEntryBlock(entry); 737 HInstruction* parameter = new (GetAllocator()) HParameterValue( 738 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 739 entry->AddInstruction(parameter); 740 741 HInstruction* constant1 = graph->GetIntConstant(1); 742 HInstruction* constant2 = graph->GetIntConstant(2); 743 744 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph); 745 graph->AddBlock(block); 746 entry->AddSuccessor(block); 747 748 *first_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, parameter, constant1); 749 block->AddInstruction(*first_sub); 750 *second_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, *first_sub, constant2); 751 block->AddInstruction(*second_sub); 752 753 block->AddInstruction(new (GetAllocator()) HExit()); 754 755 graph->BuildDominatorTree(); 756 return graph; 757 } 758 759 void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) { 760 HInstruction *first_sub, *second_sub; 761 762 { 763 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub); 764 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 765 X86InstructionSetFeatures::FromCppDefines()); 766 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 767 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 768 liveness.Analyze(); 769 770 std::unique_ptr<RegisterAllocator> register_allocator = 771 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 772 register_allocator->AllocateRegisters(); 773 774 // Sanity check that in normal conditions, the registers are the same. 775 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1); 776 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1); 777 } 778 779 { 780 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub); 781 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 782 X86InstructionSetFeatures::FromCppDefines()); 783 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 784 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 785 liveness.Analyze(); 786 787 // check that both adds get the same register. 788 // Don't use UpdateOutput because output is already allocated. 789 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2); 790 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); 791 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); 792 793 std::unique_ptr<RegisterAllocator> register_allocator = 794 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 795 register_allocator->AllocateRegisters(); 796 797 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2); 798 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2); 799 } 800 } 801 802 // TODO: Enable this test for graph coloring register allocation when iterative move 803 // coalescing is merged. 804 TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) { 805 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan); 806 } 807 808 HGraph* RegisterAllocatorTest::BuildDiv(HInstruction** div) { 809 HGraph* graph = CreateGraph(); 810 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph); 811 graph->AddBlock(entry); 812 graph->SetEntryBlock(entry); 813 HInstruction* first = new (GetAllocator()) HParameterValue( 814 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 815 HInstruction* second = new (GetAllocator()) HParameterValue( 816 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 817 entry->AddInstruction(first); 818 entry->AddInstruction(second); 819 820 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph); 821 graph->AddBlock(block); 822 entry->AddSuccessor(block); 823 824 *div = new (GetAllocator()) HDiv( 825 DataType::Type::kInt32, first, second, 0); // don't care about dex_pc. 826 block->AddInstruction(*div); 827 828 block->AddInstruction(new (GetAllocator()) HExit()); 829 830 graph->BuildDominatorTree(); 831 return graph; 832 } 833 834 void RegisterAllocatorTest::ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) { 835 HInstruction *div; 836 HGraph* graph = BuildDiv(&div); 837 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 838 X86InstructionSetFeatures::FromCppDefines()); 839 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 840 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 841 liveness.Analyze(); 842 843 std::unique_ptr<RegisterAllocator> register_allocator = 844 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy); 845 register_allocator->AllocateRegisters(); 846 847 // div on x86 requires its first input in eax and the output be the same as the first input. 848 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0); 849 } 850 851 // TODO: Enable this test for graph coloring register allocation when iterative move 852 // coalescing is merged. 853 TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) { 854 ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan); 855 } 856 857 // Test a bug in the register allocator, where allocating a blocked 858 // register would lead to spilling an inactive interval at the wrong 859 // position. 860 // This test only applies to the linear scan allocator. 861 TEST_F(RegisterAllocatorTest, SpillInactive) { 862 // Create a synthesized graph to please the register_allocator and 863 // ssa_liveness_analysis code. 864 HGraph* graph = CreateGraph(); 865 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph); 866 graph->AddBlock(entry); 867 graph->SetEntryBlock(entry); 868 HInstruction* one = new (GetAllocator()) HParameterValue( 869 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 870 HInstruction* two = new (GetAllocator()) HParameterValue( 871 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 872 HInstruction* three = new (GetAllocator()) HParameterValue( 873 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 874 HInstruction* four = new (GetAllocator()) HParameterValue( 875 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); 876 entry->AddInstruction(one); 877 entry->AddInstruction(two); 878 entry->AddInstruction(three); 879 entry->AddInstruction(four); 880 881 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph); 882 graph->AddBlock(block); 883 entry->AddSuccessor(block); 884 block->AddInstruction(new (GetAllocator()) HExit()); 885 886 // We create a synthesized user requesting a register, to avoid just spilling the 887 // intervals. 888 HPhi* user = new (GetAllocator()) HPhi(GetAllocator(), 0, 1, DataType::Type::kInt32); 889 user->AddInput(one); 890 user->SetBlock(block); 891 LocationSummary* locations = new (GetAllocator()) LocationSummary(user, LocationSummary::kNoCall); 892 locations->SetInAt(0, Location::RequiresRegister()); 893 static constexpr size_t phi_ranges[][2] = {{20, 30}}; 894 BuildInterval(phi_ranges, arraysize(phi_ranges), GetScopedAllocator(), -1, user); 895 896 // Create an interval with lifetime holes. 897 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}}; 898 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), -1, one); 899 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8)); 900 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 7)); 901 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 6)); 902 903 locations = new (GetAllocator()) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall); 904 locations->SetOut(Location::RequiresRegister()); 905 first = first->SplitAt(1); 906 907 // Create an interval that conflicts with the next interval, to force the next 908 // interval to call `AllocateBlockedReg`. 909 static constexpr size_t ranges2[][2] = {{2, 4}}; 910 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), -1, two); 911 locations = 912 new (GetAllocator()) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall); 913 locations->SetOut(Location::RequiresRegister()); 914 915 // Create an interval that will lead to splitting the first interval. The bug occured 916 // by splitting at a wrong position, in this case at the next intersection between 917 // this interval and the first interval. We would have then put the interval with ranges 918 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals 919 // before lifetime position 6 yet. 920 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}}; 921 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), GetScopedAllocator(), -1, three); 922 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8)); 923 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 4)); 924 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 3)); 925 locations = new (GetAllocator()) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall); 926 locations->SetOut(Location::RequiresRegister()); 927 third = third->SplitAt(3); 928 929 // Because the first part of the split interval was considered handled, this interval 930 // was free to allocate the same register, even though it conflicts with it. 931 static constexpr size_t ranges4[][2] = {{4, 6}}; 932 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), GetScopedAllocator(), -1, four); 933 locations = 934 new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall); 935 locations->SetOut(Location::RequiresRegister()); 936 937 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 938 X86InstructionSetFeatures::FromCppDefines()); 939 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); 940 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); 941 // Populate the instructions in the liveness object, to please the register allocator. 942 for (size_t i = 0; i < 32; ++i) { 943 liveness.instructions_from_lifetime_position_.push_back(user); 944 } 945 946 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness); 947 register_allocator.unhandled_core_intervals_.push_back(fourth); 948 register_allocator.unhandled_core_intervals_.push_back(third); 949 register_allocator.unhandled_core_intervals_.push_back(second); 950 register_allocator.unhandled_core_intervals_.push_back(first); 951 952 // Set just one register available to make all intervals compete for the same. 953 register_allocator.number_of_registers_ = 1; 954 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1); 955 register_allocator.processing_core_registers_ = true; 956 register_allocator.unhandled_ = ®ister_allocator.unhandled_core_intervals_; 957 register_allocator.LinearScan(); 958 959 // Test that there is no conflicts between intervals. 960 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter()); 961 intervals.push_back(first); 962 intervals.push_back(second); 963 intervals.push_back(third); 964 intervals.push_back(fourth); 965 ASSERT_TRUE(ValidateIntervals(intervals, codegen)); 966 } 967 968 } // namespace art 969