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):