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