diff options
author | Mads Ager <ager@google.com> | 2017-05-24 09:56:54 +0200 |
---|---|---|
committer | Mads Ager <ager@google.com> | 2017-05-24 09:56:54 +0200 |
commit | 741a2789541e2af16b0a6abbb1cb5dc0438825ea (patch) | |
tree | 222de9bf6a37713303f6b52dbaac9314fdaa7218 /src/main/java/com/android/tools/r8/ir/regalloc | |
parent | 677e3007bab3d7b05dc596b5309d6ab4eb966b76 (diff) | |
download | r8-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.java | 39 |
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(); |