Merge "Make usage of basic block marks more explicit"
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 dbc3e90..1e076dd 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
@@ -414,29 +414,22 @@
}
}
- public void mark() {
- assert color == 0;
- color = 1;
+ public void mark(int color) {
+ assert color != 0;
+ assert !isMarked(color);
+ this.color |= color;
+ assert isMarked(color);
}
- public void clearMark() {
- color = 0;
+ public void clearMark(int color) {
+ assert color != 0;
+ this.color &= ~color;
+ assert !isMarked(color);
}
- public boolean isMarked() {
- return color == 1;
- }
-
- public void setColor(int color) {
- this.color = color;
- }
-
- public int getColor() {
- return color;
- }
-
- public boolean hasColor(int color) {
- return this.color == color;
+ public boolean isMarked(int color) {
+ assert color != 0;
+ return (this.color & color) != 0;
}
public void incrementUnfilledPredecessorCount() {
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 9595f5c..4862d70 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
@@ -33,6 +33,7 @@
public LinkedList<BasicBlock> blocks;
public final ValueNumberGenerator valueNumberGenerator;
+ private int usedMarkingColors = 0;
private boolean numbered = false;
private int nextInstructionNumber = 0;
@@ -157,17 +158,17 @@
public void traceBlocks() {
// Get the blocks first, as calling topologicallySortedBlocks also sets marks.
ImmutableList<BasicBlock> sorted = topologicallySortedBlocks();
- clearMarks();
+ int color = reserveMarkingColor();
int nextBlockNumber = blocks.size();
LinkedList<BasicBlock> tracedBlocks = new LinkedList<>();
for (BasicBlock block : sorted) {
- if (!block.isMarked()) {
- block.mark();
+ if (!block.isMarked(color)) {
+ block.mark(color);
tracedBlocks.add(block);
BasicBlock current = block;
BasicBlock fallthrough = block.exit().fallthroughBlock();
- while (fallthrough != null && !fallthrough.isMarked()) {
- fallthrough.mark();
+ while (fallthrough != null && !fallthrough.isMarked(color)) {
+ fallthrough.mark(color);
tracedBlocks.add(fallthrough);
current = fallthrough;
fallthrough = fallthrough.exit().fallthroughBlock();
@@ -177,12 +178,14 @@
current.exit().setFallthroughBlock(newFallthrough);
newFallthrough.getPredecessors().add(current);
fallthrough.replacePredecessor(current, newFallthrough);
- newFallthrough.mark();
+ newFallthrough.mark(color);
tracedBlocks.add(newFallthrough);
}
}
}
blocks = tracedBlocks;
+ returnMarkingColor(color);
+ assert verifyNoColorsInUse();
}
private void ensureBlockNumbering() {
@@ -206,22 +209,32 @@
return builder.toString();
}
- public void clearMarks() {
+ public void clearMarks(int color) {
for (BasicBlock block : blocks) {
- block.clearMark();
+ block.clearMark(color);
}
}
- public void removeMarkedBlocks() {
+ public void removeMarkedBlocks(int color) {
ListIterator<BasicBlock> blockIterator = listIterator();
while (blockIterator.hasNext()) {
BasicBlock block = blockIterator.next();
- if (block.isMarked()) {
+ if (block.isMarked(color)) {
blockIterator.remove();
}
}
}
+ private boolean verifyNoBlocksMarked(int color) {
+ for (BasicBlock block : blocks) {
+ if (block.isMarked(color)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
public void removeBlocks(List<BasicBlock> blocksToRemove) {
blocks.removeAll(blocksToRemove);
}
@@ -268,6 +281,7 @@
}
public boolean isConsistentGraph() {
+ assert verifyNoColorsInUse();
assert consistentBlockNumbering();
assert consistentPredecessorSuccessors();
assert consistentCatchHandlers();
@@ -588,4 +602,27 @@
}
}
}
+
+ public int reserveMarkingColor() {
+ int color = 1;
+ while ((usedMarkingColors & color) == color) {
+ assert color <= 0x40000000;
+ color <<= 1;
+ }
+ // TODO(sgjesse): Remove this assert if more colors will be required.
+ assert color == 1;
+ assert verifyNoBlocksMarked(color);
+ usedMarkingColors |= color;
+ return color;
+ }
+
+ public void returnMarkingColor(int color) {
+ assert (usedMarkingColors | color) == color;
+ clearMarks(color);
+ usedMarkingColors &= ~color;
+ }
+
+ public boolean verifyNoColorsInUse() {
+ return usedMarkingColors == 0;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 8684c75..eeb843c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -628,7 +628,7 @@
BasicBlock nextBlock;
// The marks will be used for cycle detection.
- code.clearMarks();
+ int color = code.reserveMarkingColor();
do {
nextBlock = iterator.hasNext() ? iterator.next() : null;
if (block.isTrivialGoto()) {
@@ -657,6 +657,7 @@
} while (block != null);
code.removeBlocks(blocksToRemove);
}
+ code.returnMarkingColor(color);
assert removedTrivialGotos(code);
assert code.isConsistentGraph();
}
@@ -1701,16 +1702,16 @@
public void simplifyIf(IRCode code) {
Supplier<DominatorTree> dominatorTreeMemoization = Suppliers
.memoize(() -> new DominatorTree(code));
- code.clearMarks();
+ int color = code.reserveMarkingColor();
for (BasicBlock block : code.blocks) {
- if (block.isMarked()) {
+ if (block.isMarked(color)) {
continue;
}
if (block.exit().isIf()) {
// First rewrite zero comparison.
rewriteIfWithConstZero(block);
- if (simplifyKnownBooleanCondition(code, dominatorTreeMemoization, block)) {
+ if (simplifyKnownBooleanCondition(code, dominatorTreeMemoization, block, color)) {
continue;
}
@@ -1756,10 +1757,11 @@
BasicBlock target = theIf.targetFromCondition(cond);
BasicBlock deadTarget =
target == theIf.getTrueTarget() ? theIf.fallthroughBlock() : theIf.getTrueTarget();
- rewriteIfToGoto(dominatorTreeMemoization, block, theIf, target, deadTarget);
+ rewriteIfToGoto(dominatorTreeMemoization, block, theIf, target, deadTarget, color);
}
}
- code.removeMarkedBlocks();
+ code.removeMarkedBlocks(color);
+ code.returnMarkingColor(color);
assert code.isConsistentSSA();
}
@@ -1795,7 +1797,7 @@
* by an xor instruction which is smaller.
*/
private boolean simplifyKnownBooleanCondition(IRCode code,
- Supplier<DominatorTree> dominatorTreeMemoization, BasicBlock block) {
+ Supplier<DominatorTree> dominatorTreeMemoization, BasicBlock block, int color) {
If theIf = block.exit().asIf();
Value testValue = theIf.inValues().get(0);
if (theIf.isZeroTest() && testValue.knownToBeBoolean()) {
@@ -1857,7 +1859,7 @@
// If all phis were removed, there is no need for the diamond shape anymore
// and it can be rewritten to a goto to one of the branches.
if (deadPhis == targetBlock.getPhis().size()) {
- rewriteIfToGoto(dominatorTreeMemoization, block, theIf, trueBlock, falseBlock);
+ rewriteIfToGoto(dominatorTreeMemoization, block, theIf, trueBlock, falseBlock, color);
return true;
}
}
@@ -1900,11 +1902,11 @@
}
private void rewriteIfToGoto(Supplier<DominatorTree> dominatorTreeMemoization, BasicBlock block,
- If theIf, BasicBlock target, BasicBlock deadTarget) {
+ If theIf, BasicBlock target, BasicBlock deadTarget, int color) {
List<BasicBlock> removedBlocks = block.unlink(deadTarget, dominatorTreeMemoization.get());
for (BasicBlock removedBlock : removedBlocks) {
- if (!removedBlock.isMarked()) {
- removedBlock.mark();
+ if (!removedBlock.isMarked(color)) {
+ removedBlock.mark(color);
}
}
assert theIf == block.exit();
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 fc9a16b..88f9e63 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
@@ -25,47 +25,49 @@
Queue<BasicBlock> worklist = new LinkedList<>();
Supplier<DominatorTree> dominatorTreeMemoization = Suppliers
.memoize(() -> new DominatorTree(code));
- code.clearMarks();
+ int color = code.reserveMarkingColor();
worklist.addAll(code.blocks);
for (BasicBlock block = worklist.poll(); block != null; block = worklist.poll()) {
- if (block.isMarked()) {
+ if (block.isMarked(color)) {
// Ignore marked blocks, as they are scheduled for removal.
continue;
}
- removeDeadInstructions(worklist, code, block, options);
- removeDeadPhis(worklist, block, options);
- removeUnneededCatchHandlers(worklist, block, dominatorTreeMemoization);
+ removeDeadInstructions(worklist, code, block, options, color);
+ removeDeadPhis(worklist, block, options, color);
+ removeUnneededCatchHandlers(worklist, block, dominatorTreeMemoization, color);
}
- code.removeMarkedBlocks();
+ 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) {
+ 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()) {
+ 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) {
+ private static void updateWorklist(
+ Queue<BasicBlock> worklist, Instruction instruction, int color) {
for (Value inValue : instruction.inValues()) {
- updateWorklist(worklist, inValue);
+ updateWorklist(worklist, inValue, color);
}
for (Value debugValue : instruction.getDebugValues()) {
- updateWorklist(worklist, debugValue);
+ updateWorklist(worklist, debugValue, color);
}
}
private static void removeDeadPhis(Queue<BasicBlock> worklist, BasicBlock block,
- InternalOptions options) {
+ InternalOptions options, int color) {
Iterator<Phi> phiIt = block.getPhis().iterator();
while (phiIt.hasNext()) {
Phi phi = phiIt.next();
@@ -73,14 +75,15 @@
phiIt.remove();
for (Value operand : phi.getOperands()) {
operand.removePhiUser(phi);
- updateWorklist(worklist, operand);
+ updateWorklist(worklist, operand, color);
}
}
}
}
private static void removeDeadInstructions(
- Queue<BasicBlock> worklist, IRCode code, BasicBlock block, InternalOptions options) {
+ 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();
@@ -101,7 +104,7 @@
continue;
}
- updateWorklist(worklist, current);
+ 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();
@@ -110,17 +113,17 @@
}
private static void removeUnneededCatchHandlers(Queue<BasicBlock> worklist, BasicBlock block,
- Supplier<DominatorTree> dominatorTreeMemoization) {
+ Supplier<DominatorTree> dominatorTreeMemoization, int color) {
if (block.hasCatchHandlers() && !block.canThrow()) {
CatchHandlers<BasicBlock> handlers = block.getCatchHandlers();
for (BasicBlock target : handlers.getUniqueTargets()) {
for (BasicBlock unlinked : block.unlink(target, dominatorTreeMemoization.get())) {
- if (!unlinked.isMarked()) {
+ if (!unlinked.isMarked(color)) {
Iterator<Instruction> iterator = unlinked.iterator();
while (iterator.hasNext()) {
- updateWorklist(worklist, iterator.next());
+ updateWorklist(worklist, iterator.next(), color);
}
- unlinked.mark();
+ unlinked.mark(color);
}
}
}