| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "base/arena_allocator.h" |
| #include "base/macros.h" |
| #include "base/malloc_arena_pool.h" |
| #include "nodes.h" |
| #include "parallel_move_resolver.h" |
| |
| #include "gtest/gtest-typed-test.h" |
| #include "gtest/gtest.h" |
| |
| namespace art HIDDEN { |
| |
| constexpr int kScratchRegisterStartIndexForTest = 100; |
| |
| static void DumpRegisterForTest(std::ostream& os, int reg) { |
| if (reg >= kScratchRegisterStartIndexForTest) { |
| os << "T" << reg - kScratchRegisterStartIndexForTest; |
| } else { |
| os << reg; |
| } |
| } |
| |
| static void DumpLocationForTest(std::ostream& os, Location location) { |
| if (location.IsConstant()) { |
| os << "C"; |
| } else if (location.IsPair()) { |
| DumpRegisterForTest(os, location.low()); |
| os << ","; |
| DumpRegisterForTest(os, location.high()); |
| } else if (location.IsRegister()) { |
| DumpRegisterForTest(os, location.reg()); |
| } else if (location.IsStackSlot()) { |
| os << location.GetStackIndex() << "(sp)"; |
| } else { |
| DCHECK(location.IsDoubleStackSlot())<< location; |
| os << "2x" << location.GetStackIndex() << "(sp)"; |
| } |
| } |
| |
| class TestParallelMoveResolverWithSwap : public ParallelMoveResolverWithSwap { |
| public: |
| explicit TestParallelMoveResolverWithSwap(ArenaAllocator* allocator) |
| : ParallelMoveResolverWithSwap(allocator) {} |
| |
| void EmitMove(size_t index) override { |
| MoveOperands* move = moves_[index]; |
| if (!message_.str().empty()) { |
| message_ << " "; |
| } |
| message_ << "("; |
| DumpLocationForTest(message_, move->GetSource()); |
| message_ << " -> "; |
| DumpLocationForTest(message_, move->GetDestination()); |
| message_ << ")"; |
| } |
| |
| void EmitSwap(size_t index) override { |
| MoveOperands* move = moves_[index]; |
| if (!message_.str().empty()) { |
| message_ << " "; |
| } |
| message_ << "("; |
| DumpLocationForTest(message_, move->GetSource()); |
| message_ << " <-> "; |
| DumpLocationForTest(message_, move->GetDestination()); |
| message_ << ")"; |
| } |
| |
| void SpillScratch(int reg ATTRIBUTE_UNUSED) override {} |
| void RestoreScratch(int reg ATTRIBUTE_UNUSED) override {} |
| |
| std::string GetMessage() const { |
| return message_.str(); |
| } |
| |
| private: |
| std::ostringstream message_; |
| |
| |
| DISALLOW_COPY_AND_ASSIGN(TestParallelMoveResolverWithSwap); |
| }; |
| |
| class TestParallelMoveResolverNoSwap : public ParallelMoveResolverNoSwap { |
| public: |
| explicit TestParallelMoveResolverNoSwap(ArenaAllocator* allocator) |
| : ParallelMoveResolverNoSwap(allocator), scratch_index_(kScratchRegisterStartIndexForTest) {} |
| |
| void PrepareForEmitNativeCode() override { |
| scratch_index_ = kScratchRegisterStartIndexForTest; |
| } |
| |
| void FinishEmitNativeCode() override {} |
| |
| Location AllocateScratchLocationFor(Location::Kind kind) override { |
| if (kind == Location::kStackSlot || kind == Location::kFpuRegister || |
| kind == Location::kRegister) { |
| kind = Location::kRegister; |
| } else { |
| // Allocate register pair for double stack slot which simulates 32-bit backend's behavior. |
| kind = Location::kRegisterPair; |
| } |
| Location scratch = GetScratchLocation(kind); |
| if (scratch.Equals(Location::NoLocation())) { |
| AddScratchLocation(Location::RegisterLocation(scratch_index_)); |
| AddScratchLocation(Location::RegisterLocation(scratch_index_ + 1)); |
| AddScratchLocation(Location::RegisterPairLocation(scratch_index_, scratch_index_ + 1)); |
| scratch = (kind == Location::kRegister) ? Location::RegisterLocation(scratch_index_) |
| : Location::RegisterPairLocation(scratch_index_, scratch_index_ + 1); |
| scratch_index_ += 2; |
| } |
| return scratch; |
| } |
| |
| void FreeScratchLocation(Location loc ATTRIBUTE_UNUSED) override {} |
| |
| void EmitMove(size_t index) override { |
| MoveOperands* move = moves_[index]; |
| if (!message_.str().empty()) { |
| message_ << " "; |
| } |
| message_ << "("; |
| DumpLocationForTest(message_, move->GetSource()); |
| message_ << " -> "; |
| DumpLocationForTest(message_, move->GetDestination()); |
| message_ << ")"; |
| } |
| |
| std::string GetMessage() const { |
| return message_.str(); |
| } |
| |
| private: |
| std::ostringstream message_; |
| |
| int scratch_index_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestParallelMoveResolverNoSwap); |
| }; |
| |
| static HParallelMove* BuildParallelMove(ArenaAllocator* allocator, |
| const size_t operands[][2], |
| size_t number_of_moves) { |
| HParallelMove* moves = new (allocator) HParallelMove(allocator); |
| for (size_t i = 0; i < number_of_moves; ++i) { |
| moves->AddMove( |
| Location::RegisterLocation(operands[i][0]), |
| Location::RegisterLocation(operands[i][1]), |
| DataType::Type::kInt32, |
| nullptr); |
| } |
| return moves; |
| } |
| |
| template <typename T> |
| class ParallelMoveTest : public ::testing::Test { |
| public: |
| static const bool has_swap; |
| }; |
| |
| template<> const bool ParallelMoveTest<TestParallelMoveResolverWithSwap>::has_swap = true; |
| template<> const bool ParallelMoveTest<TestParallelMoveResolverNoSwap>::has_swap = false; |
| |
| using ParallelMoveResolverTestTypes = |
| ::testing::Types<TestParallelMoveResolverWithSwap, TestParallelMoveResolverNoSwap>; |
| |
| TYPED_TEST_CASE(ParallelMoveTest, ParallelMoveResolverTestTypes); |
| |
| |
| TYPED_TEST(ParallelMoveTest, Dependency) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 2}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(1 -> 2) (0 -> 1)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(1 -> 2) (0 -> 1)", resolver.GetMessage().c_str()); |
| } |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {1, 4}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(2 -> 3) (1 -> 2) (1 -> 4) (0 -> 1)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2 -> 3) (1 -> 2) (0 -> 1) (2 -> 4)", resolver.GetMessage().c_str()); |
| } |
| } |
| } |
| |
| TYPED_TEST(ParallelMoveTest, Cycle) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 0}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(1 <-> 0)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(1 -> T0) (0 -> 1) (T0 -> 0)", resolver.GetMessage().c_str()); |
| } |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {1, 0}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(1 -> 2) (1 <-> 0)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(1 -> 2) (0 -> 1) (2 -> 0)", resolver.GetMessage().c_str()); |
| } |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 0}, {0, 2}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0 -> 2) (1 <-> 0)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(0 -> 2) (1 -> 0) (2 -> 1)", resolver.GetMessage().c_str()); |
| } |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(4 <-> 0) (3 <-> 4) (2 <-> 3) (1 <-> 2)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(4 -> T0) (3 -> 4) (2 -> 3) (1 -> 2) (0 -> 1) (T0 -> 0)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| } |
| |
| TYPED_TEST(ParallelMoveTest, ConstantLast) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::ConstantLocation(new (&allocator) HIntConstant(0)), |
| Location::RegisterLocation(0), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(1), |
| Location::RegisterLocation(2), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| ASSERT_STREQ("(1 -> 2) (C -> 0)", resolver.GetMessage().c_str()); |
| } |
| |
| TYPED_TEST(ParallelMoveTest, Pairs) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(4), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str()); |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(4), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str()); |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(0), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2 -> T0) (0,1 -> 2,3) (T0 -> 0)", resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(7), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(7), |
| Location::RegisterLocation(1), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(0,1 -> T0,T1) (7 -> 1) (2 -> 7) (T0,T1 -> 2,3)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(7), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(7), |
| Location::RegisterLocation(1), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(0,1 -> T0,T1) (7 -> 1) (2 -> 7) (T0,T1 -> 2,3)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(7), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(7), |
| Location::RegisterLocation(1), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(7 -> T0) (2 -> 7) (0,1 -> 2,3) (T0 -> 1)", resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(2, 3), |
| Location::RegisterPairLocation(0, 1), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(2,3 <-> 0,1)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2,3 -> T0,T1) (0,1 -> 2,3) (T0,T1 -> 0,1)", resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(2, 3), |
| Location::RegisterPairLocation(0, 1), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(0,1 -> T0,T1) (2,3 -> 0,1) (T0,T1 -> 2,3)", resolver.GetMessage().c_str()); |
| } |
| } |
| } |
| |
| TYPED_TEST(ParallelMoveTest, MultiCycles) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| |
| { |
| TypeParam resolver(&allocator); |
| static constexpr size_t moves[][2] = {{0, 1}, {1, 0}, {2, 3}, {3, 2}}; |
| resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(1 <-> 0) (3 <-> 2)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(1 -> T0) (0 -> 1) (T0 -> 0) (3 -> T0) (2 -> 3) (T0 -> 2)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(0), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(3), |
| Location::RegisterLocation(1), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2 -> T0) (3 -> T1) (0,1 -> 2,3) (T0 -> 0) (T1 -> 1)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(2), |
| Location::RegisterLocation(0), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(3), |
| Location::RegisterLocation(1), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(3 -> T0) (0,1 -> T2,T3) (T0 -> 1) (2 -> 0) (T2,T3 -> 2,3)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| |
| { |
| // Test involving registers used in single context and pair context. |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(10), |
| Location::RegisterLocation(5), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(4, 5), |
| Location::DoubleStackSlot(32), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::DoubleStackSlot(32), |
| Location::RegisterPairLocation(10, 11), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(2x32(sp) <-> 10,11) (4,5 <-> 2x32(sp)) (4 -> 5)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2x32(sp) -> T0,T1) (4,5 -> 2x32(sp)) (10 -> 5) (T0,T1 -> 10,11)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| } |
| |
| // Test that we do 64bits moves before 32bits moves. |
| TYPED_TEST(ParallelMoveTest, CyclesWith64BitsMoves) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(0), |
| Location::RegisterLocation(1), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(1), |
| Location::StackSlot(48), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::StackSlot(48), |
| Location::RegisterLocation(0), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(0 <-> 1) (48(sp) <-> 0)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(48(sp) -> T0) (1 -> 48(sp)) (0 -> 1) (T0 -> 0)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterPairLocation(0, 1), |
| Location::RegisterPairLocation(2, 3), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(2, 3), |
| Location::DoubleStackSlot(32), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::DoubleStackSlot(32), |
| Location::RegisterPairLocation(0, 1), |
| DataType::Type::kInt64, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(2x32(sp) <-> 0,1) (2,3 <-> 2x32(sp))", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2x32(sp) -> T0,T1) (2,3 -> 2x32(sp)) (0,1 -> 2,3) (T0,T1 -> 0,1)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| } |
| |
| TYPED_TEST(ParallelMoveTest, CyclesWith64BitsMoves2) { |
| MallocArenaPool pool; |
| ArenaAllocator allocator(&pool); |
| |
| { |
| TypeParam resolver(&allocator); |
| HParallelMove* moves = new (&allocator) HParallelMove(&allocator); |
| moves->AddMove( |
| Location::RegisterLocation(0), |
| Location::RegisterLocation(3), |
| DataType::Type::kInt32, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterPairLocation(2, 3), |
| Location::RegisterPairLocation(0, 1), |
| DataType::Type::kInt64, |
| nullptr); |
| moves->AddMove( |
| Location::RegisterLocation(7), |
| Location::RegisterLocation(2), |
| DataType::Type::kInt32, |
| nullptr); |
| resolver.EmitNativeCode(moves); |
| if (TestFixture::has_swap) { |
| ASSERT_STREQ("(2,3 <-> 0,1) (2 -> 3) (7 -> 2)", resolver.GetMessage().c_str()); |
| } else { |
| ASSERT_STREQ("(2,3 -> T0,T1) (0 -> 3) (T0,T1 -> 0,1) (7 -> 2)", |
| resolver.GetMessage().c_str()); |
| } |
| } |
| } |
| |
| } // namespace art |