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
DumpRegisterForTest(std::ostream & os,int reg)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
DumpLocationForTest(std::ostream & os,Location location)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:
TestParallelMoveResolverWithSwap(ArenaAllocator * allocator)55 explicit TestParallelMoveResolverWithSwap(ArenaAllocator* allocator)
56 : ParallelMoveResolverWithSwap(allocator) {}
57
EmitMove(size_t index)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
EmitSwap(size_t index)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
SpillScratch(int reg ATTRIBUTE_UNUSED)82 void SpillScratch(int reg ATTRIBUTE_UNUSED) OVERRIDE {}
RestoreScratch(int reg ATTRIBUTE_UNUSED)83 void RestoreScratch(int reg ATTRIBUTE_UNUSED) OVERRIDE {}
84
GetMessage() const85 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:
TestParallelMoveResolverNoSwap(ArenaAllocator * allocator)98 explicit TestParallelMoveResolverNoSwap(ArenaAllocator* allocator)
99 : ParallelMoveResolverNoSwap(allocator), scratch_index_(kScratchRegisterStartIndexForTest) {}
100
PrepareForEmitNativeCode()101 void PrepareForEmitNativeCode() OVERRIDE {
102 scratch_index_ = kScratchRegisterStartIndexForTest;
103 }
104
FinishEmitNativeCode()105 void FinishEmitNativeCode() OVERRIDE {}
106
AllocateScratchLocationFor(Location::Kind kind)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
FreeScratchLocation(Location loc ATTRIBUTE_UNUSED)127 void FreeScratchLocation(Location loc ATTRIBUTE_UNUSED) OVERRIDE {}
128
EmitMove(size_t index)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
GetMessage() const141 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
BuildParallelMove(ArenaAllocator * allocator,const size_t operands[][2],size_t number_of_moves)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
TYPED_TEST(ParallelMoveTest,Dependency)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
TYPED_TEST(ParallelMoveTest,Cycle)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
TYPED_TEST(ParallelMoveTest,ConstantLast)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
TYPED_TEST(ParallelMoveTest,Pairs)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
TYPED_TEST(ParallelMoveTest,MultiCycles)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.
TYPED_TEST(ParallelMoveTest,CyclesWith64BitsMoves)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
TYPED_TEST(ParallelMoveTest,CyclesWith64BitsMoves2)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