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 "base/arena_allocator.h" 18 #include "nodes.h" 19 #include "parallel_move_resolver.h" 20 21 #include "gtest/gtest.h" 22 #include "gtest/gtest-typed-test.h" 23 24 namespace art { 25 26 constexpr int kScratchRegisterStartIndexForTest = 100; 27 28 static void DumpRegisterForTest(std::ostream& os, int reg) { 29 if (reg >= kScratchRegisterStartIndexForTest) { 30 os << "T" << reg - kScratchRegisterStartIndexForTest; 31 } else { 32 os << reg; 33 } 34 } 35 36 static void DumpLocationForTest(std::ostream& os, Location location) { 37 if (location.IsConstant()) { 38 os << "C"; 39 } else if (location.IsPair()) { 40 DumpRegisterForTest(os, location.low()); 41 os << ","; 42 DumpRegisterForTest(os, location.high()); 43 } else if (location.IsRegister()) { 44 DumpRegisterForTest(os, location.reg()); 45 } else if (location.IsStackSlot()) { 46 os << location.GetStackIndex() << "(sp)"; 47 } else { 48 DCHECK(location.IsDoubleStackSlot())<< location; 49 os << "2x" << location.GetStackIndex() << "(sp)"; 50 } 51 } 52 53 class TestParallelMoveResolverWithSwap : public ParallelMoveResolverWithSwap { 54 public: 55 explicit TestParallelMoveResolverWithSwap(ArenaAllocator* allocator) 56 : ParallelMoveResolverWithSwap(allocator) {} 57 58 void EmitMove(size_t index) OVERRIDE { 59 MoveOperands* move = moves_[index]; 60 if (!message_.str().empty()) { 61 message_ << " "; 62 } 63 message_ << "("; 64 DumpLocationForTest(message_, move->GetSource()); 65 message_ << " -> "; 66 DumpLocationForTest(message_, move->GetDestination()); 67 message_ << ")"; 68 } 69 70 void EmitSwap(size_t index) OVERRIDE { 71 MoveOperands* move = moves_[index]; 72 if (!message_.str().empty()) { 73 message_ << " "; 74 } 75 message_ << "("; 76 DumpLocationForTest(message_, move->GetSource()); 77 message_ << " <-> "; 78 DumpLocationForTest(message_, move->GetDestination()); 79 message_ << ")"; 80 } 81 82 void SpillScratch(int reg ATTRIBUTE_UNUSED) OVERRIDE {} 83 void RestoreScratch(int reg ATTRIBUTE_UNUSED) OVERRIDE {} 84 85 std::string GetMessage() const { 86 return message_.str(); 87 } 88 89 private: 90 std::ostringstream message_; 91 92 93 DISALLOW_COPY_AND_ASSIGN(TestParallelMoveResolverWithSwap); 94 }; 95 96 class TestParallelMoveResolverNoSwap : public ParallelMoveResolverNoSwap { 97 public: 98 explicit TestParallelMoveResolverNoSwap(ArenaAllocator* allocator) 99 : ParallelMoveResolverNoSwap(allocator), scratch_index_(kScratchRegisterStartIndexForTest) {} 100 101 void PrepareForEmitNativeCode() OVERRIDE { 102 scratch_index_ = kScratchRegisterStartIndexForTest; 103 } 104 105 void FinishEmitNativeCode() OVERRIDE {} 106 107 Location AllocateScratchLocationFor(Location::Kind kind) OVERRIDE { 108 if (kind == Location::kStackSlot || kind == Location::kFpuRegister || 109 kind == Location::kRegister) { 110 kind = Location::kRegister; 111 } else { 112 // Allocate register pair for double stack slot which simulates 32-bit backend's behavior. 113 kind = Location::kRegisterPair; 114 } 115 Location scratch = GetScratchLocation(kind); 116 if (scratch.Equals(Location::NoLocation())) { 117 AddScratchLocation(Location::RegisterLocation(scratch_index_)); 118 AddScratchLocation(Location::RegisterLocation(scratch_index_ + 1)); 119 AddScratchLocation(Location::RegisterPairLocation(scratch_index_, scratch_index_ + 1)); 120 scratch = (kind == Location::kRegister) ? Location::RegisterLocation(scratch_index_) 121 : Location::RegisterPairLocation(scratch_index_, scratch_index_ + 1); 122 scratch_index_ += 2; 123 } 124 return scratch; 125 } 126 127 void FreeScratchLocation(Location loc ATTRIBUTE_UNUSED) OVERRIDE {} 128 129 void EmitMove(size_t index) OVERRIDE { 130 MoveOperands* move = moves_[index]; 131 if (!message_.str().empty()) { 132 message_ << " "; 133 } 134 message_ << "("; 135 DumpLocationForTest(message_, move->GetSource()); 136 message_ << " -> "; 137 DumpLocationForTest(message_, move->GetDestination()); 138 message_ << ")"; 139 } 140 141 std::string GetMessage() const { 142 return message_.str(); 143 } 144 145 private: 146 std::ostringstream message_; 147 148 int scratch_index_; 149 150 DISALLOW_COPY_AND_ASSIGN(TestParallelMoveResolverNoSwap); 151 }; 152 153 static HParallelMove* BuildParallelMove(ArenaAllocator* allocator, 154 const size_t operands[][2], 155 size_t number_of_moves) { 156 HParallelMove* moves = new (allocator) HParallelMove(allocator); 157 for (size_t i = 0; i < number_of_moves; ++i) { 158 moves->AddMove( 159 Location::RegisterLocation(operands[i][0]), 160 Location::RegisterLocation(operands[i][1]), 161 Primitive::kPrimInt, 162 nullptr); 163 } 164 return moves; 165 } 166 167 template <typename T> 168 class ParallelMoveTest : public ::testing::Test { 169 public: 170 static const bool has_swap; 171 }; 172 173 template<> const bool ParallelMoveTest<TestParallelMoveResolverWithSwap>::has_swap = true; 174 template<> const bool ParallelMoveTest<TestParallelMoveResolverNoSwap>::has_swap = false; 175 176 typedef ::testing::Types<TestParallelMoveResolverWithSwap, TestParallelMoveResolverNoSwap> 177 ParallelMoveResolverTestTypes; 178 179 TYPED_TEST_CASE(ParallelMoveTest, ParallelMoveResolverTestTypes); 180 181 182 TYPED_TEST(ParallelMoveTest, Dependency) { 183 ArenaPool pool; 184 ArenaAllocator allocator(&pool); 185 186 { 187 TypeParam resolver(&allocator); 188 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}}; 189 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 190 if (TestFixture::has_swap) { 191 ASSERT_STREQ("(1 -> 2) (0 -> 1)", resolver.GetMessage().c_str()); 192 } else { 193 ASSERT_STREQ("(1 -> 2) (0 -> 1)", resolver.GetMessage().c_str()); 194 } 195 } 196 197 { 198 TypeParam resolver(&allocator); 199 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {1, 4}}; 200 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 201 if (TestFixture::has_swap) { 202 ASSERT_STREQ("(2 -> 3) (1 -> 2) (1 -> 4) (0 -> 1)", resolver.GetMessage().c_str()); 203 } else { 204 ASSERT_STREQ("(2 -> 3) (1 -> 2) (0 -> 1) (2 -> 4)", resolver.GetMessage().c_str()); 205 } 206 } 207 } 208 209 TYPED_TEST(ParallelMoveTest, Cycle) { 210 ArenaPool pool; 211 ArenaAllocator allocator(&pool); 212 213 { 214 TypeParam resolver(&allocator); 215 static constexpr size_t moves[][2] = {{0, 1}, {1, 0}}; 216 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 217 if (TestFixture::has_swap) { 218 ASSERT_STREQ("(1 <-> 0)", resolver.GetMessage().c_str()); 219 } else { 220 ASSERT_STREQ("(1 -> T0) (0 -> 1) (T0 -> 0)", resolver.GetMessage().c_str()); 221 } 222 } 223 224 { 225 TypeParam resolver(&allocator); 226 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {1, 0}}; 227 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 228 if (TestFixture::has_swap) { 229 ASSERT_STREQ("(1 -> 2) (1 <-> 0)", resolver.GetMessage().c_str()); 230 } else { 231 ASSERT_STREQ("(1 -> 2) (0 -> 1) (2 -> 0)", resolver.GetMessage().c_str()); 232 } 233 } 234 235 { 236 TypeParam resolver(&allocator); 237 static constexpr size_t moves[][2] = {{0, 1}, {1, 0}, {0, 2}}; 238 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 239 if (TestFixture::has_swap) { 240 ASSERT_STREQ("(0 -> 2) (1 <-> 0)", resolver.GetMessage().c_str()); 241 } else { 242 ASSERT_STREQ("(0 -> 2) (1 -> 0) (2 -> 1)", resolver.GetMessage().c_str()); 243 } 244 } 245 246 { 247 TypeParam resolver(&allocator); 248 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}}; 249 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 250 if (TestFixture::has_swap) { 251 ASSERT_STREQ("(4 <-> 0) (3 <-> 4) (2 <-> 3) (1 <-> 2)", resolver.GetMessage().c_str()); 252 } else { 253 ASSERT_STREQ("(4 -> T0) (3 -> 4) (2 -> 3) (1 -> 2) (0 -> 1) (T0 -> 0)", 254 resolver.GetMessage().c_str()); 255 } 256 } 257 } 258 259 TYPED_TEST(ParallelMoveTest, ConstantLast) { 260 ArenaPool pool; 261 ArenaAllocator allocator(&pool); 262 TypeParam resolver(&allocator); 263 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 264 moves->AddMove( 265 Location::ConstantLocation(new (&allocator) HIntConstant(0)), 266 Location::RegisterLocation(0), 267 Primitive::kPrimInt, 268 nullptr); 269 moves->AddMove( 270 Location::RegisterLocation(1), 271 Location::RegisterLocation(2), 272 Primitive::kPrimInt, 273 nullptr); 274 resolver.EmitNativeCode(moves); 275 ASSERT_STREQ("(1 -> 2) (C -> 0)", resolver.GetMessage().c_str()); 276 } 277 278 TYPED_TEST(ParallelMoveTest, Pairs) { 279 ArenaPool pool; 280 ArenaAllocator allocator(&pool); 281 282 { 283 TypeParam resolver(&allocator); 284 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 285 moves->AddMove( 286 Location::RegisterLocation(2), 287 Location::RegisterLocation(4), 288 Primitive::kPrimInt, 289 nullptr); 290 moves->AddMove( 291 Location::RegisterPairLocation(0, 1), 292 Location::RegisterPairLocation(2, 3), 293 Primitive::kPrimLong, 294 nullptr); 295 resolver.EmitNativeCode(moves); 296 ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str()); 297 } 298 299 { 300 TypeParam resolver(&allocator); 301 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 302 moves->AddMove( 303 Location::RegisterPairLocation(0, 1), 304 Location::RegisterPairLocation(2, 3), 305 Primitive::kPrimLong, 306 nullptr); 307 moves->AddMove( 308 Location::RegisterLocation(2), 309 Location::RegisterLocation(4), 310 Primitive::kPrimInt, 311 nullptr); 312 resolver.EmitNativeCode(moves); 313 ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str()); 314 } 315 316 { 317 TypeParam resolver(&allocator); 318 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 319 moves->AddMove( 320 Location::RegisterPairLocation(0, 1), 321 Location::RegisterPairLocation(2, 3), 322 Primitive::kPrimLong, 323 nullptr); 324 moves->AddMove( 325 Location::RegisterLocation(2), 326 Location::RegisterLocation(0), 327 Primitive::kPrimInt, 328 nullptr); 329 resolver.EmitNativeCode(moves); 330 if (TestFixture::has_swap) { 331 ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); 332 } else { 333 ASSERT_STREQ("(2 -> T0) (0,1 -> 2,3) (T0 -> 0)", resolver.GetMessage().c_str()); 334 } 335 } 336 { 337 TypeParam resolver(&allocator); 338 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 339 moves->AddMove( 340 Location::RegisterLocation(2), 341 Location::RegisterLocation(7), 342 Primitive::kPrimInt, 343 nullptr); 344 moves->AddMove( 345 Location::RegisterLocation(7), 346 Location::RegisterLocation(1), 347 Primitive::kPrimInt, 348 nullptr); 349 moves->AddMove( 350 Location::RegisterPairLocation(0, 1), 351 Location::RegisterPairLocation(2, 3), 352 Primitive::kPrimLong, 353 nullptr); 354 resolver.EmitNativeCode(moves); 355 if (TestFixture::has_swap) { 356 ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str()); 357 } else { 358 ASSERT_STREQ("(0,1 -> T0,T1) (7 -> 1) (2 -> 7) (T0,T1 -> 2,3)", 359 resolver.GetMessage().c_str()); 360 } 361 } 362 { 363 TypeParam resolver(&allocator); 364 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 365 moves->AddMove( 366 Location::RegisterLocation(2), 367 Location::RegisterLocation(7), 368 Primitive::kPrimInt, 369 nullptr); 370 moves->AddMove( 371 Location::RegisterPairLocation(0, 1), 372 Location::RegisterPairLocation(2, 3), 373 Primitive::kPrimLong, 374 nullptr); 375 moves->AddMove( 376 Location::RegisterLocation(7), 377 Location::RegisterLocation(1), 378 Primitive::kPrimInt, 379 nullptr); 380 resolver.EmitNativeCode(moves); 381 if (TestFixture::has_swap) { 382 ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str()); 383 } else { 384 ASSERT_STREQ("(0,1 -> T0,T1) (7 -> 1) (2 -> 7) (T0,T1 -> 2,3)", 385 resolver.GetMessage().c_str()); 386 } 387 } 388 { 389 TypeParam resolver(&allocator); 390 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 391 moves->AddMove( 392 Location::RegisterPairLocation(0, 1), 393 Location::RegisterPairLocation(2, 3), 394 Primitive::kPrimLong, 395 nullptr); 396 moves->AddMove( 397 Location::RegisterLocation(2), 398 Location::RegisterLocation(7), 399 Primitive::kPrimInt, 400 nullptr); 401 moves->AddMove( 402 Location::RegisterLocation(7), 403 Location::RegisterLocation(1), 404 Primitive::kPrimInt, 405 nullptr); 406 resolver.EmitNativeCode(moves); 407 if (TestFixture::has_swap) { 408 ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str()); 409 } else { 410 ASSERT_STREQ("(7 -> T0) (2 -> 7) (0,1 -> 2,3) (T0 -> 1)", resolver.GetMessage().c_str()); 411 } 412 } 413 { 414 TypeParam resolver(&allocator); 415 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 416 moves->AddMove( 417 Location::RegisterPairLocation(0, 1), 418 Location::RegisterPairLocation(2, 3), 419 Primitive::kPrimLong, 420 nullptr); 421 moves->AddMove( 422 Location::RegisterPairLocation(2, 3), 423 Location::RegisterPairLocation(0, 1), 424 Primitive::kPrimLong, 425 nullptr); 426 resolver.EmitNativeCode(moves); 427 if (TestFixture::has_swap) { 428 ASSERT_STREQ("(2,3 <-> 0,1)", resolver.GetMessage().c_str()); 429 } else { 430 ASSERT_STREQ("(2,3 -> T0,T1) (0,1 -> 2,3) (T0,T1 -> 0,1)", resolver.GetMessage().c_str()); 431 } 432 } 433 { 434 TypeParam resolver(&allocator); 435 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 436 moves->AddMove( 437 Location::RegisterPairLocation(2, 3), 438 Location::RegisterPairLocation(0, 1), 439 Primitive::kPrimLong, 440 nullptr); 441 moves->AddMove( 442 Location::RegisterPairLocation(0, 1), 443 Location::RegisterPairLocation(2, 3), 444 Primitive::kPrimLong, 445 nullptr); 446 resolver.EmitNativeCode(moves); 447 if (TestFixture::has_swap) { 448 ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); 449 } else { 450 ASSERT_STREQ("(0,1 -> T0,T1) (2,3 -> 0,1) (T0,T1 -> 2,3)", resolver.GetMessage().c_str()); 451 } 452 } 453 } 454 455 TYPED_TEST(ParallelMoveTest, MultiCycles) { 456 ArenaPool pool; 457 ArenaAllocator allocator(&pool); 458 459 { 460 TypeParam resolver(&allocator); 461 static constexpr size_t moves[][2] = {{0, 1}, {1, 0}, {2, 3}, {3, 2}}; 462 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); 463 if (TestFixture::has_swap) { 464 ASSERT_STREQ("(1 <-> 0) (3 <-> 2)", resolver.GetMessage().c_str()); 465 } else { 466 ASSERT_STREQ("(1 -> T0) (0 -> 1) (T0 -> 0) (3 -> T0) (2 -> 3) (T0 -> 2)", 467 resolver.GetMessage().c_str()); 468 } 469 } 470 { 471 TypeParam resolver(&allocator); 472 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 473 moves->AddMove( 474 Location::RegisterPairLocation(0, 1), 475 Location::RegisterPairLocation(2, 3), 476 Primitive::kPrimLong, 477 nullptr); 478 moves->AddMove( 479 Location::RegisterLocation(2), 480 Location::RegisterLocation(0), 481 Primitive::kPrimInt, 482 nullptr); 483 moves->AddMove( 484 Location::RegisterLocation(3), 485 Location::RegisterLocation(1), 486 Primitive::kPrimInt, 487 nullptr); 488 resolver.EmitNativeCode(moves); 489 if (TestFixture::has_swap) { 490 ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); 491 } else { 492 ASSERT_STREQ("(2 -> T0) (3 -> T1) (0,1 -> 2,3) (T0 -> 0) (T1 -> 1)", 493 resolver.GetMessage().c_str()); 494 } 495 } 496 { 497 TypeParam resolver(&allocator); 498 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 499 moves->AddMove( 500 Location::RegisterLocation(2), 501 Location::RegisterLocation(0), 502 Primitive::kPrimInt, 503 nullptr); 504 moves->AddMove( 505 Location::RegisterLocation(3), 506 Location::RegisterLocation(1), 507 Primitive::kPrimInt, 508 nullptr); 509 moves->AddMove( 510 Location::RegisterPairLocation(0, 1), 511 Location::RegisterPairLocation(2, 3), 512 Primitive::kPrimLong, 513 nullptr); 514 resolver.EmitNativeCode(moves); 515 if (TestFixture::has_swap) { 516 ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); 517 } else { 518 ASSERT_STREQ("(3 -> T0) (0,1 -> T2,T3) (T0 -> 1) (2 -> 0) (T2,T3 -> 2,3)", 519 resolver.GetMessage().c_str()); 520 } 521 } 522 523 { 524 // Test involving registers used in single context and pair context. 525 TypeParam resolver(&allocator); 526 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 527 moves->AddMove( 528 Location::RegisterLocation(10), 529 Location::RegisterLocation(5), 530 Primitive::kPrimInt, 531 nullptr); 532 moves->AddMove( 533 Location::RegisterPairLocation(4, 5), 534 Location::DoubleStackSlot(32), 535 Primitive::kPrimLong, 536 nullptr); 537 moves->AddMove( 538 Location::DoubleStackSlot(32), 539 Location::RegisterPairLocation(10, 11), 540 Primitive::kPrimLong, 541 nullptr); 542 resolver.EmitNativeCode(moves); 543 if (TestFixture::has_swap) { 544 ASSERT_STREQ("(2x32(sp) <-> 10,11) (4,5 <-> 2x32(sp)) (4 -> 5)", resolver.GetMessage().c_str()); 545 } else { 546 ASSERT_STREQ("(2x32(sp) -> T0,T1) (4,5 -> 2x32(sp)) (10 -> 5) (T0,T1 -> 10,11)", 547 resolver.GetMessage().c_str()); 548 } 549 } 550 } 551 552 // Test that we do 64bits moves before 32bits moves. 553 TYPED_TEST(ParallelMoveTest, CyclesWith64BitsMoves) { 554 ArenaPool pool; 555 ArenaAllocator allocator(&pool); 556 557 { 558 TypeParam resolver(&allocator); 559 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 560 moves->AddMove( 561 Location::RegisterLocation(0), 562 Location::RegisterLocation(1), 563 Primitive::kPrimLong, 564 nullptr); 565 moves->AddMove( 566 Location::RegisterLocation(1), 567 Location::StackSlot(48), 568 Primitive::kPrimInt, 569 nullptr); 570 moves->AddMove( 571 Location::StackSlot(48), 572 Location::RegisterLocation(0), 573 Primitive::kPrimInt, 574 nullptr); 575 resolver.EmitNativeCode(moves); 576 if (TestFixture::has_swap) { 577 ASSERT_STREQ("(0 <-> 1) (48(sp) <-> 0)", resolver.GetMessage().c_str()); 578 } else { 579 ASSERT_STREQ("(48(sp) -> T0) (1 -> 48(sp)) (0 -> 1) (T0 -> 0)", 580 resolver.GetMessage().c_str()); 581 } 582 } 583 584 { 585 TypeParam resolver(&allocator); 586 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 587 moves->AddMove( 588 Location::RegisterPairLocation(0, 1), 589 Location::RegisterPairLocation(2, 3), 590 Primitive::kPrimLong, 591 nullptr); 592 moves->AddMove( 593 Location::RegisterPairLocation(2, 3), 594 Location::DoubleStackSlot(32), 595 Primitive::kPrimLong, 596 nullptr); 597 moves->AddMove( 598 Location::DoubleStackSlot(32), 599 Location::RegisterPairLocation(0, 1), 600 Primitive::kPrimLong, 601 nullptr); 602 resolver.EmitNativeCode(moves); 603 if (TestFixture::has_swap) { 604 ASSERT_STREQ("(2x32(sp) <-> 0,1) (2,3 <-> 2x32(sp))", resolver.GetMessage().c_str()); 605 } else { 606 ASSERT_STREQ("(2x32(sp) -> T0,T1) (2,3 -> 2x32(sp)) (0,1 -> 2,3) (T0,T1 -> 0,1)", 607 resolver.GetMessage().c_str()); 608 } 609 } 610 } 611 612 TYPED_TEST(ParallelMoveTest, CyclesWith64BitsMoves2) { 613 ArenaPool pool; 614 ArenaAllocator allocator(&pool); 615 616 { 617 TypeParam resolver(&allocator); 618 HParallelMove* moves = new (&allocator) HParallelMove(&allocator); 619 moves->AddMove( 620 Location::RegisterLocation(0), 621 Location::RegisterLocation(3), 622 Primitive::kPrimInt, 623 nullptr); 624 moves->AddMove( 625 Location::RegisterPairLocation(2, 3), 626 Location::RegisterPairLocation(0, 1), 627 Primitive::kPrimLong, 628 nullptr); 629 moves->AddMove( 630 Location::RegisterLocation(7), 631 Location::RegisterLocation(2), 632 Primitive::kPrimInt, 633 nullptr); 634 resolver.EmitNativeCode(moves); 635 if (TestFixture::has_swap) { 636 ASSERT_STREQ("(2,3 <-> 0,1) (2 -> 3) (7 -> 2)", resolver.GetMessage().c_str()); 637 } else { 638 ASSERT_STREQ("(2,3 -> T0,T1) (0 -> 3) (T0,T1 -> 0,1) (7 -> 2)", 639 resolver.GetMessage().c_str()); 640 } 641 } 642 } 643 644 } // namespace art 645