| 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 | 
|  |