HLoopInformation::HLoopInformation(HBasicBlock* header, HGraph* graph)
: header_(header),
suspend_check_(nullptr),
irreducible_(false),
contains_irreducible_loop_(false),
back_edges_(graph->GetAllocator()->Adapter(kArenaAllocLoopInfoBackEdges)), // Make bit vector growable, as the number of blocks may change.
block_mask_(graph->GetAllocator(),
graph->GetBlocks().size(), /*expandable=*/ true,
kArenaAllocLoopInfoBackEdges) {
back_edges_.reserve(kDefaultNumberOfBackEdges);
}
void HLoopInformation::Dump(std::ostream& os) {
os << "header: " << header_->GetBlockId() << std::endl;
os << "pre header: " << GetPreHeader()->GetBlockId() << std::endl; for (HBasicBlock* block : back_edges_) {
os << "back edge: " << block->GetBlockId() << std::endl;
} for (HBasicBlock* block : header_->GetPredecessors()) {
os << "predecessor: " << block->GetBlockId() << std::endl;
} for (uint32_t idx : block_mask_.Indexes()) {
os << " in loop: " << idx << std::endl;
}
}
block_mask_.SetBit(block->GetBlockId());
MarkInLoop(block); if (block->IsLoopHeader()) { // We're visiting loops in post-order, so inner loops must have been // populated already.
DCHECK(block->GetLoopInformation()->IsPopulated()); if (block->GetLoopInformation()->ContainsIrreducibleLoop()) {
contains_irreducible_loop_ = true;
}
}
constbool is_catch_block = block->IsCatchBlock(); if (is_catch_block) { auto it = blocks_in_catch.find(block); if (it != blocks_in_catch.end()) { const ArenaSet<HBasicBlock*>& try_blocks = it->second; for (HBasicBlock* try_block : try_blocks) {
PopulateRecursive(try_block, blocks_in_catch);
}
}
}
for (HBasicBlock* predecessor : block->GetPredecessors()) { if (is_catch_block) {
DCHECK(predecessor->EndsWithTryBoundary()); if (predecessor->GetLastInstruction()->AsTryBoundary()->IsEntry()) { // Predecessors that are try entries cannot flow to the catch block as they are outside of // the try. continue;
}
}
PopulateRecursive(predecessor, blocks_in_catch);
}
}
// If `block` is in `finalized`, we know its membership in the loop has been // decided and it does not need to be revisited. if (finalized->IsBitSet(block_id)) { return;
}
bool is_finalized = false; if (block->IsLoopHeader()) { // If we hit a loop header in an irreducible loop, we first check if the // pre header of that loop belongs to the currently analyzed loop. If it does, // then we visit the back edges. // Note that we cannot use GetPreHeader, as the loop may have not been populated // yet.
HBasicBlock* pre_header = block->GetPredecessors()[0];
PopulateIrreducibleRecursive(pre_header, finalized, blocks_in_catch); if (block_mask_.IsBitSet(pre_header->GetBlockId())) {
MarkInLoop(block);
block_mask_.SetBit(block_id);
finalized->SetBit(block_id);
is_finalized = true;
HLoopInformation* info = block->GetLoopInformation(); for (HBasicBlock* back_edge : info->GetBackEdges()) {
PopulateIrreducibleRecursive(back_edge, finalized, blocks_in_catch);
}
}
} else { // Visit all predecessors. If one predecessor is part of the loop, this // block is also part of this loop. auto process_predecessor = [&](HBasicBlock* predecessor) ALWAYS_INLINE {
PopulateIrreducibleRecursive(predecessor, finalized, blocks_in_catch); if (!is_finalized && block_mask_.IsBitSet(predecessor->GetBlockId())) {
MarkInLoop(block);
block_mask_.SetBit(block_id);
finalized->SetBit(block_id);
is_finalized = true;
}
};
constbool is_catch_block = block->IsCatchBlock(); if (is_catch_block) { auto it = blocks_in_catch.find(block); if (it != blocks_in_catch.end()) { const ArenaSet<HBasicBlock*>& try_blocks = it->second; for (HBasicBlock* try_block : try_blocks) {
process_predecessor(try_block);
}
}
}
for (HBasicBlock* predecessor : block->GetPredecessors()) { if (is_catch_block) {
DCHECK(predecessor->EndsWithTryBoundary()); if (predecessor->GetLastInstruction()->AsTryBoundary()->IsEntry()) { // Predecessors that are try entries cannot flow to the catch block as they are outside of // the try. continue;
}
}
process_predecessor(predecessor);
}
}
// All predecessors have been recursively visited. Mark finalized if not marked yet. if (!is_finalized) {
finalized->SetBit(block_id);
}
}
void HLoopInformation::Populate() {
DCHECK_EQ(block_mask_.NumSetBits(), 0u) << "Loop information has already been populated"; // Populate this loop: starting with the back edge, recursively add predecessors // that are not already part of that loop. Set the header as part of the loop // to end the recursion. // This is a recursive implementation of the algorithm described in // "Advanced Compiler Design & Implementation" (Muchnick) p192.
HGraph* graph = header_->GetGraph();
block_mask_.SetBit(header_->GetBlockId());
MarkInLoop(header_);
if (!is_irreducible_loop && graph->IsCompilingOsr()) { // When compiling in OSR mode, all loops in the compiled method may be entered // from the interpreter. We treat this OSR entry point just like an extra entry // to an irreducible loop, so we need to mark the method's loops as irreducible. // This does not apply to inlined loops which do not act as OSR entry points. if (suspend_check_ == nullptr) { // Just building the graph in OSR mode, this loop is not inlined. We never build an // inner graph in OSR mode as we can do OSR transition only from the outer method.
is_irreducible_loop = true;
} else { // Look at the suspend check's environment to determine if the loop was inlined.
DCHECK(suspend_check_->HasEnvironment()); if (!suspend_check_->GetEnvironment()->IsFromInlinedInvoke()) {
is_irreducible_loop = true;
}
}
} if (is_irreducible_loop) {
irreducible_ = true;
contains_irreducible_loop_ = true;
graph->SetHasIrreducibleLoops(true);
}
graph->SetHasLoops(true);
}
bool HLoopInformation::DominatesAllBackEdges(HBasicBlock* block) { for (HBasicBlock* back_edge : GetBackEdges()) { if (!block->Dominates(back_edge)) { returnfalse;
}
} returntrue;
}
bool HLoopInformation::HasExitEdge() const { // Determine if this loop has at least one exit edge. for (HBasicBlock* block : GetBlocks()) { for (HBasicBlock* successor : block->GetSuccessors()) { if (!Contains(*successor)) { returntrue;
}
}
} returnfalse;
}
inlinevoid HLoopInformation::MarkInLoop(HBasicBlock* block) { if (!block->IsInLoop()) {
block->SetLoopInformation(this);
} elseif (block->IsLoopHeader()) { // Nothing to do. This just means `*this` is an outer loop.
} elseif (block->GetLoopInformation()->Contains(*GetHeader())) { // The `block` is currently part of an outer loop. Make it part of this inner loop. // Note that a non loop header having a loop information means this loop information // has already been populated
block->SetLoopInformation(this);
} elseif (IsBackEdge(*block)) { // If the `block` is a back edge of the current loop, it must point to this loop.
block->SetLoopInformation(this);
} else { // The `block` is part of an inner loop. Do not update the loop information. // Note that we cannot do the check `Contains(block->GetLoopInformation()->GetHeader())` // at this point, because this function is being called while populating `*this`.
}
}
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.