[CF] Ensure safe phi-moves by loading all values on the stack prior to storing.
Change-Id: I04f814b2d84c6152b17678657e6eff5567b01a5a
diff --git a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
index 7215eed..6242e9b 100644
--- a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
@@ -22,6 +22,8 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfBuilder.FixedLocal;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
public class LoadStoreHelper {
@@ -40,12 +42,14 @@
if (!block.getPhis().isEmpty()) {
for (int predIndex = 0; predIndex < block.getPredecessors().size(); predIndex++) {
BasicBlock pred = block.getPredecessors().get(predIndex);
- for (Phi phi : block.getPhis()) {
- Value value = phi.getOperand(predIndex);
- InstructionListIterator it = pred.listIterator(pred.getInstructions().size());
- it.previous();
- movePhi(phi, value, it);
+ List<Phi> phis = block.getPhis();
+ List<Value> values = new ArrayList<>(phis.size());
+ for (Phi phi : phis) {
+ values.add(phi.getOperand(predIndex));
}
+ InstructionListIterator it = pred.listIterator(pred.getInstructions().size());
+ it.previous();
+ movePhis(phis, values, it);
}
}
}
@@ -107,13 +111,25 @@
add(new Pop(newOutValue), instruction, it);
}
- public void movePhi(Phi phi, Value value, InstructionListIterator it) {
- StackValue tmp = createStackValue(phi, 0);
- FixedLocal out = new FixedLocal(phi);
- add(load(tmp, value), phi.getBlock(), Position.none(), it);
- add(new Store(out, tmp), phi.getBlock(), Position.none(), it);
- value.removePhiUser(phi);
- phi.replaceUsers(out);
+ public void movePhis(List<Phi> phis, List<Value> values, InstructionListIterator it) {
+ // TODO(zerny): Accounting for non-interfering phis would lower the max stack size.
+ int topOfStack = 0;
+ List<StackValue> temps = new ArrayList<>(phis.size());
+ for (int i = 0; i < phis.size(); i++) {
+ Phi phi = phis.get(i);
+ Value value = values.get(i);
+ StackValue tmp = createStackValue(phi, topOfStack++);
+ add(load(tmp, value), phi.getBlock(), Position.none(), it);
+ temps.add(tmp);
+ value.removePhiUser(phi);
+ }
+ for (int i = phis.size() - 1; i >= 0; i--) {
+ Phi phi = phis.get(i);
+ StackValue tmp = temps.get(i);
+ FixedLocal out = new FixedLocal(phi);
+ add(new Store(out, tmp), phi.getBlock(), Position.none(), it);
+ phi.replaceUsers(out);
+ }
}
private Instruction load(StackValue stackValue, Value value) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 835cae2..1486b7b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -185,6 +185,8 @@
// Remove the load.
it.next();
it.remove();
+ // Rewind to the instruction before the store so we can identify new patterns.
+ it.previous();
}
}
}