[torque] Reduce generated CSA blocks

Significantly reduces the number of blocks in CSA code generated by
Torque by merging blocks along a straight-line path into a single
block.

Bug: v8:9861
Change-Id: I592cc1ed5b1ca0ad12c907d5cce7dcf7fec5f141
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1917157
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65181}
This commit is contained in:
Nico Hartmann 2019-11-26 16:29:05 +01:00 committed by Commit Bot
parent 3252ee85f3
commit aa36de6def
2 changed files with 66 additions and 0 deletions

View File

@ -160,6 +160,55 @@ void CfgAssembler::DebugBreak() {
Emit(AbortInstruction{AbortInstruction::Kind::kDebugBreak});
}
std::vector<std::size_t> CountBlockPredecessors(const ControlFlowGraph& cfg) {
std::vector<std::size_t> count(cfg.NumberOfBlockIds(), 0);
count[cfg.start()->id()] = 1;
for (const Block* block : cfg.blocks()) {
std::vector<Block*> successors;
for (const auto& instruction : block->instructions()) {
instruction->AppendSuccessorBlocks(&successors);
}
for (Block* successor : successors) {
DCHECK_LT(successor->id(), count.size());
++count[successor->id()];
}
}
return count;
}
void CfgAssembler::OptimizeCfg() {
auto predecessor_count = CountBlockPredecessors(cfg_);
for (Block* block : cfg_.blocks()) {
if (cfg_.end() && *cfg_.end() == block) continue;
if (predecessor_count[block->id()] == 0) continue;
while (!block->instructions().empty()) {
const auto& instruction = block->instructions().back();
if (!instruction.Is<GotoInstruction>()) break;
Block* destination = instruction.Cast<GotoInstruction>().destination;
if (destination == block) break;
if (cfg_.end() && *cfg_.end() == destination) break;
DCHECK_GT(predecessor_count[destination->id()], 0);
if (predecessor_count[destination->id()] != 1) break;
DCHECK_GT(destination->instructions().size(), 0);
block->instructions().pop_back();
block->instructions().insert(block->instructions().end(),
destination->instructions().begin(),
destination->instructions().end());
--predecessor_count[destination->id()];
DCHECK_EQ(predecessor_count[destination->id()], 0);
}
}
cfg_.UnplaceBlockIf(
[&](Block* b) { return predecessor_count[b->id()] == 0; });
}
} // namespace torque
} // namespace internal
} // namespace v8

View File

@ -45,6 +45,7 @@ class Block {
}
}
std::vector<Instruction>& instructions() { return instructions_; }
const std::vector<Instruction>& instructions() const { return instructions_; }
bool IsComplete() const {
return !instructions_.empty() && instructions_.back()->IsBlockTerminator();
@ -74,6 +75,12 @@ class ControlFlowGraph {
return &blocks_.back();
}
void PlaceBlock(Block* block) { placed_blocks_.push_back(block); }
template <typename UnaryPredicate>
void UnplaceBlockIf(UnaryPredicate&& predicate) {
auto newEnd = std::remove_if(placed_blocks_.begin(), placed_blocks_.end(),
std::forward<UnaryPredicate>(predicate));
placed_blocks_.erase(newEnd, placed_blocks_.end());
}
Block* start() const { return start_; }
base::Optional<Block*> end() const { return end_; }
void set_end(Block* end) { end_ = end; }
@ -87,6 +94,7 @@ class ControlFlowGraph {
}
}
const std::vector<Block*>& blocks() const { return placed_blocks_; }
size_t NumberOfBlockIds() const { return next_block_id_; }
private:
std::list<Block> blocks_;
@ -106,6 +114,8 @@ class CfgAssembler {
if (!CurrentBlockIsComplete()) {
cfg_.set_end(current_block_);
}
OptimizeCfg();
DCHECK(CfgIsComplete());
return cfg_;
}
@ -116,6 +126,12 @@ class CfgAssembler {
}
bool CurrentBlockIsComplete() const { return current_block_->IsComplete(); }
bool CfgIsComplete() const {
return std::all_of(
cfg_.blocks().begin(), cfg_.blocks().end(), [this](Block* block) {
return (cfg_.end() && *cfg_.end() == block) || block->IsComplete();
});
}
void Emit(Instruction instruction) {
instruction.TypeInstruction(&current_stack_, &cfg_);
@ -150,6 +166,7 @@ class CfgAssembler {
void DebugBreak();
void PrintCurrentStack(std::ostream& s) { s << "stack: " << current_stack_; }
void OptimizeCfg();
private:
friend class CfgAssemblerScopedTemporaryBlock;