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