Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(336)

Unified Diff: src/compiler/move-optimizer.cc

Issue 755323011: [turbofan] optimize moves into merges (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/move-optimizer.h ('k') | test/unittests/compiler/move-optimizer-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/move-optimizer.cc
diff --git a/src/compiler/move-optimizer.cc b/src/compiler/move-optimizer.cc
index 330f32f65d584fba17d082f3d72924c9d97a6f6c..74fcabe161aec71c761b05e1218aa30475f1ce63 100644
--- a/src/compiler/move-optimizer.cc
+++ b/src/compiler/move-optimizer.cc
@@ -8,69 +8,70 @@ namespace v8 {
namespace internal {
namespace compiler {
+namespace {
+
+struct MoveKey {
Benedikt Meurer 2015/01/28 05:18:51 Once the issues mentioned below are addressed, how
dcarney 2015/02/02 09:23:33 Done.
+ InstructionOperand src;
+ InstructionOperand dst;
+};
+
+struct OperandLess {
Benedikt Meurer 2015/01/28 05:18:51 Can you add an operator< (and operator>) to Instru
dcarney 2015/02/02 09:23:33 now that it's 64 bits, it might be a little wierd,
+ bool operator()(const InstructionOperand a,
+ const InstructionOperand b) const {
+ if (a.kind() == b.kind()) return a.index() < b.index();
+ return a.kind() < b.kind();
+ }
+};
+
+struct MoveKeyLess {
+ bool operator()(const MoveKey& a, const MoveKey& b) const {
+ OperandLess operand_less;
+ if (a.src.Equals(&b.src)) return operand_less(a.dst, b.dst);
+ return operand_less(a.src, b.src);
+ }
+};
+
+typedef std::set<InstructionOperand, std::less<InstructionOperand>,
Benedikt Meurer 2015/01/28 05:18:51 I guess this shouldn't be std::less<InstructionOpe
dcarney 2015/02/02 09:23:33 Done.
+ zone_allocator<InstructionOperand>> OperandSetSuper;
+typedef std::map<MoveKey, unsigned, MoveKeyLess,
Benedikt Meurer 2015/01/28 05:18:51 How about adding ZoneSet and ZoneMap to zone-conta
dcarney 2015/02/02 09:23:33 Done.
+ zone_allocator<std::pair<const MoveKey, unsigned>>>
+ MoveMapSuper;
+
+
+class MoveMap : public MoveMapSuper {
+ public:
+ explicit MoveMap(Zone* zone)
+ : MoveMapSuper(key_compare(), allocator_type(zone)) {}
+};
+
+
+class OperandSet : public OperandSetSuper {
+ public:
+ explicit OperandSet(Zone* zone)
+ : OperandSetSuper(key_compare(), allocator_type(zone)) {}
+};
+
+} // namespace
+
+
MoveOptimizer::MoveOptimizer(Zone* local_zone, InstructionSequence* code)
: local_zone_(local_zone),
code_(code),
+ to_finalize_(local_zone),
temp_vector_0_(local_zone),
temp_vector_1_(local_zone) {}
void MoveOptimizer::Run() {
- // First smash all consecutive moves into the left most move slot.
for (auto* block : code()->instruction_blocks()) {
- GapInstruction* prev_gap = nullptr;
- for (int index = block->code_start(); index < block->code_end(); ++index) {
- auto instr = code()->instructions()[index];
- if (!instr->IsGapMoves()) {
- if (instr->IsSourcePosition() || instr->IsNop()) continue;
- FinalizeMoves(&temp_vector_0_, &temp_vector_1_, prev_gap);
- prev_gap = nullptr;
- continue;
- }
- auto gap = GapInstruction::cast(instr);
- // Find first non-empty slot.
- int i = GapInstruction::FIRST_INNER_POSITION;
- for (; i <= GapInstruction::LAST_INNER_POSITION; i++) {
- auto move = gap->parallel_moves()[i];
- if (move == nullptr) continue;
- auto move_ops = move->move_operands();
- auto op = move_ops->begin();
- for (; op != move_ops->end(); ++op) {
- if (!op->IsRedundant()) break;
- }
- if (op == move_ops->end()) {
- move_ops->Rewind(0); // Clear this redundant move.
- } else {
- break; // Found index of first non-redundant move.
- }
- }
- // Nothing to do here.
- if (i == GapInstruction::LAST_INNER_POSITION + 1) {
- if (prev_gap != nullptr) {
- // Slide prev_gap down so we always know where to look for it.
- std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]);
- prev_gap = gap;
- }
- continue;
- }
- // Move the first non-empty gap to position 0.
- std::swap(gap->parallel_moves()[0], gap->parallel_moves()[i]);
- auto left = gap->parallel_moves()[0];
- // Compress everything into position 0.
- for (++i; i <= GapInstruction::LAST_INNER_POSITION; ++i) {
- auto move = gap->parallel_moves()[i];
- if (move == nullptr) continue;
- CompressMoves(&temp_vector_0_, left, move);
- }
- if (prev_gap != nullptr) {
- // Smash left into prev_gap, killing left.
- auto pred_moves = prev_gap->parallel_moves()[0];
- CompressMoves(&temp_vector_0_, pred_moves, left);
- std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]);
- }
- prev_gap = gap;
- }
- FinalizeMoves(&temp_vector_0_, &temp_vector_1_, prev_gap);
+ CompressBlock(block);
+ }
+ for (auto block : code()->instruction_blocks()) {
+ if (block->PredecessorCount() <= 1) continue;
+ OptimizeMerge(block);
+ }
+ for (auto gap : to_finalize_) {
+ FinalizeMoves(gap);
}
}
@@ -106,21 +107,21 @@ void MoveOptimizer::CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
ParallelMove* right) {
DCHECK(eliminated->empty());
auto move_ops = right->move_operands();
- // Modify the right moves in place and collect moves that will be killed by
- // merging the two gaps.
- for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
- if (op->IsRedundant()) continue;
- MoveOperands* to_eliminate = PrepareInsertAfter(left, op, code_zone());
- if (to_eliminate != nullptr) {
- eliminated->push_back(to_eliminate);
+ if (!left->move_operands()->is_empty()) {
+ // Modify the right moves in place and collect moves that will be killed by
+ // merging the two gaps.
+ for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+ if (op->IsRedundant()) continue;
+ MoveOperands* to_eliminate = PrepareInsertAfter(left, op, code_zone());
+ if (to_eliminate != nullptr) eliminated->push_back(to_eliminate);
}
+ // Eliminate dead moves. Must happen before insertion of new moves as the
+ // contents of eliminated are pointers into a list.
+ for (auto to_eliminate : *eliminated) {
+ to_eliminate->Eliminate();
+ }
+ eliminated->clear();
}
- // Eliminate dead moves. Must happen before insertion of new moves as the
- // contents of eliminated are pointers into a list.
- for (auto to_eliminate : *eliminated) {
- to_eliminate->Eliminate();
- }
- eliminated->clear();
// Add all possibly modified moves from right side.
for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
if (op->IsRedundant()) continue;
@@ -131,13 +132,185 @@ void MoveOptimizer::CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
}
-void MoveOptimizer::FinalizeMoves(MoveOpVector* loads, MoveOpVector* new_moves,
- GapInstruction* gap) {
- DCHECK(loads->empty());
- DCHECK(new_moves->empty());
- if (gap == nullptr) return;
- // Split multiple loads of the same constant or stack slot off into the second
- // slot and keep remaining moves in the first slot.
+static bool GapsCanMoveOver(Instruction* instr) {
Benedikt Meurer 2015/01/28 05:18:51 Nit: use anonymous namespace instead of static.
+ DCHECK(!instr->IsGapMoves());
+ return instr->IsSourcePosition() || instr->IsNop();
+}
+
+
+static int FindFirstNonEmptySlot(GapInstruction* gap) {
Benedikt Meurer 2015/01/28 05:18:51 Nit: use anonymous namespace instead of static.
dcarney 2015/02/02 09:23:33 Done.
+ int i = GapInstruction::FIRST_INNER_POSITION;
+ for (; i <= GapInstruction::LAST_INNER_POSITION; i++) {
+ auto move = gap->parallel_moves()[i];
+ if (move == nullptr) continue;
+ auto move_ops = move->move_operands();
+ auto op = move_ops->begin();
+ for (; op != move_ops->end(); ++op) {
+ if (!op->IsRedundant()) break;
+ op->Eliminate();
+ }
+ if (op != move_ops->end()) break; // Found non-redundant move.
+ move_ops->Rewind(0); // Clear this redundant move.
+ }
+ return i;
+}
+
+
+// Smash all consecutive moves into the left most move slot and accumulate them
+// as much as possible across instructions.
+void MoveOptimizer::CompressBlock(InstructionBlock* block) {
+ auto temp_vector = temp_vector_0();
+ DCHECK(temp_vector.empty());
+ GapInstruction* prev_gap = nullptr;
+ for (int index = block->code_start(); index < block->code_end(); ++index) {
+ auto instr = code()->instructions()[index];
+ if (!instr->IsGapMoves()) {
+ if (GapsCanMoveOver(instr)) continue;
+ if (prev_gap != nullptr) to_finalize_.push_back(prev_gap);
+ prev_gap = nullptr;
+ continue;
+ }
+ auto gap = GapInstruction::cast(instr);
+ int i = FindFirstNonEmptySlot(gap);
+ // Nothing to do here.
+ if (i == GapInstruction::LAST_INNER_POSITION + 1) {
+ if (prev_gap != nullptr) {
+ // Slide prev_gap down so we always know where to look for it.
+ std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]);
+ prev_gap = gap;
+ }
+ continue;
+ }
+ // Move the first non-empty gap to position 0.
+ std::swap(gap->parallel_moves()[0], gap->parallel_moves()[i]);
+ auto left = gap->parallel_moves()[0];
+ // Compress everything into position 0.
+ for (++i; i <= GapInstruction::LAST_INNER_POSITION; ++i) {
+ auto move = gap->parallel_moves()[i];
+ if (move == nullptr) continue;
+ CompressMoves(&temp_vector, left, move);
+ }
+ if (prev_gap != nullptr) {
+ // Smash left into prev_gap, killing left.
+ auto pred_moves = prev_gap->parallel_moves()[0];
+ CompressMoves(&temp_vector, pred_moves, left);
+ // Slide prev_gap down so we always know where to look for it.
+ std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]);
+ }
+ prev_gap = gap;
+ }
+ if (prev_gap != nullptr) to_finalize_.push_back(prev_gap);
+}
+
+
+GapInstruction* MoveOptimizer::LastGap(InstructionBlock* block) {
+ int gap_index = block->last_instruction_index() - 1;
+ auto instr = code()->instructions()[gap_index];
+ return GapInstruction::cast(instr);
+}
+
+
+void MoveOptimizer::OptimizeMerge(InstructionBlock* block) {
+ DCHECK(block->PredecessorCount() > 1);
+ // Ensure that the last instruction in all incoming blocks don't contain
+ // things that would prevent moving gap moves across them.
+ for (auto pred_index : block->predecessors()) {
+ auto pred = code()->InstructionBlockAt(pred_index);
+ auto last_instr = code()->instructions()[pred->last_instruction_index()];
+ DCHECK(!last_instr->IsGapMoves());
+ if (last_instr->IsSourcePosition()) continue;
+ if (last_instr->IsCall()) return;
+ if (last_instr->TempCount() != 0) return;
+ if (last_instr->OutputCount() != 0) return;
+ for (size_t i = 0; i < last_instr->InputCount(); ++i) {
+ auto op = last_instr->InputAt(i);
+ if (!op->IsConstant() && !op->IsImmediate()) return;
+ }
+ }
+ // TODO(dcarney): pass a ZonePool down for this?
+ MoveMap move_map(local_zone());
+ size_t correct_counts = 0;
+ // Accumulate set of shared moves.
+ for (auto pred_index : block->predecessors()) {
+ auto pred = code()->InstructionBlockAt(pred_index);
+ auto gap = LastGap(pred);
+ if (gap->parallel_moves()[0] == nullptr ||
+ gap->parallel_moves()[0]->move_operands()->is_empty()) {
+ return;
+ }
+ auto move_ops = gap->parallel_moves()[0]->move_operands();
+ for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+ if (op->IsRedundant()) continue;
+ auto src = *op->source();
+ auto dst = *op->destination();
+ MoveKey key = {src, dst};
+ auto res = move_map.insert(std::make_pair(key, 1));
+ if (!res.second) {
+ res.first->second++;
+ if (res.first->second == block->PredecessorCount()) {
+ correct_counts++;
+ }
+ }
+ }
+ }
+ if (move_map.empty() || correct_counts != move_map.size()) return;
+ // Find insertion point.
+ GapInstruction* gap = nullptr;
+ for (int i = block->first_instruction_index();
+ i <= block->last_instruction_index(); ++i) {
+ auto instr = code()->instructions()[i];
+ if (instr->IsGapMoves()) {
+ gap = GapInstruction::cast(instr);
+ continue;
+ }
+ if (!GapsCanMoveOver(instr)) break;
+ }
+ DCHECK(gap != nullptr);
+ bool gap_initialized = true;
+ if (gap->parallel_moves()[0] == nullptr ||
+ gap->parallel_moves()[0]->move_operands()->is_empty()) {
+ to_finalize_.push_back(gap);
+ } else {
+ // Will compress after insertion.
+ gap_initialized = false;
+ std::swap(gap->parallel_moves()[0], gap->parallel_moves()[1]);
+ }
+ auto move = gap->GetOrCreateParallelMove(
+ static_cast<GapInstruction::InnerPosition>(0), code_zone());
+ // Delete relevant entries in predecessors and move everything to block.
+ bool first_iteration = true;
+ for (auto pred_index : block->predecessors()) {
+ auto pred = code()->InstructionBlockAt(pred_index);
+ auto gap = LastGap(pred);
+ auto move_ops = gap->parallel_moves()[0]->move_operands();
+ for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+ if (op->IsRedundant()) continue;
+ MoveKey key = {*op->source(), *op->destination()};
+ auto it = move_map.find(key);
+ DCHECK(it != move_map.end());
+ if (first_iteration) {
+ move->AddMove(op->source(), op->destination(), code_zone());
+ }
+ op->Eliminate();
+ }
+ first_iteration = false;
+ }
+ // Compress.
+ if (!gap_initialized) {
+ MoveOpVector temp_vector(local_zone());
+ CompressMoves(&temp_vector, gap->parallel_moves()[0],
+ gap->parallel_moves()[1]);
+ }
+}
+
+
+// Split multiple loads of the same constant or stack slot off into the second
+// slot and keep remaining moves in the first slot.
+void MoveOptimizer::FinalizeMoves(GapInstruction* gap) {
+ auto loads = temp_vector_0();
+ DCHECK(loads.empty());
+ auto new_moves = temp_vector_1();
+ DCHECK(new_moves.empty());
auto move_ops = gap->parallel_moves()[0]->move_operands();
for (auto move = move_ops->begin(); move != move_ops->end(); ++move) {
if (move->IsRedundant()) {
@@ -149,7 +322,7 @@ void MoveOptimizer::FinalizeMoves(MoveOpVector* loads, MoveOpVector* new_moves,
continue;
// Search for existing move to this slot.
MoveOperands* found = nullptr;
- for (auto load : *loads) {
+ for (auto load : loads) {
if (load->source()->Equals(move->source())) {
found = load;
break;
@@ -157,7 +330,7 @@ void MoveOptimizer::FinalizeMoves(MoveOpVector* loads, MoveOpVector* new_moves,
}
// Not found so insert.
if (found == nullptr) {
- loads->push_back(move);
+ loads.push_back(move);
// Replace source with copy for later use.
auto dest = move->destination();
move->set_destination(new (code_zone())
@@ -180,24 +353,24 @@ void MoveOptimizer::FinalizeMoves(MoveOpVector* loads, MoveOpVector* new_moves,
}
// move from load destination.
move->set_source(found->destination());
- new_moves->push_back(move);
+ new_moves.push_back(move);
}
- loads->clear();
- if (new_moves->empty()) return;
+ loads.clear();
+ if (new_moves.empty()) return;
// Insert all new moves into slot 1.
auto slot_1 = gap->GetOrCreateParallelMove(
static_cast<GapInstruction::InnerPosition>(1), code_zone());
DCHECK(slot_1->move_operands()->is_empty());
slot_1->move_operands()->AddBlock(MoveOperands(nullptr, nullptr),
- static_cast<int>(new_moves->size()),
+ static_cast<int>(new_moves.size()),
code_zone());
auto it = slot_1->move_operands()->begin();
- for (auto new_move : *new_moves) {
+ for (auto new_move : new_moves) {
std::swap(*new_move, *it);
++it;
}
DCHECK_EQ(it, slot_1->move_operands()->end());
- new_moves->clear();
+ new_moves.clear();
}
} // namespace compiler
« no previous file with comments | « src/compiler/move-optimizer.h ('k') | test/unittests/compiler/move-optimizer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698