Avoid using non-argument registers for arguments when we can.
This saves around 4kB when dexing gmscore.
Redoing the move insertion is a little heavy weight but with the current
parallel move scheduling I cannot reliably put a bound on the amount
of temporary registers it will need (even though I haven't seen more
than 4 ever). Therefore, I have to postpone the determination until the
very end and redo insertion.
R=sgjesse@google.com
Change-Id: I440ec35460033b5c6eb25f161ff1740c91eee2d9
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 f2d039d..f621c67 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
@@ -429,9 +429,48 @@
private boolean performAllocation(ArgumentReuseMode mode) {
boolean result = performAllocationWithoutMoveInsertion(mode);
insertMoves();
+ if (mode == ArgumentReuseMode.DISALLOW_ARGUMENT_REUSE) {
+ // Now that we know the max register number we can compute whether it is safe to use
+ // argument registers in place. If it is, we redo move insertion to get rid of the moves
+ // caused by splitting of the argument registers.
+ if (unsplitArguments()) {
+ removeSpillAndPhiMoves();
+ insertMoves();
+ }
+ }
return result;
}
+ // When argument register reuse is disallowed, we split argument values to make sure that
+ // we can get the argument into low enough registers at uses that require low numbers. After
+ // register allocation we can check if it is safe to just use the argument register itself
+ // for all uses and thereby avoid moving argument values around.
+ private boolean unsplitArguments() {
+ boolean argumentRegisterUnsplit = false;
+ Value current = preArgumentSentinelValue;
+ while (current != null) {
+ LiveIntervals intervals = current.getLiveIntervals();
+ assert intervals.getRegisterLimit() == Constants.U16BIT_MAX;
+ boolean canUseArgumentRegister = true;
+ for (LiveIntervals child : intervals.getSplitChildren()) {
+ if (child.getRegisterLimit() < registersUsed()) {
+ canUseArgumentRegister = false;
+ break;
+ }
+ }
+ if (canUseArgumentRegister) {
+ argumentRegisterUnsplit = true;
+ for (LiveIntervals child : intervals.getSplitChildren()) {
+ child.clearRegisterAssignment();
+ child.setRegister(intervals.getRegister());
+ child.setSpilled(false);
+ }
+ }
+ current = current.getNextConsecutive();
+ }
+ return argumentRegisterUnsplit;
+ }
+
private void removeSpillAndPhiMoves() {
for (BasicBlock block : code.blocks) {
InstructionListIterator it = block.listIterator();