OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/move-optimizer.h" | 5 #include "src/compiler/move-optimizer.h" |
6 | 6 |
7 namespace v8 { | 7 namespace v8 { |
8 namespace internal { | 8 namespace internal { |
9 namespace compiler { | 9 namespace compiler { |
10 | 10 |
11 namespace { | 11 namespace { |
12 | 12 |
13 typedef std::pair<InstructionOperand, InstructionOperand> MoveKey; | 13 typedef std::pair<InstructionOperand, InstructionOperand> MoveKey; |
14 typedef ZoneMap<MoveKey, unsigned> MoveMap; | 14 typedef ZoneMap<MoveKey, unsigned> MoveMap; |
15 typedef ZoneSet<InstructionOperand> OperandSet; | 15 typedef ZoneSet<InstructionOperand> OperandSet; |
16 | 16 |
17 | 17 |
18 bool GapsCanMoveOver(Instruction* instr) { | 18 bool GapsCanMoveOver(Instruction* instr) { |
19 DCHECK(!instr->IsGapMoves()); | |
20 return instr->IsSourcePosition() || instr->IsNop(); | 19 return instr->IsSourcePosition() || instr->IsNop(); |
21 } | 20 } |
22 | 21 |
23 | 22 |
24 int FindFirstNonEmptySlot(GapInstruction* gap) { | 23 int FindFirstNonEmptySlot(Instruction* instr) { |
25 int i = GapInstruction::FIRST_INNER_POSITION; | 24 int i = Instruction::FIRST_GAP_POSITION; |
26 for (; i <= GapInstruction::LAST_INNER_POSITION; i++) { | 25 for (; i <= Instruction::LAST_GAP_POSITION; i++) { |
27 auto move = gap->parallel_moves()[i]; | 26 auto move = instr->parallel_moves()[i]; |
28 if (move == nullptr) continue; | 27 if (move == nullptr) continue; |
29 auto move_ops = move->move_operands(); | 28 auto move_ops = move->move_operands(); |
30 auto op = move_ops->begin(); | 29 auto op = move_ops->begin(); |
31 for (; op != move_ops->end(); ++op) { | 30 for (; op != move_ops->end(); ++op) { |
32 if (!op->IsRedundant()) break; | 31 if (!op->IsRedundant()) break; |
33 op->Eliminate(); | 32 op->Eliminate(); |
34 } | 33 } |
35 if (op != move_ops->end()) break; // Found non-redundant move. | 34 if (op != move_ops->end()) break; // Found non-redundant move. |
36 move_ops->Rewind(0); // Clear this redundant move. | 35 move_ops->Rewind(0); // Clear this redundant move. |
37 } | 36 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 // Nuke right. | 89 // Nuke right. |
91 move_ops->Rewind(0); | 90 move_ops->Rewind(0); |
92 } | 91 } |
93 | 92 |
94 | 93 |
95 // Smash all consecutive moves into the left most move slot and accumulate them | 94 // Smash all consecutive moves into the left most move slot and accumulate them |
96 // as much as possible across instructions. | 95 // as much as possible across instructions. |
97 void MoveOptimizer::CompressBlock(InstructionBlock* block) { | 96 void MoveOptimizer::CompressBlock(InstructionBlock* block) { |
98 auto temp_vector = temp_vector_0(); | 97 auto temp_vector = temp_vector_0(); |
99 DCHECK(temp_vector.empty()); | 98 DCHECK(temp_vector.empty()); |
100 GapInstruction* prev_gap = nullptr; | 99 Instruction* prev_instr = nullptr; |
101 for (int index = block->code_start(); index < block->code_end(); ++index) { | 100 for (int index = block->code_start(); index < block->code_end(); ++index) { |
102 auto instr = code()->instructions()[index]; | 101 auto instr = code()->instructions()[index]; |
103 if (!instr->IsGapMoves()) { | 102 int i = FindFirstNonEmptySlot(instr); |
104 if (GapsCanMoveOver(instr)) continue; | 103 if (i <= Instruction::LAST_GAP_POSITION) { |
105 if (prev_gap != nullptr) to_finalize_.push_back(prev_gap); | 104 // Move the first non-empty gap to position 0. |
106 prev_gap = nullptr; | 105 std::swap(instr->parallel_moves()[0], instr->parallel_moves()[i]); |
107 continue; | 106 auto left = instr->parallel_moves()[0]; |
| 107 // Compress everything into position 0. |
| 108 for (++i; i <= Instruction::LAST_GAP_POSITION; ++i) { |
| 109 auto move = instr->parallel_moves()[i]; |
| 110 if (move == nullptr) continue; |
| 111 CompressMoves(&temp_vector, left, move); |
| 112 } |
| 113 if (prev_instr != nullptr) { |
| 114 // Smash left into prev_instr, killing left. |
| 115 auto pred_moves = prev_instr->parallel_moves()[0]; |
| 116 CompressMoves(&temp_vector, pred_moves, left); |
| 117 } |
108 } | 118 } |
109 auto gap = GapInstruction::cast(instr); | 119 if (prev_instr != nullptr) { |
110 int i = FindFirstNonEmptySlot(gap); | 120 // Slide prev_instr down so we always know where to look for it. |
111 // Nothing to do here. | 121 std::swap(prev_instr->parallel_moves()[0], instr->parallel_moves()[0]); |
112 if (i == GapInstruction::LAST_INNER_POSITION + 1) { | |
113 if (prev_gap != nullptr) { | |
114 // Slide prev_gap down so we always know where to look for it. | |
115 std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]); | |
116 prev_gap = gap; | |
117 } | |
118 continue; | |
119 } | 122 } |
120 // Move the first non-empty gap to position 0. | 123 prev_instr = instr->parallel_moves()[0] == nullptr ? nullptr : instr; |
121 std::swap(gap->parallel_moves()[0], gap->parallel_moves()[i]); | 124 if (GapsCanMoveOver(instr)) continue; |
122 auto left = gap->parallel_moves()[0]; | 125 if (prev_instr != nullptr) { |
123 // Compress everything into position 0. | 126 to_finalize_.push_back(prev_instr); |
124 for (++i; i <= GapInstruction::LAST_INNER_POSITION; ++i) { | 127 prev_instr = nullptr; |
125 auto move = gap->parallel_moves()[i]; | |
126 if (move == nullptr) continue; | |
127 CompressMoves(&temp_vector, left, move); | |
128 } | 128 } |
129 if (prev_gap != nullptr) { | |
130 // Smash left into prev_gap, killing left. | |
131 auto pred_moves = prev_gap->parallel_moves()[0]; | |
132 CompressMoves(&temp_vector, pred_moves, left); | |
133 // Slide prev_gap down so we always know where to look for it. | |
134 std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]); | |
135 } | |
136 prev_gap = gap; | |
137 } | 129 } |
138 if (prev_gap != nullptr) to_finalize_.push_back(prev_gap); | 130 if (prev_instr != nullptr) { |
| 131 to_finalize_.push_back(prev_instr); |
| 132 } |
139 } | 133 } |
140 | 134 |
141 | 135 |
142 GapInstruction* MoveOptimizer::LastGap(InstructionBlock* block) { | 136 Instruction* MoveOptimizer::LastInstruction(InstructionBlock* block) { |
143 int gap_index = block->last_instruction_index() - 1; | 137 return code()->instructions()[block->last_instruction_index()]; |
144 auto instr = code()->instructions()[gap_index]; | |
145 return GapInstruction::cast(instr); | |
146 } | 138 } |
147 | 139 |
148 | 140 |
149 void MoveOptimizer::OptimizeMerge(InstructionBlock* block) { | 141 void MoveOptimizer::OptimizeMerge(InstructionBlock* block) { |
150 DCHECK(block->PredecessorCount() > 1); | 142 DCHECK(block->PredecessorCount() > 1); |
151 // Ensure that the last instruction in all incoming blocks don't contain | 143 // Ensure that the last instruction in all incoming blocks don't contain |
152 // things that would prevent moving gap moves across them. | 144 // things that would prevent moving gap moves across them. |
153 for (auto pred_index : block->predecessors()) { | 145 for (auto pred_index : block->predecessors()) { |
154 auto pred = code()->InstructionBlockAt(pred_index); | 146 auto pred = code()->InstructionBlockAt(pred_index); |
155 auto last_instr = code()->instructions()[pred->last_instruction_index()]; | 147 auto last_instr = code()->instructions()[pred->last_instruction_index()]; |
156 DCHECK(!last_instr->IsGapMoves()); | |
157 if (last_instr->IsSourcePosition()) continue; | 148 if (last_instr->IsSourcePosition()) continue; |
158 if (last_instr->IsCall()) return; | 149 if (last_instr->IsCall()) return; |
159 if (last_instr->TempCount() != 0) return; | 150 if (last_instr->TempCount() != 0) return; |
160 if (last_instr->OutputCount() != 0) return; | 151 if (last_instr->OutputCount() != 0) return; |
161 for (size_t i = 0; i < last_instr->InputCount(); ++i) { | 152 for (size_t i = 0; i < last_instr->InputCount(); ++i) { |
162 auto op = last_instr->InputAt(i); | 153 auto op = last_instr->InputAt(i); |
163 if (!op->IsConstant() && !op->IsImmediate()) return; | 154 if (!op->IsConstant() && !op->IsImmediate()) return; |
164 } | 155 } |
165 } | 156 } |
166 // TODO(dcarney): pass a ZonePool down for this? | 157 // TODO(dcarney): pass a ZonePool down for this? |
167 MoveMap move_map(local_zone()); | 158 MoveMap move_map(local_zone()); |
168 size_t correct_counts = 0; | 159 size_t correct_counts = 0; |
169 // Accumulate set of shared moves. | 160 // Accumulate set of shared moves. |
170 for (auto pred_index : block->predecessors()) { | 161 for (auto pred_index : block->predecessors()) { |
171 auto pred = code()->InstructionBlockAt(pred_index); | 162 auto pred = code()->InstructionBlockAt(pred_index); |
172 auto gap = LastGap(pred); | 163 auto instr = LastInstruction(pred); |
173 if (gap->parallel_moves()[0] == nullptr || | 164 if (instr->parallel_moves()[0] == nullptr || |
174 gap->parallel_moves()[0]->move_operands()->is_empty()) { | 165 instr->parallel_moves()[0]->move_operands()->is_empty()) { |
175 return; | 166 return; |
176 } | 167 } |
177 auto move_ops = gap->parallel_moves()[0]->move_operands(); | 168 auto move_ops = instr->parallel_moves()[0]->move_operands(); |
178 for (auto op = move_ops->begin(); op != move_ops->end(); ++op) { | 169 for (auto op = move_ops->begin(); op != move_ops->end(); ++op) { |
179 if (op->IsRedundant()) continue; | 170 if (op->IsRedundant()) continue; |
180 auto src = *op->source(); | 171 auto src = *op->source(); |
181 auto dst = *op->destination(); | 172 auto dst = *op->destination(); |
182 MoveKey key = {src, dst}; | 173 MoveKey key = {src, dst}; |
183 auto res = move_map.insert(std::make_pair(key, 1)); | 174 auto res = move_map.insert(std::make_pair(key, 1)); |
184 if (!res.second) { | 175 if (!res.second) { |
185 res.first->second++; | 176 res.first->second++; |
186 if (res.first->second == block->PredecessorCount()) { | 177 if (res.first->second == block->PredecessorCount()) { |
187 correct_counts++; | 178 correct_counts++; |
188 } | 179 } |
189 } | 180 } |
190 } | 181 } |
191 } | 182 } |
192 if (move_map.empty() || correct_counts != move_map.size()) return; | 183 if (move_map.empty() || correct_counts != move_map.size()) return; |
193 // Find insertion point. | 184 // Find insertion point. |
194 GapInstruction* gap = nullptr; | 185 Instruction* instr = nullptr; |
195 for (int i = block->first_instruction_index(); | 186 for (int i = block->first_instruction_index(); |
196 i <= block->last_instruction_index(); ++i) { | 187 i <= block->last_instruction_index(); ++i) { |
197 auto instr = code()->instructions()[i]; | 188 instr = code()->instructions()[i]; |
198 if (instr->IsGapMoves()) { | 189 if (!GapsCanMoveOver(instr) || !instr->AreMovesRedundant()) break; |
199 gap = GapInstruction::cast(instr); | |
200 continue; | |
201 } | |
202 if (!GapsCanMoveOver(instr)) break; | |
203 } | 190 } |
204 DCHECK(gap != nullptr); | 191 DCHECK(instr != nullptr); |
205 bool gap_initialized = true; | 192 bool gap_initialized = true; |
206 if (gap->parallel_moves()[0] == nullptr || | 193 if (instr->parallel_moves()[0] == nullptr || |
207 gap->parallel_moves()[0]->move_operands()->is_empty()) { | 194 instr->parallel_moves()[0]->move_operands()->is_empty()) { |
208 to_finalize_.push_back(gap); | 195 to_finalize_.push_back(instr); |
209 } else { | 196 } else { |
210 // Will compress after insertion. | 197 // Will compress after insertion. |
211 gap_initialized = false; | 198 gap_initialized = false; |
212 std::swap(gap->parallel_moves()[0], gap->parallel_moves()[1]); | 199 std::swap(instr->parallel_moves()[0], instr->parallel_moves()[1]); |
213 } | 200 } |
214 auto move = gap->GetOrCreateParallelMove( | 201 auto move = instr->GetOrCreateParallelMove( |
215 static_cast<GapInstruction::InnerPosition>(0), code_zone()); | 202 static_cast<Instruction::GapPosition>(0), code_zone()); |
216 // Delete relevant entries in predecessors and move everything to block. | 203 // Delete relevant entries in predecessors and move everything to block. |
217 bool first_iteration = true; | 204 bool first_iteration = true; |
218 for (auto pred_index : block->predecessors()) { | 205 for (auto pred_index : block->predecessors()) { |
219 auto pred = code()->InstructionBlockAt(pred_index); | 206 auto pred = code()->InstructionBlockAt(pred_index); |
220 auto gap = LastGap(pred); | 207 auto instr = LastInstruction(pred); |
221 auto move_ops = gap->parallel_moves()[0]->move_operands(); | 208 auto move_ops = instr->parallel_moves()[0]->move_operands(); |
222 for (auto op = move_ops->begin(); op != move_ops->end(); ++op) { | 209 for (auto op = move_ops->begin(); op != move_ops->end(); ++op) { |
223 if (op->IsRedundant()) continue; | 210 if (op->IsRedundant()) continue; |
224 MoveKey key = {*op->source(), *op->destination()}; | 211 MoveKey key = {*op->source(), *op->destination()}; |
225 auto it = move_map.find(key); | 212 auto it = move_map.find(key); |
226 USE(it); | 213 USE(it); |
227 DCHECK(it != move_map.end()); | 214 DCHECK(it != move_map.end()); |
228 if (first_iteration) { | 215 if (first_iteration) { |
229 move->AddMove(op->source(), op->destination(), code_zone()); | 216 move->AddMove(op->source(), op->destination(), code_zone()); |
230 } | 217 } |
231 op->Eliminate(); | 218 op->Eliminate(); |
232 } | 219 } |
233 first_iteration = false; | 220 first_iteration = false; |
234 } | 221 } |
235 // Compress. | 222 // Compress. |
236 if (!gap_initialized) { | 223 if (!gap_initialized) { |
237 CompressMoves(&temp_vector_0(), gap->parallel_moves()[0], | 224 CompressMoves(&temp_vector_0(), instr->parallel_moves()[0], |
238 gap->parallel_moves()[1]); | 225 instr->parallel_moves()[1]); |
239 } | 226 } |
240 } | 227 } |
241 | 228 |
242 | 229 |
243 // Split multiple loads of the same constant or stack slot off into the second | 230 // Split multiple loads of the same constant or stack slot off into the second |
244 // slot and keep remaining moves in the first slot. | 231 // slot and keep remaining moves in the first slot. |
245 void MoveOptimizer::FinalizeMoves(GapInstruction* gap) { | 232 void MoveOptimizer::FinalizeMoves(Instruction* instr) { |
246 auto loads = temp_vector_0(); | 233 auto loads = temp_vector_0(); |
247 DCHECK(loads.empty()); | 234 DCHECK(loads.empty()); |
248 auto new_moves = temp_vector_1(); | 235 auto new_moves = temp_vector_1(); |
249 DCHECK(new_moves.empty()); | 236 DCHECK(new_moves.empty()); |
250 auto move_ops = gap->parallel_moves()[0]->move_operands(); | 237 auto move_ops = instr->parallel_moves()[0]->move_operands(); |
251 for (auto move = move_ops->begin(); move != move_ops->end(); ++move) { | 238 for (auto move = move_ops->begin(); move != move_ops->end(); ++move) { |
252 if (move->IsRedundant()) { | 239 if (move->IsRedundant()) { |
253 move->Eliminate(); | 240 move->Eliminate(); |
254 continue; | 241 continue; |
255 } | 242 } |
256 if (!(move->source()->IsConstant() || move->source()->IsStackSlot() || | 243 if (!(move->source()->IsConstant() || move->source()->IsStackSlot() || |
257 move->source()->IsDoubleStackSlot())) | 244 move->source()->IsDoubleStackSlot())) |
258 continue; | 245 continue; |
259 // Search for existing move to this slot. | 246 // Search for existing move to this slot. |
260 MoveOperands* found = nullptr; | 247 MoveOperands* found = nullptr; |
(...skipping 26 matching lines...) Expand all Loading... |
287 found->destination()->ConvertTo(dest->kind(), dest->index()); | 274 found->destination()->ConvertTo(dest->kind(), dest->index()); |
288 move->set_destination(next_dest); | 275 move->set_destination(next_dest); |
289 } | 276 } |
290 // move from load destination. | 277 // move from load destination. |
291 move->set_source(found->destination()); | 278 move->set_source(found->destination()); |
292 new_moves.push_back(move); | 279 new_moves.push_back(move); |
293 } | 280 } |
294 loads.clear(); | 281 loads.clear(); |
295 if (new_moves.empty()) return; | 282 if (new_moves.empty()) return; |
296 // Insert all new moves into slot 1. | 283 // Insert all new moves into slot 1. |
297 auto slot_1 = gap->GetOrCreateParallelMove( | 284 auto slot_1 = instr->GetOrCreateParallelMove( |
298 static_cast<GapInstruction::InnerPosition>(1), code_zone()); | 285 static_cast<Instruction::GapPosition>(1), code_zone()); |
299 DCHECK(slot_1->move_operands()->is_empty()); | 286 DCHECK(slot_1->move_operands()->is_empty()); |
300 slot_1->move_operands()->AddBlock(MoveOperands(nullptr, nullptr), | 287 slot_1->move_operands()->AddBlock(MoveOperands(nullptr, nullptr), |
301 static_cast<int>(new_moves.size()), | 288 static_cast<int>(new_moves.size()), |
302 code_zone()); | 289 code_zone()); |
303 auto it = slot_1->move_operands()->begin(); | 290 auto it = slot_1->move_operands()->begin(); |
304 for (auto new_move : new_moves) { | 291 for (auto new_move : new_moves) { |
305 std::swap(*new_move, *it); | 292 std::swap(*new_move, *it); |
306 ++it; | 293 ++it; |
307 } | 294 } |
308 DCHECK_EQ(it, slot_1->move_operands()->end()); | 295 DCHECK_EQ(it, slot_1->move_operands()->end()); |
309 new_moves.clear(); | 296 new_moves.clear(); |
310 } | 297 } |
311 | 298 |
312 } // namespace compiler | 299 } // namespace compiler |
313 } // namespace internal | 300 } // namespace internal |
314 } // namespace v8 | 301 } // namespace v8 |
OLD | NEW |