Merge "Add support for Proguard option -printconfiguration"
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index 96b2122..182bb49 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -1165,7 +1165,7 @@
     @Override
     public int computeSize(DexBuilder builder) {
       Move move = getMove();
-      int srcRegister = builder.allocatedRegister(move.src(), move.getNumber());
+      int srcRegister = builder.argumentOrAllocateRegister(move.src(), move.getNumber());
       int destRegister = builder.allocatedRegister(move.dest(), move.getNumber());
       if (srcRegister == destRegister) {
         size = 1;
@@ -1183,8 +1183,8 @@
     public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
       Move move = getMove();
       MoveType moveType = MoveType.fromValueType(move.outType());
+      int src = builder.argumentOrAllocateRegister(move.src(), move.getNumber());
       int dest = builder.allocatedRegister(move.dest(), move.getNumber());
-      int src = builder.allocatedRegister(move.src(), move.getNumber());
       Instruction instruction = null;
       switch (size) {
         case 1:
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 13d66c2..5efbfb5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -82,6 +82,7 @@
 import com.android.tools.r8.ir.code.Xor;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Pair;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -1604,27 +1605,50 @@
 
   private Value readRegisterRecursive(
       int register, BasicBlock block, EdgeType readingEdge, ValueType type, DebugLocalInfo local) {
-    Value value;
-    if (!block.isSealed()) {
-      assert !blocks.isEmpty() : "No write to " + register;
-      Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
-      block.addIncompletePhi(register, phi, readingEdge);
-      value = phi;
-    } else if (block.getPredecessors().size() == 1) {
-      assert block.verifyFilledPredecessors();
-      BasicBlock pred = block.getPredecessors().get(0);
-      EdgeType edgeType = pred.getEdgeType(block);
-      value = readRegister(register, type, pred, edgeType, local);
-    } else {
-      Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
-      // We need to write the phi before adding operands to break cycles. If the phi is trivial
-      // and is removed by addOperands, the definition is overwritten and looked up again below.
-      block.updateCurrentDefinition(register, phi, readingEdge);
-      phi.addOperands(this, register);
-      // Lookup the value for the register again at this point. Recursive trivial
-      // phi removal could have simplified what we wanted to return here.
-      value = block.readCurrentDefinition(register, readingEdge);
+    Value value = null;
+    // Iterate back along the predecessor chain as long as there is a single sealed predecessor.
+    List<Pair<BasicBlock, EdgeType>> stack = null;
+    if (block.isSealed() && block.getPredecessors().size() == 1) {
+      stack = new ArrayList<>(blocks.size());
+      do {
+        assert block.verifyFilledPredecessors();
+        BasicBlock pred = block.getPredecessors().get(0);
+        EdgeType edgeType = pred.getEdgeType(block);
+        checkRegister(register);
+        value = pred.readCurrentDefinition(register, edgeType);
+        if (value != null) {
+          break;
+        }
+        stack.add(new Pair<>(block, readingEdge));
+        block = pred;
+        readingEdge = edgeType;
+      } while (block.isSealed() && block.getPredecessors().size() == 1);
     }
+    // If the register still has unknown value create a phi value for it.
+    if (value == null) {
+      if (!block.isSealed()) {
+        assert !blocks.isEmpty() : "No write to " + register;
+        Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
+        block.addIncompletePhi(register, phi, readingEdge);
+        value = phi;
+      } else {
+        Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
+        // We need to write the phi before adding operands to break cycles. If the phi is trivial
+        // and is removed by addOperands, the definition is overwritten and looked up again below.
+        block.updateCurrentDefinition(register, phi, readingEdge);
+        phi.addOperands(this, register);
+        // Lookup the value for the register again at this point. Recursive trivial
+        // phi removal could have simplified what we wanted to return here.
+        value = block.readCurrentDefinition(register, readingEdge);
+      }
+    }
+    // If the stack of successors is non-empty then update their definitions with the value.
+    if (stack != null) {
+      for (Pair<BasicBlock, EdgeType> item : stack) {
+        item.getFirst().updateCurrentDefinition(register, value, item.getSecond());
+      }
+    }
+    // Update the last block at which the definition was found/created.
     block.updateCurrentDefinition(register, value, readingEdge);
     return value;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 85e0060..6803c75 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -513,9 +513,12 @@
     // Compute the set of registers that is used based on all live intervals.
     Set<Integer> usedRegisters = new HashSet<>();
     for (LiveIntervals intervals : liveIntervals) {
-      addRegisterIfUsed(usedRegisters, intervals);
-      for (LiveIntervals childIntervals : intervals.getSplitChildren()) {
-        addRegisterIfUsed(usedRegisters, childIntervals);
+      // Argument sentinel values do not occupy any registers.
+      if (!isArgumentSentinelIntervals(intervals)) {
+        addRegisterIfUsed(usedRegisters, intervals);
+        for (LiveIntervals childIntervals : intervals.getSplitChildren()) {
+          addRegisterIfUsed(usedRegisters, childIntervals);
+        }
       }
     }
     // Additionally, we have used temporary registers for parallel move scheduling, those
@@ -535,6 +538,11 @@
     unusedRegisters = computed;
   }
 
+  private boolean isArgumentSentinelIntervals(LiveIntervals intervals) {
+    return intervals.isArgumentInterval() &&
+            (intervals.getPreviousConsecutive() == null || intervals.getNextConsecutive() == null);
+  }
+
   private void addRegisterIfUsed(Set<Integer> used, LiveIntervals intervals) {
     boolean unused = intervals.isSpilledAndRematerializable(this);
     if (!unused) {
diff --git a/src/test/java/com/android/tools/r8/debug/FinallyBlockTest.java b/src/test/java/com/android/tools/r8/debug/FinallyBlockTest.java
index 2d8119f..05bff95 100644
--- a/src/test/java/com/android/tools/r8/debug/FinallyBlockTest.java
+++ b/src/test/java/com/android/tools/r8/debug/FinallyBlockTest.java
@@ -80,7 +80,9 @@
         checkLine(FILE, 11), // throw without catch
         stepOver(),
         checkLine(FILE, 18), // finally
-        stepOver(),
+        // Don't single step here as some Java compilers generate line entry 19 and some don't.
+        breakpoint(CLASS, "callFinallyBlock", 26),
+        run(),
         checkLine(FILE, 26), // catch in callFinallyBlock
         run());
   }
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index d8fac83..b9bcc60 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -88,15 +88,17 @@
                         '\'<BENCHMARKNAME>-<segment>(CodeSize): <bytes>\'')
   return result.parse_args(argv)
 
-# Most apps have the -printmapping and -printseeds in the Proguard
-# configuration. However we don't want to write these files in these
-# locations. Instead generate an auxiliary Proguard configuration
-# placing these two output files together with the dex output.
+# Most apps have the -printmapping, -printseeds and -printusage in the
+# Proguard configuration. However we don't want to write these files
+# in the locations specified. Instead generate an auxiliary Proguard
+# configuration placing these two output files together with the dex
+# output.
 def GenerateAdditionalProguardConfiguration(temp, outdir):
   name = "output.config"
   with open(os.path.join(temp, name), 'w') as f:
     f.write('-printmapping ' + os.path.join(outdir, 'proguard.map') + "\n")
     f.write('-printseeds ' + os.path.join(outdir, 'proguard.seeds') + "\n")
+    f.write('-printusage ' + os.path.join(outdir, 'proguard.usage') + "\n")
     return os.path.abspath(f.name)
 
 def main(argv):