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

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: fix Created 5 years, 10 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') | src/compiler/register-allocator-verifier.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 f7abcf462d6f6f17f6c78ac568d378de7e6de3f2..2c4c720d263b50bd909acd5800b2eccd8df6bc48 100644
--- a/src/compiler/move-optimizer.cc
+++ b/src/compiler/move-optimizer.cc
@@ -10,6 +10,11 @@ namespace compiler {
namespace {
+typedef std::pair<InstructionOperand, InstructionOperand> MoveKey;
+typedef ZoneMap<MoveKey, unsigned> MoveMap;
+typedef ZoneSet<InstructionOperand> OperandSet;
+
+
bool GapsCanMoveOver(Instruction* instr) {
DCHECK(!instr->IsGapMoves());
return instr->IsSourcePosition() || instr->IsNop();
@@ -48,6 +53,10 @@ void MoveOptimizer::Run() {
for (auto* block : code()->instruction_blocks()) {
CompressBlock(block);
}
+ for (auto block : code()->instruction_blocks()) {
+ if (block->PredecessorCount() <= 1) continue;
+ OptimizeMerge(block);
+ }
for (auto gap : to_finalize_) {
FinalizeMoves(gap);
}
@@ -130,6 +139,107 @@ void MoveOptimizer::CompressBlock(InstructionBlock* block) {
}
+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);
brucedawson 2015/04/06 18:05:31 This line of code is worrisome because it shadows
+ 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);
+ USE(it);
+ 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) {
+ CompressMoves(&temp_vector_0(), 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) {
« no previous file with comments | « src/compiler/move-optimizer.h ('k') | src/compiler/register-allocator-verifier.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698