blob: 5144704f222004dfd13e45afde576b02e540c768 [file] [log] [blame]
// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.DominatorTree;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.InternalOptions;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
public class DeadCodeRemover {
public static void removeDeadCode(
IRCode code, CodeRewriter codeRewriter, InternalOptions options) {
Queue<BasicBlock> worklist = new LinkedList<>();
int color = code.reserveMarkingColor();
worklist.addAll(code.blocks);
for (BasicBlock block = worklist.poll(); block != null; block = worklist.poll()) {
if (block.isMarked(color)) {
// Ignore marked blocks, as they are scheduled for removal.
continue;
}
removeDeadInstructions(worklist, code, block, options, color);
removeDeadPhis(worklist, block, options, color);
removeUnneededCatchHandlers(worklist, block, code, color);
}
code.removeMarkedBlocks(color);
code.returnMarkingColor(color);
assert code.isConsistentSSA();
codeRewriter.rewriteMoveResult(code);
}
// Add the block from where the value originates to the worklist.
private static void updateWorklist(Queue<BasicBlock> worklist, Value value, int color) {
BasicBlock block;
if (value.isPhi()) {
block = value.asPhi().getBlock();
} else {
block = value.definition.getBlock();
}
if (!block.isMarked(color)) {
worklist.add(block);
}
}
// Add all blocks from where the in/debug-values to the instruction originates.
private static void updateWorklist(
Queue<BasicBlock> worklist, Instruction instruction, int color) {
for (Value inValue : instruction.inValues()) {
updateWorklist(worklist, inValue, color);
}
for (Value debugValue : instruction.getDebugValues()) {
updateWorklist(worklist, debugValue, color);
}
}
private static void removeDeadPhis(Queue<BasicBlock> worklist, BasicBlock block,
InternalOptions options, int color) {
Iterator<Phi> phiIt = block.getPhis().iterator();
while (phiIt.hasNext()) {
Phi phi = phiIt.next();
if (phi.isDead(options)) {
phiIt.remove();
for (Value operand : phi.getOperands()) {
operand.removePhiUser(phi);
updateWorklist(worklist, operand, color);
}
}
}
}
private static void removeDeadInstructions(
Queue<BasicBlock> worklist, IRCode code, BasicBlock block, InternalOptions options,
int color) {
InstructionListIterator iterator = block.listIterator(block.getInstructions().size());
while (iterator.hasPrevious()) {
Instruction current = iterator.previous();
// Remove unused invoke results.
if (current.isInvoke()
&& current.outValue() != null
&& !current.outValue().isUsed()) {
current.setOutValue(null);
}
if (!current.canBeDeadCode(code, options)) {
continue;
}
Value outValue = current.outValue();
// Instructions with no out value cannot be dead code by the current definition
// (unused out value). They typically side-effect input values or deals with control-flow.
assert outValue != null;
if (!outValue.isDead(options)) {
continue;
}
updateWorklist(worklist, current, color);
// All users will be removed for this instruction. Eagerly clear them so further inspection
// of this instruction during dead code elimination will terminate here.
outValue.clearUsers();
iterator.removeOrReplaceByDebugLocalRead();
}
}
private static void removeUnneededCatchHandlers(Queue<BasicBlock> worklist, BasicBlock block,
IRCode code, int color) {
if (block.hasCatchHandlers() && !block.canThrow()) {
CatchHandlers<BasicBlock> handlers = block.getCatchHandlers();
for (BasicBlock target : handlers.getUniqueTargets()) {
DominatorTree dominatorTree = new DominatorTree(code);
for (BasicBlock unlinked : block.unlink(target, dominatorTree)) {
if (!unlinked.isMarked(color)) {
Iterator<Instruction> iterator = unlinked.iterator();
while (iterator.hasNext()) {
updateWorklist(worklist, iterator.next(), color);
}
unlinked.mark(color);
}
}
}
}
}
}