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