blob: 413c58b6feb48684bd1a50974896e219ef3326d6 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
8namespace v8 {
9namespace internal {
10namespace compiler {
11
12class MoveOptimizerTest : public InstructionSequenceTest {
13 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014 Instruction* LastInstruction() { return sequence()->instructions().back(); }
15
16 void AddMove(Instruction* instr, TestOperand from, TestOperand to,
17 Instruction::GapPosition pos = Instruction::START) {
18 auto parallel_move = instr->GetOrCreateParallelMove(pos, zone());
19 parallel_move->AddMove(ConvertMoveArg(from), ConvertMoveArg(to));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020 }
21
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 int NonRedundantSize(ParallelMove* moves) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023 int i = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024 for (auto move : *moves) {
25 if (move->IsRedundant()) continue;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040026 i++;
27 }
28 return i;
29 }
30
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 bool Contains(ParallelMove* moves, TestOperand from_op, TestOperand to_op) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040032 auto from = ConvertMoveArg(from_op);
33 auto to = ConvertMoveArg(to_op);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 for (auto move : *moves) {
35 if (move->IsRedundant()) continue;
36 if (move->source().Equals(from) && move->destination().Equals(to)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040037 return true;
38 }
39 }
40 return false;
41 }
42
43 // TODO(dcarney): add a verifier.
44 void Optimize() {
45 WireBlocks();
46 if (FLAG_trace_turbo) {
47 OFStream os(stdout);
48 PrintableInstructionSequence printable = {config(), sequence()};
49 os << "----- Instruction sequence before move optimization -----\n"
50 << printable;
51 }
52 MoveOptimizer move_optimizer(zone(), sequence());
53 move_optimizer.Run();
54 if (FLAG_trace_turbo) {
55 OFStream os(stdout);
56 PrintableInstructionSequence printable = {config(), sequence()};
57 os << "----- Instruction sequence after move optimization -----\n"
58 << printable;
59 }
60 }
61
62 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063 InstructionOperand ConvertMoveArg(TestOperand op) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064 CHECK_EQ(kNoValue, op.vreg_.value_);
65 CHECK_NE(kNoValue, op.value_);
66 switch (op.type_) {
67 case kConstant:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068 return ConstantOperand(op.value_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040069 case kFixedSlot:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070 return AllocatedOperand(LocationOperand::STACK_SLOT,
71 MachineRepresentation::kWord32, op.value_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040072 case kFixedRegister:
73 CHECK(0 <= op.value_ && op.value_ < num_general_registers());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 return AllocatedOperand(LocationOperand::REGISTER,
75 MachineRepresentation::kWord32, op.value_);
76 case kExplicit:
77 CHECK(0 <= op.value_ && op.value_ < num_general_registers());
78 return ExplicitOperand(LocationOperand::REGISTER,
79 MachineRepresentation::kWord32, op.value_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040080 default:
81 break;
82 }
83 CHECK(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 return InstructionOperand();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 }
86};
87
88
89TEST_F(MoveOptimizerTest, RemovesRedundant) {
90 StartBlock();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 auto first_instr = EmitNop();
92 AddMove(first_instr, Reg(0), Reg(1));
93 auto last_instr = EmitNop();
94 AddMove(last_instr, Reg(1), Reg(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040095 EndBlock(Last());
96
97 Optimize();
98
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 CHECK_EQ(0, NonRedundantSize(first_instr->parallel_moves()[0]));
100 auto move = last_instr->parallel_moves()[0];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400101 CHECK_EQ(1, NonRedundantSize(move));
102 CHECK(Contains(move, Reg(0), Reg(1)));
103}
104
105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106TEST_F(MoveOptimizerTest, RemovesRedundantExplicit) {
107 int first_reg_index =
108 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
109 ->GetAllocatableGeneralCode(0);
110 int second_reg_index =
111 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
112 ->GetAllocatableGeneralCode(1);
113
114 StartBlock();
115 auto first_instr = EmitNop();
116 AddMove(first_instr, Reg(first_reg_index), ExplicitReg(second_reg_index));
117 auto last_instr = EmitNop();
118 AddMove(last_instr, Reg(second_reg_index), Reg(first_reg_index));
119 EndBlock(Last());
120
121 Optimize();
122
123 CHECK_EQ(0, NonRedundantSize(first_instr->parallel_moves()[0]));
124 auto move = last_instr->parallel_moves()[0];
125 CHECK_EQ(1, NonRedundantSize(move));
126 CHECK(Contains(move, Reg(first_reg_index), ExplicitReg(second_reg_index)));
127}
128
129
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400130TEST_F(MoveOptimizerTest, SplitsConstants) {
131 StartBlock();
132 EndBlock(Last());
133
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 auto gap = LastInstruction();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400135 AddMove(gap, Const(1), Slot(0));
136 AddMove(gap, Const(1), Slot(1));
137 AddMove(gap, Const(1), Reg(0));
138 AddMove(gap, Const(1), Slot(2));
139
140 Optimize();
141
142 auto move = gap->parallel_moves()[0];
143 CHECK_EQ(1, NonRedundantSize(move));
144 CHECK(Contains(move, Const(1), Reg(0)));
145
146 move = gap->parallel_moves()[1];
147 CHECK_EQ(3, NonRedundantSize(move));
148 CHECK(Contains(move, Reg(0), Slot(0)));
149 CHECK(Contains(move, Reg(0), Slot(1)));
150 CHECK(Contains(move, Reg(0), Slot(2)));
151}
152
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153
154TEST_F(MoveOptimizerTest, SimpleMerge) {
155 StartBlock();
156 EndBlock(Branch(Imm(), 1, 2));
157
158 StartBlock();
159 EndBlock(Jump(2));
160 AddMove(LastInstruction(), Reg(0), Reg(1));
161
162 StartBlock();
163 EndBlock(Jump(1));
164 AddMove(LastInstruction(), Reg(0), Reg(1));
165
166 StartBlock();
167 EndBlock(Last());
168
169 auto last = LastInstruction();
170
171 Optimize();
172
173 auto move = last->parallel_moves()[0];
174 CHECK_EQ(1, NonRedundantSize(move));
175 CHECK(Contains(move, Reg(0), Reg(1)));
176}
177
178
179TEST_F(MoveOptimizerTest, SimpleMergeCycle) {
180 StartBlock();
181 EndBlock(Branch(Imm(), 1, 2));
182
183 StartBlock();
184 EndBlock(Jump(2));
185 auto gap_0 = LastInstruction();
186 AddMove(gap_0, Reg(0), Reg(1));
187 AddMove(LastInstruction(), Reg(1), Reg(0));
188
189 StartBlock();
190 EndBlock(Jump(1));
191 auto gap_1 = LastInstruction();
192 AddMove(gap_1, Reg(0), Reg(1));
193 AddMove(gap_1, Reg(1), Reg(0));
194
195 StartBlock();
196 EndBlock(Last());
197
198 auto last = LastInstruction();
199
200 Optimize();
201
202 CHECK(gap_0->AreMovesRedundant());
203 CHECK(gap_1->AreMovesRedundant());
204 auto move = last->parallel_moves()[0];
205 CHECK_EQ(2, NonRedundantSize(move));
206 CHECK(Contains(move, Reg(0), Reg(1)));
207 CHECK(Contains(move, Reg(1), Reg(0)));
208}
209
210
211TEST_F(MoveOptimizerTest, GapsCanMoveOverInstruction) {
212 StartBlock();
213 int const_index = 1;
214 DefineConstant(const_index);
215 Instruction* ctant_def = LastInstruction();
216 AddMove(ctant_def, Reg(1), Reg(0));
217
218 Instruction* last = EmitNop();
219 AddMove(last, Const(const_index), Reg(0));
220 AddMove(last, Reg(0), Reg(1));
221 EndBlock(Last());
222 Optimize();
223
224 ParallelMove* inst1_start =
225 ctant_def->GetParallelMove(Instruction::GapPosition::START);
226 ParallelMove* inst1_end =
227 ctant_def->GetParallelMove(Instruction::GapPosition::END);
228 ParallelMove* last_start =
229 last->GetParallelMove(Instruction::GapPosition::START);
230 CHECK(inst1_start == nullptr || inst1_start->size() == 0);
231 CHECK(inst1_end == nullptr || inst1_end->size() == 0);
232 CHECK(last_start->size() == 2);
233 int redundants = 0;
234 int assignment = 0;
235 for (MoveOperands* move : *last_start) {
236 if (move->IsRedundant()) {
237 ++redundants;
238 } else {
239 ++assignment;
240 CHECK(move->destination().IsRegister());
241 CHECK(move->source().IsConstant());
242 }
243 }
244 CHECK_EQ(1, redundants);
245 CHECK_EQ(1, assignment);
246}
247
248
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400249} // namespace compiler
250} // namespace internal
251} // namespace v8