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