summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Geoffray <ngeoffray@google.com>2015-06-19 16:17:05 +0100
committerNicolas Geoffray <ngeoffray@google.com>2015-06-22 12:38:56 +0100
commit1e256bf257e8d97df9b2178ae8658b731ca2d662 (patch)
treeaa13e2795a2b9e1469a941af4856ae1751cf48db
parentbbcec62c0484fbfb82ee2c317e8afa478a63027b (diff)
downloadart-1e256bf257e8d97df9b2178ae8658b731ca2d662.zip
art-1e256bf257e8d97df9b2178ae8658b731ca2d662.tar.gz
art-1e256bf257e8d97df9b2178ae8658b731ca2d662.tar.bz2
Be careful with predecessor/successor index.
When we simplify the CFG, we must preserve things that were already simplified. For example, the index in the predecessor list or successor list of a block must be preserved for ensuring the first block is a loop pre header. bug:21867463 (cherry picked from commit 8b20f88b0a8d1b374dd5eaae289d19734c77b8f8) Change-Id: I2581b5a50942290da96cd9ec876f6f2573e0a6c4
-rw-r--r--compiler/optimizing/constant_folding_test.cc4
-rw-r--r--compiler/optimizing/dead_code_elimination_test.cc6
-rw-r--r--compiler/optimizing/nodes.cc5
-rw-r--r--compiler/optimizing/nodes.h14
-rw-r--r--compiler/optimizing/ssa_test.cc14
-rw-r--r--test/485-checker-dce-loop-update/smali/TestCase.smali4
-rw-r--r--test/509-pre-header/expected.txt1
-rw-r--r--test/509-pre-header/info.txt3
-rw-r--r--test/509-pre-header/smali/PreHeader.smali39
-rw-r--r--test/509-pre-header/src/Main.java28
10 files changed, 102 insertions, 16 deletions
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 422223f..11f6362 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -627,8 +627,8 @@ TEST(ConstantFolding, ConstantCondition) {
" 9: If(8)\n"
"BasicBlock 2, pred: 1, succ: 3\n"
" 12: Goto 3\n"
- "BasicBlock 3, pred: 2, 5, succ: 4\n"
- " 22: Phi(3, 5) [15]\n"
+ "BasicBlock 3, pred: 5, 2, succ: 4\n"
+ " 22: Phi(5, 3) [15]\n"
" 15: Add(22, 3)\n"
" 17: ReturnVoid\n"
"BasicBlock 4, pred: 3\n"
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index 3209d3e..ee3a61a 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -89,8 +89,8 @@ TEST(DeadCodeElimination, AdditionAndConditionalJump) {
" 9: If(8)\n"
"BasicBlock 2, pred: 1, succ: 3\n"
" 12: Goto 3\n"
- "BasicBlock 3, pred: 2, 5, succ: 4\n"
- " 22: Phi(3, 5) [15]\n"
+ "BasicBlock 3, pred: 5, 2, succ: 4\n"
+ " 22: Phi(5, 3) [15]\n"
" 15: Add(22, 3)\n"
" 17: ReturnVoid\n"
"BasicBlock 4, pred: 3\n"
@@ -101,7 +101,7 @@ TEST(DeadCodeElimination, AdditionAndConditionalJump) {
// Expected difference after dead code elimination.
diff_t expected_diff = {
{ " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [22, 8]\n" },
- { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
+ { " 22: Phi(5, 3) [15]\n", " 22: Phi(5, 3)\n" },
{ " 15: Add(22, 3)\n", removed }
};
std::string expected_after = Patch(expected_before, expected_diff);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index fb150c3..c01364a 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -179,8 +179,9 @@ void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
HBasicBlock* new_block = new (arena_) HBasicBlock(this, successor->GetDexPc());
AddBlock(new_block);
new_block->AddInstruction(new (arena_) HGoto());
- block->ReplaceSuccessor(successor, new_block);
- new_block->AddSuccessor(successor);
+ // Use `InsertBetween` to ensure the predecessor index and successor index of
+ // `block` and `successor` are preserved.
+ new_block->InsertBetween(block, successor);
if (successor->IsLoopHeader()) {
// If we split at a back edge boundary, make the new block the back edge.
HLoopInformation* info = successor->GetLoopInformation();
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index c1f1c9d..394e3fc 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -582,6 +582,20 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
predecessors_.Put(predecessor_index, new_block);
}
+ // Insert `this` between `predecessor` and `successor. This method
+ // preserves the indicies, and will update the first edge found between
+ // `predecessor` and `successor`.
+ void InsertBetween(HBasicBlock* predecessor, HBasicBlock* successor) {
+ size_t predecessor_index = successor->GetPredecessorIndexOf(predecessor);
+ DCHECK_NE(predecessor_index, static_cast<size_t>(-1));
+ size_t successor_index = predecessor->GetSuccessorIndexOf(successor);
+ DCHECK_NE(successor_index, static_cast<size_t>(-1));
+ successor->predecessors_.Put(predecessor_index, this);
+ predecessor->successors_.Put(successor_index, this);
+ successors_.Add(successor);
+ predecessors_.Add(predecessor);
+ }
+
void RemovePredecessor(HBasicBlock* block) {
predecessors_.Delete(block);
}
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index fb3e7d7..0e8c058 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -115,7 +115,7 @@ TEST(SsaTest, CFG1) {
" 3: If(2)\n"
"BasicBlock 2, pred: 1, succ: 3\n"
" 4: Goto\n"
- "BasicBlock 3, pred: 2, 5, succ: 4\n"
+ "BasicBlock 3, pred: 5, 2, succ: 4\n"
" 5: ReturnVoid\n"
"BasicBlock 4, pred: 3\n"
" 6: Exit\n"
@@ -145,8 +145,8 @@ TEST(SsaTest, CFG2) {
" 4: If(3)\n"
"BasicBlock 2, pred: 1, succ: 3\n"
" 5: Goto\n"
- "BasicBlock 3, pred: 2, 5, succ: 4\n"
- " 6: Phi(1, 0) [7]\n"
+ "BasicBlock 3, pred: 5, 2, succ: 4\n"
+ " 6: Phi(0, 1) [7]\n"
" 7: Return(6)\n"
"BasicBlock 4, pred: 3\n"
" 8: Exit\n"
@@ -428,8 +428,8 @@ TEST(SsaTest, Loop7) {
" 10: Goto\n"
"BasicBlock 5, pred: 3, succ: 2\n"
" 11: Goto\n"
- "BasicBlock 6, pred: 4, 8, succ: 7\n"
- " 12: Phi(2, 5) [13]\n"
+ "BasicBlock 6, pred: 8, 4, succ: 7\n"
+ " 12: Phi(5, 2) [13]\n"
" 13: Return(12)\n"
"BasicBlock 7, pred: 6\n"
" 14: Exit\n"
@@ -480,7 +480,7 @@ TEST(SsaTest, LocalInIf) {
" 4: If(3)\n"
"BasicBlock 2, pred: 1, succ: 3\n"
" 5: Goto\n"
- "BasicBlock 3, pred: 2, 5, succ: 4\n"
+ "BasicBlock 3, pred: 5, 2, succ: 4\n"
" 6: ReturnVoid\n"
"BasicBlock 4, pred: 3\n"
" 7: Exit\n"
@@ -517,7 +517,7 @@ TEST(SsaTest, MultiplePredecessors) {
" 8: Add(0, 0)\n"
" 9: Goto\n"
// This block should not get a phi for local 1.
- "BasicBlock 5, pred: 2, 4, 7, succ: 6\n"
+ "BasicBlock 5, pred: 2, 7, 4, succ: 6\n"
" 10: ReturnVoid\n"
"BasicBlock 6, pred: 5\n"
" 11: Exit\n"
diff --git a/test/485-checker-dce-loop-update/smali/TestCase.smali b/test/485-checker-dce-loop-update/smali/TestCase.smali
index 3873ac5..6a42a46 100644
--- a/test/485-checker-dce-loop-update/smali/TestCase.smali
+++ b/test/485-checker-dce-loop-update/smali/TestCase.smali
@@ -141,7 +141,7 @@
# CHECK-DAG: If [ [[ArgY]] ] loop_header:[[HeaderY]]
# CHECK-DAG: If [ [[ArgZ]] ] loop_header:[[HeaderY]]
# CHECK-DAG: [[Mul9:i\d+]] Mul [ [[PhiX1]] [[Cst9]] ] loop_header:[[HeaderY]]
-# CHECK-DAG: [[PhiX2:i\d+]] Phi [ [[Mul9]] [[PhiX1]] ] loop_header:[[HeaderY]]
+# CHECK-DAG: [[PhiX2:i\d+]] Phi [ [[PhiX1]] [[Mul9]] ] loop_header:[[HeaderY]]
# CHECK-DAG: If [ [[Cst1]] ] loop_header:[[HeaderY]]
# CHECK-DAG: [[Add5]] Add [ [[PhiX2]] [[Cst5]] ] loop_header:[[HeaderY]]
# CHECK-DAG: [[Add7]] Add [ [[PhiX1]] [[Cst7]] ] loop_header:[[HeaderY]]
@@ -158,7 +158,7 @@
# CHECK-DAG: [[Add7]] Add [ [[PhiX1]] [[Cst7]] ] loop_header:[[HeaderY]]
# CHECK-DAG: If [ [[ArgZ]] ] loop_header:null
# CHECK-DAG: [[Mul9:i\d+]] Mul [ [[PhiX1]] [[Cst9]] ] loop_header:null
-# CHECK-DAG: [[PhiX2:i\d+]] Phi [ [[Mul9]] [[PhiX1]] ] loop_header:null
+# CHECK-DAG: [[PhiX2:i\d+]] Phi [ [[PhiX1]] [[Mul9]] ] loop_header:null
# CHECK-DAG: Return [ [[PhiX2]] ] loop_header:null
.method public static testExitPredecessors(IZZ)I
diff --git a/test/509-pre-header/expected.txt b/test/509-pre-header/expected.txt
new file mode 100644
index 0000000..ccaf6f8
--- /dev/null
+++ b/test/509-pre-header/expected.txt
@@ -0,0 +1 @@
+Enter
diff --git a/test/509-pre-header/info.txt b/test/509-pre-header/info.txt
new file mode 100644
index 0000000..e9d8b94
--- /dev/null
+++ b/test/509-pre-header/info.txt
@@ -0,0 +1,3 @@
+Regression test for the SimplifyCFG phase of optimizing.
+The invariant that the pre header of a loop header is the
+first predecessor was not preserved.
diff --git a/test/509-pre-header/smali/PreHeader.smali b/test/509-pre-header/smali/PreHeader.smali
new file mode 100644
index 0000000..04f4e49
--- /dev/null
+++ b/test/509-pre-header/smali/PreHeader.smali
@@ -0,0 +1,39 @@
+# Copyright (C) 2015 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.
+
+.class public LPreHeader;
+
+.super Ljava/lang/Object;
+
+# Label names in this method are taken from the original apk
+# that exposed the crash. The crash was due to fixing a critical
+# edge and not preserving the invariant that the pre header of a loop
+# is the first predecessor of the loop header.
+.method public static method()V
+ .registers 2
+ const/4 v0, 0
+ const/4 v1, 0
+ goto :b31
+ :b23
+ if-eqz v0, :b25
+ goto :b23
+ :b25
+ return-void
+ :b31
+ if-eqz v0, :b23
+ if-eqz v1, :bexit
+ goto :b31
+ :bexit
+ return-void
+.end method
diff --git a/test/509-pre-header/src/Main.java b/test/509-pre-header/src/Main.java
new file mode 100644
index 0000000..1eca419
--- /dev/null
+++ b/test/509-pre-header/src/Main.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ // Workaround for b/18051191.
+ System.out.println("Enter");
+ Class<?> c = Class.forName("PreHeader");
+ Method m = c.getMethod("method");
+ Object[] arguments = { };
+ m.invoke(null, arguments);
+ }
+}