aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android/tools/r8/ir/regalloc
diff options
context:
space:
mode:
authorMads Ager <ager@google.com>2017-05-24 09:56:54 +0200
committerMads Ager <ager@google.com>2017-05-24 09:56:54 +0200
commit741a2789541e2af16b0a6abbb1cb5dc0438825ea (patch)
tree222de9bf6a37713303f6b52dbaac9314fdaa7218 /src/main/java/com/android/tools/r8/ir/regalloc
parent677e3007bab3d7b05dc596b5309d6ab4eb966b76 (diff)
downloadr8-741a2789541e2af16b0a6abbb1cb5dc0438825ea.tar.gz
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
Diffstat (limited to 'src/main/java/com/android/tools/r8/ir/regalloc')
-rw-r--r--src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java39
1 files changed, 39 insertions, 0 deletions
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 f2d039d5b..f621c6740 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 @@ public class LinearScanRegisterAllocator implements RegisterAllocator {
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();