Extend redundant block removal to blocks with non-jump instructions
Change-Id: Ida0e3a5c91990a50488727df934efe500a51ae6e
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 50e4f53..3f61db3 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
@@ -886,7 +886,7 @@
private boolean noRedundantBlocks() {
for (BasicBlock block : blocks) {
- assert !isRedundantBlock(block);
+ assert !isBlockWithRedundantSuccessorBlock(block);
}
return true;
}
@@ -1315,7 +1315,30 @@
return true;
}
- private boolean isRedundantBlock(BasicBlock block) {
+ private boolean isBlockWithRedundantSuccessorBlock(BasicBlock block) {
+ if (options.debug) {
+ return isBlockWithRedundantSuccessorBlockInDebug(block);
+ } else {
+ return isBlockWithRedundantSuccessorBlockInRelease(block);
+ }
+ }
+
+ private boolean isBlockWithRedundantSuccessorBlockInRelease(BasicBlock block) {
+ if (!block.hasUniqueSuccessorWithUniquePredecessor()
+ || !block.exit().isGoto()
+ || !block.exit().getDebugValues().isEmpty()) {
+ return false;
+ }
+ BasicBlock successor = block.getUniqueSuccessor();
+ if (successor.hasCatchHandlers()) {
+ if (block.isEntry() || block.canThrow()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isBlockWithRedundantSuccessorBlockInDebug(BasicBlock block) {
return block.hasUniqueSuccessorWithUniquePredecessor()
&& block.getInstructions().size() == 1
&& block.exit().isGoto()
@@ -1324,31 +1347,59 @@
}
public void removeRedundantBlocks() {
- List<BasicBlock> blocksToRemove = new ArrayList<>();
-
+ // See b/237567012.
+ assert verifyNoStackInstructions();
+ Set<BasicBlock> blocksToRemove = Sets.newIdentityHashSet();
+ // Run over all blocks while merging successor blocks into the current block.
for (BasicBlock block : blocks) {
- // Check that there are no redundant blocks.
- assert !blocksToRemove.contains(block);
- if (isRedundantBlock(block)) {
- assert block.getUniqueSuccessor().getMutablePredecessors().size() == 1;
- assert block.getUniqueSuccessor().getMutablePredecessors().get(0) == block;
- assert block.getUniqueSuccessor().getPhis().size() == 0;
- // Let the successor consume this block.
+ if (blocksToRemove.contains(block)) {
+ continue;
+ }
+ while (isBlockWithRedundantSuccessorBlock(block)) {
+ // Let the current block consume the successor.;
BasicBlock successor = block.getUniqueSuccessor();
- successor.getMutablePredecessors().clear();
- successor.getMutablePredecessors().addAll(block.getPredecessors());
- successor.getPhis().addAll(block.getPhis());
- successor.getPhis().forEach(phi -> phi.setBlock(block.getUniqueSuccessor()));
- block
- .getPredecessors()
- .forEach(predecessors -> predecessors.replaceSuccessor(block, successor));
- block.getMutablePredecessors().clear();
+ assert !successor.hasCatchHandlers() || !block.canThrow();
+ assert !successor.hasPhis();
+ Instruction instruction = successor.entry();
+ while (instruction != null) {
+ Instruction next = instruction.getNext();
+ if (instruction.isJumpInstruction()) {
+ block.replaceLastInstruction(instruction);
+ } else {
+ block.getInstructions().addBefore(instruction, block.exit());
+ }
+ instruction = next;
+ }
+
+ // Unlink successor block.
block.getMutableSuccessors().clear();
- block.getPhis().clear();
- blocksToRemove.add(block);
+ if (successor.hasCatchHandlers()) {
+ block.moveCatchHandlers(successor);
+ }
+ block.getMutableSuccessors().addAll(successor.getSuccessors());
+ block.forEachNormalSuccessor(
+ successorOfSuccessor -> successorOfSuccessor.replacePredecessor(successor, block));
+
+ // Clean successor block and record for removal.
+ successor.getInstructions().clear();
+ successor.getMutablePredecessors().clear();
+ successor.getMutableSuccessors().clear();
+ blocksToRemove.add(successor);
}
}
blocks.removeAll(blocksToRemove);
+ assert noRedundantBlocks();
+ }
+
+ private boolean verifyNoStackInstructions() {
+ for (BasicBlock block : blocks) {
+ for (Instruction instruction : block.getInstructions()) {
+ assert !instruction.isStore();
+ assert !instruction.isPop();
+ assert !instruction.hasOutValue() || !instruction.outValue().isValueOnStack();
+ }
+ }
+ return true;
}
public boolean removeAllDeadAndTrivialPhis() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index da53eb3..b86c119 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -75,7 +75,7 @@
long paramNullCheckCount =
countCall(testMethod, "Intrinsics", "checkParameterIsNotNull");
// One after Iterator#hasNext, and another in the filter predicate: sinceYear != null.
- assertEquals(2, ifzCount);
+ assertEquals(testParameters.isCfRuntime() ? 5 : 2, ifzCount);
assertEquals(0, paramNullCheckCount);
});
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
index 8f359b5..d0faa2b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
@@ -105,12 +105,6 @@
inspector
.assertIsCompleteMergeGroup(
lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$1"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$2"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$3"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
getTestName(), "MainKt$testFirst$4"),
lambdasInInput.getKStyleLambdaReferenceFromTypeName(
getTestName(), "MainKt$testFirst$5"),
@@ -123,12 +117,6 @@
lambdasInInput.getKStyleLambdaReferenceFromTypeName(
getTestName(), "MainKt$testFirst$9"),
lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$1"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$2"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$3"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
getTestName(), "MainKt$testSecond$4"),
lambdasInInput.getKStyleLambdaReferenceFromTypeName(
getTestName(), "MainKt$testSecond$5"),
diff --git a/src/test/java/com/android/tools/r8/repackage/MappingFileAfterRepackagingTest.java b/src/test/java/com/android/tools/r8/repackage/MappingFileAfterRepackagingTest.java
index 1464cff..2c53eb2 100644
--- a/src/test/java/com/android/tools/r8/repackage/MappingFileAfterRepackagingTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/MappingFileAfterRepackagingTest.java
@@ -59,14 +59,18 @@
line.contains(
"java.lang.String MappingFileAfterRepackagingTest$A.toString()"))
.count();
- assertEquals(repackage ? 2 : 0, syntheticMatches);
+ assertEquals(
+ repackage ? 1 + BooleanUtils.intValue(parameters.isDexRuntime()) : 0,
+ syntheticMatches);
long unqualifiedMatches =
StringUtils.splitLines(runResult.proguardMap()).stream()
.filter(line -> line.contains("java.lang.String toString()"))
.count();
assertEquals(
- (repackage ? 1 : 3) + BooleanUtils.intValue(isPc2pc()), unqualifiedMatches);
+ (repackage ? 1 : 2 + BooleanUtils.intValue(parameters.isDexRuntime()))
+ + BooleanUtils.intValue(isPc2pc()),
+ unqualifiedMatches);
});
}
@@ -78,7 +82,7 @@
static class Main {
public static void main(String[] args) {
- System.out.println((System.currentTimeMillis() > 0 ? new A() : new B()));
+ System.out.println(System.currentTimeMillis() > 0 ? new A() : new B());
}
}