[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:
parent
3252ee85f3
commit
aa36de6def
@ -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
|
||||
|
@ -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(¤t_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;
|
||||
|
Loading…
Reference in New Issue
Block a user