register_allocator_test.cc revision 56b9ee6fe1d6880c5fca0e7feb28b25a1ded2e2f
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 "builder.h" 18#include "code_generator.h" 19#include "code_generator_x86.h" 20#include "dex_file.h" 21#include "dex_instruction.h" 22#include "nodes.h" 23#include "optimizing_unit_test.h" 24#include "register_allocator.h" 25#include "ssa_liveness_analysis.h" 26#include "ssa_phi_elimination.h" 27#include "utils/arena_allocator.h" 28 29#include "gtest/gtest.h" 30 31namespace art { 32 33// Note: the register allocator tests rely on the fact that constants have live 34// intervals and registers get allocated to them. 35 36static bool Check(const uint16_t* data) { 37 ArenaPool pool; 38 ArenaAllocator allocator(&pool); 39 HGraphBuilder builder(&allocator); 40 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); 41 HGraph* graph = builder.BuildGraph(*item); 42 graph->BuildDominatorTree(); 43 graph->TransformToSSA(); 44 graph->FindNaturalLoops(); 45 x86::CodeGeneratorX86 codegen(graph); 46 SsaLivenessAnalysis liveness(*graph, &codegen); 47 liveness.Analyze(); 48 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 49 register_allocator.AllocateRegisters(); 50 return register_allocator.Validate(false); 51} 52 53/** 54 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator 55 * tests are based on this validation method. 56 */ 57TEST(RegisterAllocatorTest, ValidateIntervals) { 58 ArenaPool pool; 59 ArenaAllocator allocator(&pool); 60 HGraph* graph = new (&allocator) HGraph(&allocator); 61 x86::CodeGeneratorX86 codegen(graph); 62 GrowableArray<LiveInterval*> intervals(&allocator, 0); 63 64 // Test with two intervals of the same range. 65 { 66 static constexpr size_t ranges[][2] = {{0, 42}}; 67 intervals.Add(BuildInterval(ranges, arraysize(ranges), &allocator, 0)); 68 intervals.Add(BuildInterval(ranges, arraysize(ranges), &allocator, 1)); 69 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 70 intervals, 0, 0, codegen, &allocator, true, false)); 71 72 intervals.Get(1)->SetRegister(0); 73 ASSERT_FALSE(RegisterAllocator::ValidateIntervals( 74 intervals, 0, 0, codegen, &allocator, true, false)); 75 intervals.Reset(); 76 } 77 78 // Test with two non-intersecting intervals. 79 { 80 static constexpr size_t ranges1[][2] = {{0, 42}}; 81 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0)); 82 static constexpr size_t ranges2[][2] = {{42, 43}}; 83 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1)); 84 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 85 intervals, 0, 0, codegen, &allocator, true, false)); 86 87 intervals.Get(1)->SetRegister(0); 88 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 89 intervals, 0, 0, codegen, &allocator, true, false)); 90 intervals.Reset(); 91 } 92 93 // Test with two non-intersecting intervals, with one with a lifetime hole. 94 { 95 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}}; 96 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0)); 97 static constexpr size_t ranges2[][2] = {{42, 43}}; 98 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1)); 99 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 100 intervals, 0, 0, codegen, &allocator, true, false)); 101 102 intervals.Get(1)->SetRegister(0); 103 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 104 intervals, 0, 0, codegen, &allocator, true, false)); 105 intervals.Reset(); 106 } 107 108 // Test with intersecting intervals. 109 { 110 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}}; 111 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0)); 112 static constexpr size_t ranges2[][2] = {{42, 47}}; 113 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1)); 114 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 115 intervals, 0, 0, codegen, &allocator, true, false)); 116 117 intervals.Get(1)->SetRegister(0); 118 ASSERT_FALSE(RegisterAllocator::ValidateIntervals( 119 intervals, 0, 0, codegen, &allocator, true, false)); 120 intervals.Reset(); 121 } 122 123 // Test with siblings. 124 { 125 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}}; 126 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0)); 127 intervals.Get(0)->SplitAt(43); 128 static constexpr size_t ranges2[][2] = {{42, 47}}; 129 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1)); 130 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 131 intervals, 0, 0, codegen, &allocator, true, false)); 132 133 intervals.Get(1)->SetRegister(0); 134 // Sibling of the first interval has no register allocated to it. 135 ASSERT_TRUE(RegisterAllocator::ValidateIntervals( 136 intervals, 0, 0, codegen, &allocator, true, false)); 137 138 intervals.Get(0)->GetNextSibling()->SetRegister(0); 139 ASSERT_FALSE(RegisterAllocator::ValidateIntervals( 140 intervals, 0, 0, codegen, &allocator, true, false)); 141 } 142} 143 144TEST(RegisterAllocatorTest, CFG1) { 145 /* 146 * Test the following snippet: 147 * return 0; 148 * 149 * Which becomes the following graph: 150 * constant0 151 * goto 152 * | 153 * return 154 * | 155 * exit 156 */ 157 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 158 Instruction::CONST_4 | 0 | 0, 159 Instruction::RETURN); 160 161 ASSERT_TRUE(Check(data)); 162} 163 164TEST(RegisterAllocatorTest, Loop1) { 165 /* 166 * Test the following snippet: 167 * int a = 0; 168 * while (a == a) { 169 * a = 4; 170 * } 171 * return 5; 172 * 173 * Which becomes the following graph: 174 * constant0 175 * constant4 176 * constant5 177 * goto 178 * | 179 * goto 180 * | 181 * phi 182 * equal 183 * if +++++ 184 * | \ + 185 * | goto 186 * | 187 * return 188 * | 189 * exit 190 */ 191 192 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 193 Instruction::CONST_4 | 0 | 0, 194 Instruction::IF_EQ, 4, 195 Instruction::CONST_4 | 4 << 12 | 0, 196 Instruction::GOTO | 0xFD00, 197 Instruction::CONST_4 | 5 << 12 | 1 << 8, 198 Instruction::RETURN | 1 << 8); 199 200 ASSERT_TRUE(Check(data)); 201} 202 203TEST(RegisterAllocatorTest, Loop2) { 204 /* 205 * Test the following snippet: 206 * int a = 0; 207 * while (a == 8) { 208 * a = 4 + 5; 209 * } 210 * return 6 + 7; 211 * 212 * Which becomes the following graph: 213 * constant0 214 * constant4 215 * constant5 216 * constant6 217 * constant7 218 * constant8 219 * goto 220 * | 221 * goto 222 * | 223 * phi 224 * equal 225 * if +++++ 226 * | \ + 227 * | 4 + 5 228 * | goto 229 * | 230 * 6 + 7 231 * return 232 * | 233 * exit 234 */ 235 236 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 237 Instruction::CONST_4 | 0 | 0, 238 Instruction::CONST_4 | 8 << 12 | 1 << 8, 239 Instruction::IF_EQ | 1 << 8, 7, 240 Instruction::CONST_4 | 4 << 12 | 0 << 8, 241 Instruction::CONST_4 | 5 << 12 | 1 << 8, 242 Instruction::ADD_INT, 1 << 8 | 0, 243 Instruction::GOTO | 0xFA00, 244 Instruction::CONST_4 | 6 << 12 | 1 << 8, 245 Instruction::CONST_4 | 7 << 12 | 1 << 8, 246 Instruction::ADD_INT, 1 << 8 | 0, 247 Instruction::RETURN | 1 << 8); 248 249 ASSERT_TRUE(Check(data)); 250} 251 252static HGraph* BuildSSAGraph(const uint16_t* data, ArenaAllocator* allocator) { 253 HGraphBuilder builder(allocator); 254 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); 255 HGraph* graph = builder.BuildGraph(*item); 256 graph->BuildDominatorTree(); 257 graph->TransformToSSA(); 258 graph->FindNaturalLoops(); 259 return graph; 260} 261 262TEST(RegisterAllocatorTest, Loop3) { 263 /* 264 * Test the following snippet: 265 * int a = 0 266 * do { 267 * b = a; 268 * a++; 269 * } while (a != 5) 270 * return b; 271 * 272 * Which becomes the following graph: 273 * constant0 274 * constant1 275 * constant5 276 * goto 277 * | 278 * goto 279 * |++++++++++++ 280 * phi + 281 * a++ + 282 * equals + 283 * if + 284 * |++++++++++++ 285 * return 286 * | 287 * exit 288 */ 289 290 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 291 Instruction::CONST_4 | 0 | 0, 292 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8, 293 Instruction::CONST_4 | 5 << 12 | 2 << 8, 294 Instruction::IF_NE | 1 << 8 | 2 << 12, 3, 295 Instruction::RETURN | 0 << 8, 296 Instruction::MOVE | 1 << 12 | 0 << 8, 297 Instruction::GOTO | 0xF900); 298 299 ArenaPool pool; 300 ArenaAllocator allocator(&pool); 301 HGraph* graph = BuildSSAGraph(data, &allocator); 302 x86::CodeGeneratorX86 codegen(graph); 303 SsaLivenessAnalysis liveness(*graph, &codegen); 304 liveness.Analyze(); 305 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 306 register_allocator.AllocateRegisters(); 307 ASSERT_TRUE(register_allocator.Validate(false)); 308 309 HBasicBlock* loop_header = graph->GetBlocks().Get(2); 310 HPhi* phi = loop_header->GetFirstPhi()->AsPhi(); 311 312 LiveInterval* phi_interval = phi->GetLiveInterval(); 313 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval(); 314 ASSERT_TRUE(phi_interval->HasRegister()); 315 ASSERT_TRUE(loop_update->HasRegister()); 316 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister()); 317 318 HBasicBlock* return_block = graph->GetBlocks().Get(3); 319 HReturn* ret = return_block->GetLastInstruction()->AsReturn(); 320 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister()); 321} 322 323TEST(RegisterAllocatorTest, FirstRegisterUse) { 324 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 325 Instruction::CONST_4 | 0 | 0, 326 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8, 327 Instruction::ADD_INT_LIT8 | 0 << 8, 1 << 8, 328 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8 | 1, 329 Instruction::RETURN_VOID); 330 331 ArenaPool pool; 332 ArenaAllocator allocator(&pool); 333 HGraph* graph = BuildSSAGraph(data, &allocator); 334 x86::CodeGeneratorX86 codegen(graph); 335 SsaLivenessAnalysis liveness(*graph, &codegen); 336 liveness.Analyze(); 337 338 HAdd* first_add = graph->GetBlocks().Get(1)->GetFirstInstruction()->AsAdd(); 339 HAdd* last_add = graph->GetBlocks().Get(1)->GetLastInstruction()->GetPrevious()->AsAdd(); 340 ASSERT_EQ(last_add->InputAt(0), first_add); 341 LiveInterval* interval = first_add->GetLiveInterval(); 342 ASSERT_EQ(interval->GetEnd(), last_add->GetLifetimePosition()); 343 ASSERT_TRUE(interval->GetNextSibling() == nullptr); 344 345 // We need a register for the output of the instruction. 346 ASSERT_EQ(interval->FirstRegisterUse(), first_add->GetLifetimePosition()); 347 348 // Split at the next instruction. 349 interval = interval->SplitAt(first_add->GetLifetimePosition() + 2); 350 // The user of the split is the last add. 351 ASSERT_EQ(interval->FirstRegisterUse(), last_add->GetLifetimePosition() - 1); 352 353 // Split before the last add. 354 LiveInterval* new_interval = interval->SplitAt(last_add->GetLifetimePosition() - 1); 355 // Ensure the current interval has no register use... 356 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime); 357 // And the new interval has it for the last add. 358 ASSERT_EQ(new_interval->FirstRegisterUse(), last_add->GetLifetimePosition() - 1); 359} 360 361TEST(RegisterAllocatorTest, DeadPhi) { 362 /* Test for a dead loop phi taking as back-edge input a phi that also has 363 * this loop phi as input. Walking backwards in SsaDeadPhiElimination 364 * does not solve the problem because the loop phi will be visited last. 365 * 366 * Test the following snippet: 367 * int a = 0 368 * do { 369 * if (true) { 370 * a = 2; 371 * } 372 * } while (true); 373 */ 374 375 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 376 Instruction::CONST_4 | 0 | 0, 377 Instruction::CONST_4 | 1 << 8 | 0, 378 Instruction::IF_NE | 1 << 8 | 1 << 12, 3, 379 Instruction::CONST_4 | 2 << 12 | 0 << 8, 380 Instruction::GOTO | 0xFD00, 381 Instruction::RETURN_VOID); 382 383 ArenaPool pool; 384 ArenaAllocator allocator(&pool); 385 HGraph* graph = BuildSSAGraph(data, &allocator); 386 SsaDeadPhiElimination(graph).Run(); 387 x86::CodeGeneratorX86 codegen(graph); 388 SsaLivenessAnalysis liveness(*graph, &codegen); 389 liveness.Analyze(); 390 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 391 register_allocator.AllocateRegisters(); 392 ASSERT_TRUE(register_allocator.Validate(false)); 393} 394 395/** 396 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals 397 * that share the same register. It should split the interval it is currently 398 * allocating for at the minimum lifetime position between the two inactive intervals. 399 */ 400TEST(RegisterAllocatorTest, FreeUntil) { 401 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 402 Instruction::CONST_4 | 0 | 0, 403 Instruction::RETURN); 404 405 ArenaPool pool; 406 ArenaAllocator allocator(&pool); 407 HGraph* graph = BuildSSAGraph(data, &allocator); 408 SsaDeadPhiElimination(graph).Run(); 409 x86::CodeGeneratorX86 codegen(graph); 410 SsaLivenessAnalysis liveness(*graph, &codegen); 411 liveness.Analyze(); 412 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 413 414 // Add an artifical range to cover the temps that will be put in the unhandled list. 415 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval(); 416 unhandled->AddLoopRange(0, 60); 417 418 // Add three temps holding the same register, and starting at different positions. 419 // Put the one that should be picked in the middle of the inactive list to ensure 420 // we do not depend on an order. 421 LiveInterval* interval = LiveInterval::MakeTempInterval(&allocator, Primitive::kPrimInt); 422 interval->SetRegister(0); 423 interval->AddRange(40, 50); 424 register_allocator.inactive_.Add(interval); 425 426 interval = LiveInterval::MakeTempInterval(&allocator, Primitive::kPrimInt); 427 interval->SetRegister(0); 428 interval->AddRange(20, 30); 429 register_allocator.inactive_.Add(interval); 430 431 interval = LiveInterval::MakeTempInterval(&allocator, Primitive::kPrimInt); 432 interval->SetRegister(0); 433 interval->AddRange(60, 70); 434 register_allocator.inactive_.Add(interval); 435 436 register_allocator.number_of_registers_ = 1; 437 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1); 438 register_allocator.processing_core_registers_ = true; 439 register_allocator.unhandled_ = ®ister_allocator.unhandled_core_intervals_; 440 441 register_allocator.TryAllocateFreeReg(unhandled); 442 443 // Check that we have split the interval. 444 ASSERT_EQ(1u, register_allocator.unhandled_->Size()); 445 // Check that we know need to find a new register where the next interval 446 // that uses the register starts. 447 ASSERT_EQ(20u, register_allocator.unhandled_->Get(0)->GetStart()); 448} 449 450static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator, 451 HPhi** phi, 452 HInstruction** input1, 453 HInstruction** input2) { 454 HGraph* graph = new (allocator) HGraph(allocator); 455 HBasicBlock* entry = new (allocator) HBasicBlock(graph); 456 graph->AddBlock(entry); 457 graph->SetEntryBlock(entry); 458 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot); 459 entry->AddInstruction(parameter); 460 461 HBasicBlock* block = new (allocator) HBasicBlock(graph); 462 graph->AddBlock(block); 463 entry->AddSuccessor(block); 464 465 HInstruction* test = new (allocator) HInstanceFieldGet( 466 parameter, Primitive::kPrimBoolean, MemberOffset(22)); 467 block->AddInstruction(test); 468 block->AddInstruction(new (allocator) HIf(test)); 469 HBasicBlock* then = new (allocator) HBasicBlock(graph); 470 HBasicBlock* else_ = new (allocator) HBasicBlock(graph); 471 HBasicBlock* join = new (allocator) HBasicBlock(graph); 472 graph->AddBlock(then); 473 graph->AddBlock(else_); 474 graph->AddBlock(join); 475 476 block->AddSuccessor(then); 477 block->AddSuccessor(else_); 478 then->AddSuccessor(join); 479 else_->AddSuccessor(join); 480 then->AddInstruction(new (allocator) HGoto()); 481 else_->AddInstruction(new (allocator) HGoto()); 482 483 *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt); 484 join->AddPhi(*phi); 485 *input1 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt, MemberOffset(42)); 486 *input2 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt, MemberOffset(42)); 487 then->AddInstruction(*input1); 488 else_->AddInstruction(*input2); 489 join->AddInstruction(new (allocator) HExit()); 490 (*phi)->AddInput(*input1); 491 (*phi)->AddInput(*input2); 492 493 graph->BuildDominatorTree(); 494 graph->FindNaturalLoops(); 495 return graph; 496} 497 498TEST(RegisterAllocatorTest, PhiHint) { 499 ArenaPool pool; 500 ArenaAllocator allocator(&pool); 501 HPhi *phi; 502 HInstruction *input1, *input2; 503 504 { 505 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); 506 x86::CodeGeneratorX86 codegen(graph); 507 SsaLivenessAnalysis liveness(*graph, &codegen); 508 liveness.Analyze(); 509 510 // Check that the register allocator is deterministic. 511 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 512 register_allocator.AllocateRegisters(); 513 514 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0); 515 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0); 516 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0); 517 } 518 519 { 520 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); 521 x86::CodeGeneratorX86 codegen(graph); 522 SsaLivenessAnalysis liveness(*graph, &codegen); 523 liveness.Analyze(); 524 525 // Set the phi to a specific register, and check that the inputs get allocated 526 // the same register. 527 phi->GetLocations()->SetOut(Location::RegisterLocation(2)); 528 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 529 register_allocator.AllocateRegisters(); 530 531 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2); 532 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2); 533 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2); 534 } 535 536 { 537 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); 538 x86::CodeGeneratorX86 codegen(graph); 539 SsaLivenessAnalysis liveness(*graph, &codegen); 540 liveness.Analyze(); 541 542 // Set input1 to a specific register, and check that the phi and other input get allocated 543 // the same register. 544 input1->GetLocations()->SetOut(Location::RegisterLocation(2)); 545 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 546 register_allocator.AllocateRegisters(); 547 548 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2); 549 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2); 550 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2); 551 } 552 553 { 554 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); 555 x86::CodeGeneratorX86 codegen(graph); 556 SsaLivenessAnalysis liveness(*graph, &codegen); 557 liveness.Analyze(); 558 559 // Set input2 to a specific register, and check that the phi and other input get allocated 560 // the same register. 561 input2->GetLocations()->SetOut(Location::RegisterLocation(2)); 562 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 563 register_allocator.AllocateRegisters(); 564 565 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2); 566 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2); 567 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2); 568 } 569} 570 571static HGraph* BuildFieldReturn(ArenaAllocator* allocator, 572 HInstruction** field, 573 HInstruction** ret) { 574 HGraph* graph = new (allocator) HGraph(allocator); 575 HBasicBlock* entry = new (allocator) HBasicBlock(graph); 576 graph->AddBlock(entry); 577 graph->SetEntryBlock(entry); 578 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot); 579 entry->AddInstruction(parameter); 580 581 HBasicBlock* block = new (allocator) HBasicBlock(graph); 582 graph->AddBlock(block); 583 entry->AddSuccessor(block); 584 585 *field = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt, MemberOffset(42)); 586 block->AddInstruction(*field); 587 *ret = new (allocator) HReturn(*field); 588 block->AddInstruction(*ret); 589 590 HBasicBlock* exit = new (allocator) HBasicBlock(graph); 591 graph->AddBlock(exit); 592 block->AddSuccessor(exit); 593 exit->AddInstruction(new (allocator) HExit()); 594 return graph; 595} 596 597TEST(RegisterAllocatorTest, ExpectedInRegisterHint) { 598 ArenaPool pool; 599 ArenaAllocator allocator(&pool); 600 HInstruction *field, *ret; 601 602 { 603 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret); 604 x86::CodeGeneratorX86 codegen(graph); 605 SsaLivenessAnalysis liveness(*graph, &codegen); 606 liveness.Analyze(); 607 608 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 609 register_allocator.AllocateRegisters(); 610 611 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX). 612 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0); 613 } 614 615 { 616 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret); 617 x86::CodeGeneratorX86 codegen(graph); 618 SsaLivenessAnalysis liveness(*graph, &codegen); 619 liveness.Analyze(); 620 621 // Check that the field gets put in the register expected by its use. 622 ret->GetLocations()->SetInAt(0, Location::RegisterLocation(2)); 623 624 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 625 register_allocator.AllocateRegisters(); 626 627 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2); 628 } 629} 630 631static HGraph* BuildTwoAdds(ArenaAllocator* allocator, 632 HInstruction** first_add, 633 HInstruction** second_add) { 634 HGraph* graph = new (allocator) HGraph(allocator); 635 HBasicBlock* entry = new (allocator) HBasicBlock(graph); 636 graph->AddBlock(entry); 637 graph->SetEntryBlock(entry); 638 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimInt); 639 HInstruction* constant1 = new (allocator) HIntConstant(0); 640 HInstruction* constant2 = new (allocator) HIntConstant(0); 641 entry->AddInstruction(parameter); 642 entry->AddInstruction(constant1); 643 entry->AddInstruction(constant2); 644 645 HBasicBlock* block = new (allocator) HBasicBlock(graph); 646 graph->AddBlock(block); 647 entry->AddSuccessor(block); 648 649 *first_add = new (allocator) HAdd(Primitive::kPrimInt, parameter, constant1); 650 block->AddInstruction(*first_add); 651 *second_add = new (allocator) HAdd(Primitive::kPrimInt, *first_add, constant2); 652 block->AddInstruction(*second_add); 653 654 block->AddInstruction(new (allocator) HExit()); 655 return graph; 656} 657 658TEST(RegisterAllocatorTest, SameAsFirstInputHint) { 659 ArenaPool pool; 660 ArenaAllocator allocator(&pool); 661 HInstruction *first_add, *second_add; 662 663 { 664 HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add); 665 x86::CodeGeneratorX86 codegen(graph); 666 SsaLivenessAnalysis liveness(*graph, &codegen); 667 liveness.Analyze(); 668 669 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 670 register_allocator.AllocateRegisters(); 671 672 // Sanity check that in normal conditions, the registers are the same. 673 ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 1); 674 ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 1); 675 } 676 677 { 678 HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add); 679 x86::CodeGeneratorX86 codegen(graph); 680 SsaLivenessAnalysis liveness(*graph, &codegen); 681 liveness.Analyze(); 682 683 // check that both adds get the same register. 684 first_add->InputAt(0)->GetLocations()->SetOut(Location::RegisterLocation(2)); 685 ASSERT_EQ(first_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); 686 ASSERT_EQ(second_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); 687 688 RegisterAllocator register_allocator(&allocator, &codegen, liveness); 689 register_allocator.AllocateRegisters(); 690 691 ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 2); 692 ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 2); 693 } 694} 695 696} // namespace art 697