blob: 6269d1628e3d89d2861ce880c7f7f9833574da8c [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dead_code_elimination.h"
#include "base/bit_vector-inl.h"
#include "ssa_phi_elimination.h"
namespace art {
static void MarkReachableBlocks(HBasicBlock* block, ArenaBitVector* visited) {
int block_id = block->GetBlockId();
if (visited->IsBitSet(block_id)) {
return;
}
visited->SetBit(block_id);
HInstruction* last_instruction = block->GetLastInstruction();
if (last_instruction->IsIf()) {
HIf* if_instruction = last_instruction->AsIf();
HInstruction* condition = if_instruction->InputAt(0);
if (!condition->IsIntConstant()) {
MarkReachableBlocks(if_instruction->IfTrueSuccessor(), visited);
MarkReachableBlocks(if_instruction->IfFalseSuccessor(), visited);
} else if (condition->AsIntConstant()->IsOne()) {
MarkReachableBlocks(if_instruction->IfTrueSuccessor(), visited);
} else {
DCHECK(condition->AsIntConstant()->IsZero());
MarkReachableBlocks(if_instruction->IfFalseSuccessor(), visited);
}
} else {
for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
MarkReachableBlocks(block->GetSuccessors().Get(i), visited);
}
}
}
static void MarkLoopHeadersContaining(const HBasicBlock& block, ArenaBitVector* set) {
for (HLoopInformationOutwardIterator it(block); !it.Done(); it.Advance()) {
set->SetBit(it.Current()->GetHeader()->GetBlockId());
}
}
void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) {
if (stats_ != nullptr) {
stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction,
block->GetPhis().CountSize() + block->GetInstructions().CountSize());
}
}
void HDeadCodeElimination::RemoveDeadBlocks() {
// Classify blocks as reachable/unreachable.
ArenaAllocator* allocator = graph_->GetArena();
ArenaBitVector live_blocks(allocator, graph_->GetBlocks().Size(), false);
ArenaBitVector affected_loops(allocator, graph_->GetBlocks().Size(), false);
MarkReachableBlocks(graph_->GetEntryBlock(), &live_blocks);
bool removed_one_or_more_blocks = false;
// Remove all dead blocks. Iterate in post order because removal needs the
// block's chain of dominators and nested loops need to be updated from the
// inside out.
for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
int id = block->GetBlockId();
if (live_blocks.IsBitSet(id)) {
if (affected_loops.IsBitSet(id)) {
DCHECK(block->IsLoopHeader());
block->GetLoopInformation()->Update();
}
} else {
MaybeRecordDeadBlock(block);
MarkLoopHeadersContaining(*block, &affected_loops);
block->DisconnectAndDelete();
removed_one_or_more_blocks = true;
}
}
// If we removed at least one block, we need to recompute the full
// dominator tree.
if (removed_one_or_more_blocks) {
graph_->ClearDominanceInformation();
graph_->ComputeDominanceInformation();
}
// Connect successive blocks created by dead branches. Order does not matter.
for (HReversePostOrderIterator it(*graph_); !it.Done();) {
HBasicBlock* block = it.Current();
if (block->IsEntryBlock() || block->GetSuccessors().Size() != 1u) {
it.Advance();
continue;
}
HBasicBlock* successor = block->GetSuccessors().Get(0);
if (successor->IsExitBlock() || successor->GetPredecessors().Size() != 1u) {
it.Advance();
continue;
}
block->MergeWith(successor);
// Reiterate on this block in case it can be merged with its new successor.
}
}
void HDeadCodeElimination::RemoveDeadInstructions() {
// Process basic blocks in post-order in the dominator tree, so that
// a dead instruction depending on another dead instruction is removed.
for (HPostOrderIterator b(*graph_); !b.Done(); b.Advance()) {
HBasicBlock* block = b.Current();
// Traverse this block's instructions in backward order and remove
// the unused ones.
HBackwardInstructionIterator i(block->GetInstructions());
// Skip the first iteration, as the last instruction of a block is
// a branching instruction.
DCHECK(i.Current()->IsControlFlow());
for (i.Advance(); !i.Done(); i.Advance()) {
HInstruction* inst = i.Current();
DCHECK(!inst->IsControlFlow());
if (!inst->DoesAnyWrite()
&& !inst->CanThrow()
&& !inst->IsSuspendCheck()
// If we added an explicit barrier then we should keep it.
&& !inst->IsMemoryBarrier()
&& !inst->HasUses()) {
block->RemoveInstruction(inst);
MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction);
}
}
}
}
void HDeadCodeElimination::Run() {
RemoveDeadBlocks();
SsaRedundantPhiElimination(graph_).Run();
RemoveDeadInstructions();
}
} // namespace art