Fix conditions used to apply def chains simplifier

Optimization will transform
a = b // called s0
...
m(a) // called s1
will be transform to:
a = b
...
m(b)

Conditions must take into account that definitions of b done between s0 and s1
can reach s0, if it is the case the transformation must not be apply.
Dectect this case can not be realized without to walk through the tree, thus
we restrict optimization when b as only one definition (it ensure that this
definition dominates s0)

Bug: 26709400
Change-Id: I165c511ee939790e43470424f19ba63d6d639de7
diff --git a/jack-tests/tests/com/android/jack/optimizations/usedef/UseDefTests.java b/jack-tests/tests/com/android/jack/optimizations/usedef/UseDefTests.java
new file mode 100644
index 0000000..1b4d1f2
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/optimizations/usedef/UseDefTests.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.jack.optimizations.usedef;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.android.jack.test.category.RuntimeRegressionTest;
+import com.android.jack.test.helper.RuntimeTestHelper;
+import com.android.jack.test.runtime.RuntimeTest;
+import com.android.jack.test.runtime.RuntimeTestInfo;
+import com.android.jack.test.toolchain.AbstractTestTools;
+
+public class UseDefTests extends RuntimeTest {
+  private RuntimeTestInfo TEST001 = new RuntimeTestInfo(
+      AbstractTestTools.getTestRootDir("com.android.jack.optimizations.usedef.test001"),
+      "com.android.jack.optimizations.usedef.test001.dx.Tests");
+
+    @Test
+    @Category(RuntimeRegressionTest.class)
+    public void test001() throws Exception {
+      new RuntimeTestHelper(TEST001).compileAndRunTest();
+    }
+
+    @Override
+    protected void fillRtTestInfos() {
+      rtTestInfos.add(TEST001);
+    }
+}
diff --git a/jack-tests/tests/com/android/jack/optimizations/usedef/test001/dx/Tests.java b/jack-tests/tests/com/android/jack/optimizations/usedef/test001/dx/Tests.java
new file mode 100644
index 0000000..b954f27
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/optimizations/usedef/test001/dx/Tests.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.jack.optimizations.usedef.test001.dx;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.android.jack.optimizations.usedef.test001.jack.UseDef001;
+
+public class Tests {
+
+  @Test
+  public void test001() {
+     Assert.assertEquals(2, UseDef001.test());
+  }
+
+}
diff --git a/jack-tests/tests/com/android/jack/optimizations/usedef/test001/jack/UseDef001.java b/jack-tests/tests/com/android/jack/optimizations/usedef/test001/jack/UseDef001.java
new file mode 100644
index 0000000..cb943ae
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/optimizations/usedef/test001/jack/UseDef001.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.jack.optimizations.usedef.test001.jack;
+
+public class UseDef001 {
+
+  public static int test() {
+    int offset = 0;
+    for (int i = 0; i < 2; i++) {
+      int start = offset;
+      for (int j = 0; j < 2; j++) {
+        offset++;
+      }
+      if (i == 1) {
+        return start;
+      }
+    }
+
+    return 0;
+  }
+}
diff --git a/jack/src/com/android/jack/optimizations/UseDefsChainsSimplifier.java b/jack/src/com/android/jack/optimizations/UseDefsChainsSimplifier.java
index de1db8c..6da0640 100644
--- a/jack/src/com/android/jack/optimizations/UseDefsChainsSimplifier.java
+++ b/jack/src/com/android/jack/optimizations/UseDefsChainsSimplifier.java
@@ -66,10 +66,14 @@
  *  - condition (1) a must have a value and b must be variable reference
  *  - condition (2) if s0 and s1 are in the same block then the variable b must not be redefine
  *  between statement s0 and s1
- *  - condition (3) if s0 and s1 are not into the same block then all definitions of b used
- *  by s0 must reach the block containing s1 and this block must not redefine b between the
- *  beginning of the block and s1
+ *  - condition (3) if s0 and s1 are not into the same block then all definitions of b used by s0
+ *  must reach the block containing s1 and all of these definitions must dominates s0. The block
+ *  that contains s1 must not redefine b between the beginning of this block and s1
  *
+ * Temporary restriction of condition(3)
+ * if several definitions of b exists, Jack must checks that all definition statements dominate s0.
+ * Currently, as it can not be done efficiently (without walk through the cfg) we do not optimize
+ * this case and restrict optimization to case where b has only one definitions.
  */
 @Description("Simplify use definitions chains.")
 @Constraint(need = {UseDefsMarker.class, ThreeAddressCodeForm.class, ControlFlowGraph.class})
@@ -103,6 +107,7 @@
       for (JVariableRef varRefOfa : varsUsedBys1.toArray(new JVariableRef[varsUsedBys1.size()])) {
         List<DefinitionMarker> defsOfa = OptimizationTools.getUsedDefinitions(varRefOfa);
 
+        // Condition(0)
         if (defsOfa.size() == 1) {
           DefinitionMarker defOfa = defsOfa.get(0);
 
@@ -158,7 +163,7 @@
       } else {
         // Condition (3)
         List<DefinitionMarker> defsOfbUseFroms0 = OptimizationTools.getUsedDefinitions(varRefb);
-        if (bbHasOnlyDefinitions(bbOfs1, b, defsOfbUseFroms0)
+        if (defsOfbUseFroms0.size() == 1 && bbHasOnlyDefinitions(bbOfs1, b, defsOfbUseFroms0)
             && !hasLocalDef(b, bbOfs1, null, s1)) {
           return true;
         }