void SsaDeadPhiElimination::MarkDeadPhis() { // Use local allocator for allocating memory used by this optimization.
ScopedArenaAllocator allocator(graph_->GetArenaStack());
// Phis are constructed live and should not be revived if previously marked // dead. This algorithm temporarily breaks that invariant but we DCHECK that // only phis which were initially live are revived.
ScopedArenaSet<HPhi*> initially_live(allocator.Adapter(kArenaAllocSsaPhiElimination));
// Add to the worklist phis referenced by non-phi instructions. for (HBasicBlock* block : graph_->GetReversePostOrder()) { for (HInstructionIteratorPrefetchNext inst_it(block->GetPhis()); !inst_it.Done();
inst_it.Advance()) {
HPhi* phi = inst_it.Current()->AsPhi(); if (phi->IsDead()) { continue;
}
bool keep_alive = (graph_->IsDebuggable() && phi->HasEnvironmentUses()); if (!keep_alive) { for (const HUseListNode<HInstruction*>& use : phi->GetUses()) { if (!use.GetUser()->IsPhi()) {
keep_alive = true; break;
}
}
}
if (keep_alive) {
worklist.push_back(phi);
} else {
phi->SetDead(); if (kIsDebugBuild) {
initially_live.insert(phi);
}
}
}
}
// Process the worklist by propagating liveness to phi inputs. while (!worklist.empty()) {
HPhi* phi = worklist.back();
worklist.pop_back(); for (HInstruction* raw_input : phi->GetInputs()) {
HPhi* input = raw_input->AsPhiOrNull(); if (input != nullptr && input->IsDead()) { // Input is a dead phi. Revive it and add to the worklist. We make sure // that the phi was not dead initially (see definition of `initially_live`).
DCHECK(ContainsElement(initially_live, input));
input->SetLive();
worklist.push_back(input);
}
}
}
}
void SsaDeadPhiElimination::EliminateDeadPhis() { // Remove phis that are not live. Visit in post order so that phis // that are not inputs of loop phis can be removed when they have // no users left (dead phis might use dead phis). for (HBasicBlock* block : graph_->GetPostOrder()) {
HInstruction* current = block->GetFirstPhi();
HInstruction* next = nullptr;
HPhi* phi; while (current != nullptr) {
phi = current->AsPhi();
next = current->GetNext(); if (phi->IsDead()) { // Make sure the phi is only used by other dead phis. if (kIsDebugBuild) { for (const HUseListNode<HInstruction*>& use : phi->GetUses()) {
HInstruction* user = use.GetUser();
DCHECK(user->IsLoopHeaderPhi());
DCHECK(user->AsPhi()->IsDead());
}
} // Remove the phi from use lists of its inputs.
phi->RemoveAsUserOfAllInputs(); // Remove the phi from environments that use it. for (const HUseListNode<HEnvironment*>& use : phi->GetEnvUses()) {
HEnvironment* user = use.GetUser();
user->SetRawEnvAt(use.GetIndex(), nullptr);
} // Delete it from the instruction list.
block->RemovePhi(phi, /*ensure_safety=*/ false);
}
current = next;
}
}
}
bool SsaRedundantPhiElimination::Run() { // Use local allocator for allocating memory used by this optimization.
ScopedArenaAllocator allocator(graph_->GetArenaStack());
// Add all phis in the worklist. Order does not matter for correctness, and // neither will necessarily converge faster. for (HBasicBlock* block : graph_->GetReversePostOrder()) { for (HInstructionIteratorPrefetchNext inst_it(block->GetPhis()); !inst_it.Done();
inst_it.Advance()) {
worklist.push_back(inst_it.Current()->AsPhi());
}
}
// First do a simple loop over inputs and check if they are all the same. for (HInstruction* input : phi->GetInputs()) { if (input == phi) { continue;
} elseif (candidate == nullptr) {
candidate = input;
} elseif (candidate != input) {
candidate = nullptr; break;
}
}
// If we haven't found a candidate, check for a phi cycle. Note that we need to detect // such cycles to avoid having reference and non-reference equivalents. We check this // invariant in the graph checker. if (candidate == nullptr) { // We iterate over the array as long as it grows. for (size_t i = 0; i < cycle_worklist.size(); ++i) {
HPhi* current = cycle_worklist[i];
DCHECK_IMPLIES(current->IsLoopHeaderPhi(),
current->GetBlock()->IsLoopPreHeaderFirstPredecessor());
for (HInstruction* input : current->GetInputs()) { if (input == current) { continue;
} elseif (input->IsPhi()) { if (!visited_phis_in_cycle.IsBitSet(input->GetId())) {
cycle_worklist.push_back(input->AsPhi());
visited_phis_in_cycle.SetBit(input->GetId());
catch_phi_in_cycle |= input->AsPhi()->IsCatchPhi();
irreducible_loop_phi_in_cycle |= IsIrreducibleLoopHeaderPhi(input->AsPhi());
} else { // Already visited, nothing to do.
}
} elseif (candidate == nullptr) {
candidate = input;
} elseif (candidate != input) {
candidate = nullptr; // Clear the cycle worklist to break out of the outer loop.
cycle_worklist.clear(); break;
}
}
}
}
if (candidate == nullptr) { continue;
}
if (irreducible_loop_phi_in_cycle && !candidate->IsConstant()) { // For irreducible loops, we need to keep the phis to satisfy our linear scan // algorithm. // There is one exception for constants, as the type propagation requires redundant // cyclic phis of a constant to be removed. This is ok for the linear scan as it // has to deal with constants anyway, and they can trivially be rematerialized. continue;
}
for (HPhi* current : cycle_worklist) { // The candidate may not dominate a phi in a catch block: there may be non-throwing // instructions at the beginning of a try range, that may be the first input of // catch phis. // TODO(dbrazdil): Remove this situation by moving those non-throwing instructions // before the try entry. if (catch_phi_in_cycle) { if (!candidate->StrictlyDominates(current)) { continue;
}
} else {
DCHECK(candidate->StrictlyDominates(current));
}
// Because we're updating the users of this phi, we may have new candidates // for elimination. Add phis that use this phi to the worklist. for (const HUseListNode<HInstruction*>& use : current->GetUses()) {
HInstruction* user = use.GetUser(); if (user->IsPhi() && !visited_phis_in_cycle.IsBitSet(user->GetId())) {
worklist.push_back(user->AsPhi());
}
}
DCHECK(candidate->StrictlyDominates(current));
current->ReplaceWith(candidate);
current->GetBlock()->RemovePhi(current);
}
} returntrue;
}
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.10 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.