Index: test/unittests/compiler/instruction-unittest.cc |
diff --git a/test/unittests/compiler/instruction-unittest.cc b/test/unittests/compiler/instruction-unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..443c42b62ae21a13035989f4b0df7fb13e1a3660 |
--- /dev/null |
+++ b/test/unittests/compiler/instruction-unittest.cc |
@@ -0,0 +1,175 @@ |
+// Copyright 2016 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "src/compiler/instruction.h" |
+#include "src/register-configuration.h" |
+#include "test/unittests/test-utils.h" |
+#include "testing/gtest-support.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+namespace { |
+ |
+const MachineRepresentation kWord = MachineRepresentation::kWord32; |
+const MachineRepresentation kFloat = MachineRepresentation::kFloat32; |
+const MachineRepresentation kDouble = MachineRepresentation::kFloat64; |
+ |
+bool Interfere(LocationOperand::LocationKind kind, MachineRepresentation rep1, |
+ int index1, MachineRepresentation rep2, int index2) { |
+ return AllocatedOperand(kind, rep1, index1) |
+ .InterferesWith(AllocatedOperand(kind, rep2, index2)); |
+} |
+ |
+bool Contains(const ZoneVector<MoveOperands*>* moves, |
+ const InstructionOperand& to, const InstructionOperand& from) { |
+ for (auto move : *moves) { |
+ if (move->destination().Equals(to) && move->source().Equals(from)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+} // namespace |
+ |
+class InstructionTest : public TestWithZone { |
+ public: |
+ InstructionTest() {} |
+ virtual ~InstructionTest() {} |
+ |
+ ParallelMove* CreateParallelMove( |
+ const std::vector<InstructionOperand>& operand_pairs) { |
+ ParallelMove* parallel_move = new (zone()) ParallelMove(zone()); |
+ for (size_t i = 0; i < operand_pairs.size(); i += 2) |
+ parallel_move->AddMove(operand_pairs[i + 1], operand_pairs[i]); |
+ return parallel_move; |
+ } |
+}; |
+ |
+TEST_F(InstructionTest, OperandInterference) { |
+ // All general registers and slots interfere only with themselves. |
+ for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) { |
+ EXPECT_TRUE(Interfere(LocationOperand::REGISTER, kWord, i, kWord, i)); |
+ EXPECT_TRUE(Interfere(LocationOperand::STACK_SLOT, kWord, i, kWord, i)); |
+ for (int j = i + 1; j < RegisterConfiguration::kMaxGeneralRegisters; ++j) { |
+ EXPECT_FALSE(Interfere(LocationOperand::REGISTER, kWord, i, kWord, j)); |
+ EXPECT_FALSE(Interfere(LocationOperand::STACK_SLOT, kWord, i, kWord, j)); |
+ } |
+ } |
+ |
+ // All FP registers interfere with themselves. |
+ for (int i = 0; i < RegisterConfiguration::kMaxFPRegisters; ++i) { |
+ EXPECT_TRUE(Interfere(LocationOperand::REGISTER, kFloat, i, kFloat, i)); |
+ EXPECT_TRUE(Interfere(LocationOperand::STACK_SLOT, kFloat, i, kFloat, i)); |
+ EXPECT_TRUE(Interfere(LocationOperand::REGISTER, kDouble, i, kDouble, i)); |
+ EXPECT_TRUE(Interfere(LocationOperand::STACK_SLOT, kDouble, i, kDouble, i)); |
+ } |
+ |
+ if (kSimpleFPAliasing) { |
+ // Simple FP aliasing: interfering registers of different reps have the same |
+ // index. |
+ for (int i = 0; i < RegisterConfiguration::kMaxFPRegisters; ++i) { |
+ EXPECT_TRUE(Interfere(LocationOperand::REGISTER, kFloat, i, kDouble, i)); |
+ EXPECT_TRUE(Interfere(LocationOperand::REGISTER, kDouble, i, kFloat, i)); |
+ for (int j = i + 1; j < RegisterConfiguration::kMaxFPRegisters; ++j) { |
+ EXPECT_FALSE(Interfere(LocationOperand::REGISTER, kWord, i, kWord, j)); |
+ EXPECT_FALSE( |
+ Interfere(LocationOperand::STACK_SLOT, kWord, i, kWord, j)); |
+ } |
+ } |
+ } else { |
+ // Complex FP aliasing: sub-registers intefere with containing registers. |
+ // Test sub-register indices which may not exist on the platform. This is |
+ // necessary since the GapResolver may split large moves into smaller ones. |
+ for (int i = 0; i < RegisterConfiguration::kMaxFPRegisters; ++i) { |
+ EXPECT_TRUE( |
+ Interfere(LocationOperand::REGISTER, kFloat, i * 2, kDouble, i)); |
+ EXPECT_TRUE( |
+ Interfere(LocationOperand::REGISTER, kFloat, i * 2 + 1, kDouble, i)); |
+ EXPECT_TRUE( |
+ Interfere(LocationOperand::REGISTER, kDouble, i, kFloat, i * 2)); |
+ EXPECT_TRUE( |
+ Interfere(LocationOperand::REGISTER, kDouble, i, kFloat, i * 2 + 1)); |
+ |
+ for (int j = i + 1; j < RegisterConfiguration::kMaxFPRegisters; ++j) { |
+ EXPECT_FALSE( |
+ Interfere(LocationOperand::REGISTER, kFloat, i * 2, kDouble, j)); |
+ EXPECT_FALSE(Interfere(LocationOperand::REGISTER, kFloat, i * 2 + 1, |
+ kDouble, j)); |
+ EXPECT_FALSE( |
+ Interfere(LocationOperand::REGISTER, kDouble, i, kFloat, j * 2)); |
+ EXPECT_FALSE(Interfere(LocationOperand::REGISTER, kDouble, i, kFloat, |
+ j * 2 + 1)); |
+ } |
+ } |
+ } |
+} |
+ |
+TEST_F(InstructionTest, PrepareInsertAfter) { |
+ InstructionOperand r0 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kWord32, 0); |
+ InstructionOperand r1 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kWord32, 1); |
+ InstructionOperand r2 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kWord32, 2); |
+ |
+ InstructionOperand d0 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat64, 0); |
+ InstructionOperand d1 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat64, 1); |
+ InstructionOperand d2 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat64, 2); |
+ |
+ { |
+ // Moves inserted after should pick up assignments to their sources. |
+ // Moves inserted after should cause interfering moves to be eliminated. |
+ ZoneVector<MoveOperands*> to_eliminate(zone()); |
+ std::vector<InstructionOperand> moves = { |
+ r1, r0, // r1 <- r0 |
+ r2, r0, // r2 <- r0 |
+ d1, d0, // d1 <- d0 |
+ d2, d0 // d2 <- d0 |
+ }; |
+ |
+ ParallelMove* pm = CreateParallelMove(moves); |
+ MoveOperands m1(r1, r2); // r2 <- r1 |
+ pm->PrepareInsertAfter(&m1, &to_eliminate); |
+ CHECK(m1.source().Equals(r0)); |
+ CHECK(Contains(&to_eliminate, r2, r0)); |
+ MoveOperands m2(d1, d2); // d2 <- d1 |
+ pm->PrepareInsertAfter(&m2, &to_eliminate); |
+ CHECK(m2.source().Equals(d0)); |
+ CHECK(Contains(&to_eliminate, d2, d0)); |
+ } |
+ |
+ if (!kSimpleFPAliasing) { |
+ // Moves inserted after should cause all interfering moves to be eliminated. |
+ auto s0 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 0); |
+ auto s1 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 1); |
+ auto s2 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 2); |
+ |
+ { |
+ ZoneVector<MoveOperands*> to_eliminate(zone()); |
+ std::vector<InstructionOperand> moves = { |
+ s0, s2, // s0 <- s2 |
+ s1, s2 // s1 <- s2 |
+ }; |
+ |
+ ParallelMove* pm = CreateParallelMove(moves); |
+ MoveOperands m1(d1, d0); // d0 <- d1 |
+ pm->PrepareInsertAfter(&m1, &to_eliminate); |
+ CHECK(Contains(&to_eliminate, s0, s2)); |
+ CHECK(Contains(&to_eliminate, s1, s2)); |
+ } |
+ } |
+} |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |