Merge "Fix performance of unneeded catch handler removal."
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index ee2c6ab..163c20b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -569,13 +569,15 @@
}
/**
- * Unlinks this block from a single predecessor and successor.
+ * Unlinks the current block based on the assumption that it is a catch handler.
*
- * @return Returns the unlinked successor
+ * Catch handlers always have only one predecessor and at most one successor.
+ * That is because we have edge-split form for all exceptional flow.
*/
- public BasicBlock unlinkSingle() {
- unlinkSinglePredecessor();
- return unlinkSingleSuccessor();
+ public void unlinkCatchHandler() {
+ assert predecessors.size() == 1;
+ predecessors.get(0).removeSuccessor(this);
+ predecessors.clear();
}
public void detachAllSuccessors() {
@@ -590,34 +592,41 @@
assert successor.predecessors.contains(this);
List<BasicBlock> removedBlocks = new ArrayList<>();
for (BasicBlock dominated : dominator.dominatedBlocks(successor)) {
+ dominated.cleanForRemoval();
removedBlocks.add(dominated);
- for (BasicBlock block : dominated.successors) {
- block.removePredecessor(dominated);
- }
- dominated.successors.clear();
- for (BasicBlock block : dominated.predecessors) {
- block.removeSuccessor(dominated);
- }
- dominated.predecessors.clear();
- for (Phi phi : dominated.getPhis()) {
- for (Value operand : phi.getOperands()) {
- operand.removePhiUser(phi);
- }
- }
- dominated.getPhis().clear();
- for (Instruction instruction : dominated.getInstructions()) {
- for (Value value : instruction.inValues) {
- value.removeUser(instruction);
- }
- for (Value value : instruction.getDebugValues()) {
- value.removeDebugUser(instruction);
- }
- }
}
assert blocksClean(removedBlocks);
return removedBlocks;
}
+ public void cleanForRemoval() {
+ for (BasicBlock block : successors) {
+ block.removePredecessor(this);
+ }
+ successors.clear();
+ for (BasicBlock block : predecessors) {
+ block.removeSuccessor(this);
+ }
+ predecessors.clear();
+ for (Phi phi : getPhis()) {
+ for (Value operand : phi.getOperands()) {
+ operand.removePhiUser(phi);
+ }
+ }
+ getPhis().clear();
+ for (Instruction instruction : getInstructions()) {
+ if (instruction.outValue != null) {
+ instruction.outValue.clearUsers();
+ }
+ for (Value value : instruction.inValues) {
+ value.removeUser(instruction);
+ }
+ for (Value value : instruction.getDebugValues()) {
+ value.removeDebugUser(instruction);
+ }
+ }
+ }
+
public void linkCatchSuccessors(List<DexType> guards, List<BasicBlock> targets) {
List<Integer> successorIndexes = new ArrayList<>(targets.size());
for (BasicBlock target : targets) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index bf62fed..2613aae 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -663,4 +663,31 @@
public boolean verifyNoColorsInUse() {
return usedMarkingColors == 0;
}
+
+ public void removeUnreachableBlocks() {
+ int color = reserveMarkingColor();
+ Queue<BasicBlock> worklist = new ArrayDeque<>();
+ worklist.add(blocks.getFirst());
+ while (!worklist.isEmpty()) {
+ BasicBlock block = worklist.poll();
+ if (block.isMarked(color)) {
+ continue;
+ }
+ block.mark(color);
+ for (BasicBlock successor : block.getSuccessors()) {
+ if (!successor.isMarked(color)) {
+ worklist.add(successor);
+ }
+ }
+ }
+ ListIterator<BasicBlock> blockIterator = listIterator();
+ while (blockIterator.hasNext()) {
+ BasicBlock current = blockIterator.next();
+ if (!current.isMarked(color)) {
+ current.cleanForRemoval();
+ blockIterator.remove();
+ }
+ }
+ returnMarkingColor(color);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index f767e1b..531989e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -5,7 +5,6 @@
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;
@@ -20,50 +19,43 @@
public static void removeDeadCode(
IRCode code, CodeRewriter codeRewriter, InternalOptions options) {
+ removeUnneededCatchHandlers(code);
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);
+ removeDeadInstructions(worklist, code, block, options);
+ removeDeadPhis(worklist, block, options);
}
- 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) {
+ private static void updateWorklist(Queue<BasicBlock> worklist, Value value) {
BasicBlock block = null;
if (value.isPhi()) {
block = value.asPhi().getBlock();
} else if (value.definition.hasBlock()) {
block = value.definition.getBlock();
}
- if (block != null && !block.isMarked(color)) {
+ if (block != null) {
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) {
+ Queue<BasicBlock> worklist, Instruction instruction) {
for (Value inValue : instruction.inValues()) {
- updateWorklist(worklist, inValue, color);
+ updateWorklist(worklist, inValue);
}
for (Value debugValue : instruction.getDebugValues()) {
- updateWorklist(worklist, debugValue, color);
+ updateWorklist(worklist, debugValue);
}
}
private static void removeDeadPhis(Queue<BasicBlock> worklist, BasicBlock block,
- InternalOptions options, int color) {
+ InternalOptions options) {
Iterator<Phi> phiIt = block.getPhis().iterator();
while (phiIt.hasNext()) {
Phi phi = phiIt.next();
@@ -71,15 +63,14 @@
phiIt.remove();
for (Value operand : phi.getOperands()) {
operand.removePhiUser(phi);
- updateWorklist(worklist, operand, color);
+ updateWorklist(worklist, operand);
}
}
}
}
private static void removeDeadInstructions(
- Queue<BasicBlock> worklist, IRCode code, BasicBlock block, InternalOptions options,
- int color) {
+ Queue<BasicBlock> worklist, IRCode code, BasicBlock block, InternalOptions options) {
InstructionListIterator iterator = block.listIterator(block.getInstructions().size());
while (iterator.hasPrevious()) {
Instruction current = iterator.previous();
@@ -99,7 +90,7 @@
if (!outValue.isDead(options)) {
continue;
}
- updateWorklist(worklist, current, color);
+ updateWorklist(worklist, current);
// 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();
@@ -107,22 +98,15 @@
}
}
- 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);
- }
+ private static void removeUnneededCatchHandlers(IRCode code) {
+ for (BasicBlock block : code.blocks) {
+ if (block.hasCatchHandlers() && !block.canThrow()) {
+ CatchHandlers<BasicBlock> handlers = block.getCatchHandlers();
+ for (BasicBlock target : handlers.getUniqueTargets()) {
+ target.unlinkCatchHandler();
}
}
}
+ code.removeUnreachableBlocks();
}
}