deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / test / unittests / compiler / move-optimizer-unittest.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/move-optimizer.h"
6 #include "test/unittests/compiler/instruction-sequence-unittest.h"
7
8 namespace v8 {
9 namespace internal {
10 namespace compiler {
11
12 class MoveOptimizerTest : public InstructionSequenceTest {
13  public:
14   GapInstruction* LastGap() {
15     return GapInstruction::cast(*(sequence()->instructions().rbegin() + 1));
16   }
17
18   void AddMove(GapInstruction* gap, TestOperand from, TestOperand to,
19                GapInstruction::InnerPosition pos = GapInstruction::START) {
20     auto parallel_move = gap->GetOrCreateParallelMove(pos, zone());
21     parallel_move->AddMove(ConvertMoveArg(from), ConvertMoveArg(to), zone());
22   }
23
24   int NonRedundantSize(ParallelMove* move) {
25     int i = 0;
26     auto ops = move->move_operands();
27     for (auto op = ops->begin(); op != ops->end(); ++op) {
28       if (op->IsRedundant()) continue;
29       i++;
30     }
31     return i;
32   }
33
34   bool Contains(ParallelMove* move, TestOperand from_op, TestOperand to_op) {
35     auto from = ConvertMoveArg(from_op);
36     auto to = ConvertMoveArg(to_op);
37     auto ops = move->move_operands();
38     for (auto op = ops->begin(); op != ops->end(); ++op) {
39       if (op->IsRedundant()) continue;
40       if (op->source()->Equals(from) && op->destination()->Equals(to)) {
41         return true;
42       }
43     }
44     return false;
45   }
46
47   // TODO(dcarney): add a verifier.
48   void Optimize() {
49     WireBlocks();
50     if (FLAG_trace_turbo) {
51       OFStream os(stdout);
52       PrintableInstructionSequence printable = {config(), sequence()};
53       os << "----- Instruction sequence before move optimization -----\n"
54          << printable;
55     }
56     MoveOptimizer move_optimizer(zone(), sequence());
57     move_optimizer.Run();
58     if (FLAG_trace_turbo) {
59       OFStream os(stdout);
60       PrintableInstructionSequence printable = {config(), sequence()};
61       os << "----- Instruction sequence after move optimization -----\n"
62          << printable;
63     }
64   }
65
66  private:
67   InstructionOperand* ConvertMoveArg(TestOperand op) {
68     CHECK_EQ(kNoValue, op.vreg_.value_);
69     CHECK_NE(kNoValue, op.value_);
70     switch (op.type_) {
71       case kConstant:
72         return ConstantOperand::New(op.value_, zone());
73       case kFixedSlot:
74         return StackSlotOperand::New(op.value_, zone());
75       case kFixedRegister:
76         CHECK(0 <= op.value_ && op.value_ < num_general_registers());
77         return RegisterOperand::New(op.value_, zone());
78       default:
79         break;
80     }
81     CHECK(false);
82     return nullptr;
83   }
84 };
85
86
87 TEST_F(MoveOptimizerTest, RemovesRedundant) {
88   StartBlock();
89   EmitNop();
90   AddMove(LastGap(), Reg(0), Reg(1));
91   EmitNop();
92   AddMove(LastGap(), Reg(1), Reg(0));
93   EndBlock(Last());
94
95   Optimize();
96
97   auto gap = LastGap();
98   auto move = gap->parallel_moves()[0];
99   CHECK_EQ(1, NonRedundantSize(move));
100   CHECK(Contains(move, Reg(0), Reg(1)));
101 }
102
103
104 TEST_F(MoveOptimizerTest, SplitsConstants) {
105   StartBlock();
106   EndBlock(Last());
107
108   auto gap = LastGap();
109   AddMove(gap, Const(1), Slot(0));
110   AddMove(gap, Const(1), Slot(1));
111   AddMove(gap, Const(1), Reg(0));
112   AddMove(gap, Const(1), Slot(2));
113
114   Optimize();
115
116   auto move = gap->parallel_moves()[0];
117   CHECK_EQ(1, NonRedundantSize(move));
118   CHECK(Contains(move, Const(1), Reg(0)));
119
120   move = gap->parallel_moves()[1];
121   CHECK_EQ(3, NonRedundantSize(move));
122   CHECK(Contains(move, Reg(0), Slot(0)));
123   CHECK(Contains(move, Reg(0), Slot(1)));
124   CHECK(Contains(move, Reg(0), Slot(2)));
125 }
126
127
128 TEST_F(MoveOptimizerTest, SimpleMerge) {
129   StartBlock();
130   EndBlock(Branch(Imm(), 1, 2));
131
132   StartBlock();
133   EndBlock(Jump(2));
134   AddMove(LastGap(), Reg(0), Reg(1));
135
136   StartBlock();
137   EndBlock(Jump(1));
138   AddMove(LastGap(), Reg(0), Reg(1));
139
140   StartBlock();
141   EndBlock(Last());
142
143   Optimize();
144
145   auto move = LastGap()->parallel_moves()[0];
146   CHECK_EQ(1, NonRedundantSize(move));
147   CHECK(Contains(move, Reg(0), Reg(1)));
148 }
149
150
151 TEST_F(MoveOptimizerTest, SimpleMergeCycle) {
152   StartBlock();
153   EndBlock(Branch(Imm(), 1, 2));
154
155   StartBlock();
156   EndBlock(Jump(2));
157   auto gap_0 = LastGap();
158   AddMove(gap_0, Reg(0), Reg(1));
159   AddMove(LastGap(), Reg(1), Reg(0));
160
161   StartBlock();
162   EndBlock(Jump(1));
163   auto gap_1 = LastGap();
164   AddMove(gap_1, Reg(0), Reg(1));
165   AddMove(gap_1, Reg(1), Reg(0));
166
167   StartBlock();
168   EndBlock(Last());
169
170   Optimize();
171
172   CHECK(gap_0->IsRedundant());
173   CHECK(gap_1->IsRedundant());
174   auto move = LastGap()->parallel_moves()[0];
175   CHECK_EQ(2, NonRedundantSize(move));
176   CHECK(Contains(move, Reg(0), Reg(1)));
177   CHECK(Contains(move, Reg(1), Reg(0)));
178 }
179
180 }  // namespace compiler
181 }  // namespace internal
182 }  // namespace v8