Merge "Also rematerialize constant string values"
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
index 7b3eef0..2734ff4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.DebugLocalsChange;
import com.android.tools.r8.ir.code.Goto;
import com.android.tools.r8.ir.code.IRCode;
@@ -266,9 +266,10 @@
// Mapping from register number to const number instructions for this basic block.
// Used to remove redundant const instructions that reloads the same constant into
// the same register.
- Map<Integer, ConstNumber> registerToNumber = new HashMap<>();
+ Map<Integer, ConstInstruction> registerToConstant = new HashMap<>();
MoveEliminator moveEliminator = new MoveEliminator(allocator);
ListIterator<Instruction> iterator = block.getInstructions().listIterator();
+ boolean mayNoLongerThrow = false;
while (iterator.hasNext()) {
Instruction current = iterator.next();
if (moveEliminator.shouldBeEliminated(current)) {
@@ -276,28 +277,30 @@
} else if (current.outValue() != null && current.outValue().needsRegister()) {
Value outValue = current.outValue();
int instructionNumber = current.getNumber();
- if (outValue.isConstant() && current.isConstNumber()) {
- if (constantSpilledAtDefinition(current.asConstNumber(), allocator)) {
+ if (!outValue.hasLocalInfo() && (current.isConstNumber() || current.isConstString())) {
+ if (constantSpilledAtDefinition(current.asConstInstruction(), allocator)) {
// Remove constant instructions that are spilled at their definition and are
// therefore unused.
iterator.remove();
- continue;
- }
- int outRegister = allocator.getRegisterForValue(outValue, instructionNumber);
- ConstNumber numberInRegister = registerToNumber.get(outRegister);
- if (numberInRegister != null
- && numberInRegister.identicalNonValueNonPositionParts(current)) {
- // This instruction is not needed, the same constant is already in this register.
- // We don't consider the positions of the two (non-throwing) instructions.
- iterator.remove();
+ mayNoLongerThrow |= current.instructionTypeCanThrow();
} else {
- // Insert the current constant in the mapping. Make sure to clobber the second
- // register if wide and register-1 if that defines a wide value.
- registerToNumber.put(outRegister, current.asConstNumber());
- if (current.outType().isWide()) {
- registerToNumber.remove(outRegister + 1);
+ int outRegister = allocator.getRegisterForValue(outValue, instructionNumber);
+ ConstInstruction constantInRegister = registerToConstant.get(outRegister);
+ if (constantInRegister != null
+ && constantInRegister.identicalNonValueNonPositionParts(current)) {
+ // This instruction is not needed, the same constant is already in this register.
+ // We don't consider the positions of the two (non-throwing) instructions.
+ iterator.remove();
+ mayNoLongerThrow |= current.instructionTypeCanThrow();
} else {
- removeWideConstantCovering(registerToNumber, outRegister);
+ // Insert the current constant in the mapping. Make sure to clobber the second
+ // register if wide and register-1 if that defines a wide value.
+ registerToConstant.put(outRegister, current.asConstNumber());
+ if (current.outType().isWide()) {
+ registerToConstant.remove(outRegister + 1);
+ } else {
+ removeWideConstantCovering(registerToConstant, outRegister);
+ }
}
}
} else {
@@ -305,32 +308,40 @@
// from the mapping.
int outRegister = allocator.getRegisterForValue(outValue, instructionNumber);
for (int i = 0; i < outValue.requiredRegisters(); i++) {
- registerToNumber.remove(outRegister + i);
+ registerToConstant.remove(outRegister + i);
}
// Check if the first register written is the second part of a wide value. If so
// the wide value is no longer active.
- removeWideConstantCovering(registerToNumber, outRegister);
+ removeWideConstantCovering(registerToConstant, outRegister);
}
}
}
+
+ if (mayNoLongerThrow && block.hasCatchHandlers() && !block.canThrow()) {
+ block.clearCatchHandlers();
+ }
}
}
private static void removeWideConstantCovering(
- Map<Integer, ConstNumber> registerToNumber, int register) {
- ConstNumber number = registerToNumber.get(register - 1);
- if (number != null && number.outType().isWide()) {
- registerToNumber.remove(register - 1);
+ Map<Integer, ConstInstruction> registerToConstant, int register) {
+ ConstInstruction constant = registerToConstant.get(register - 1);
+ if (constant != null && constant.outType().isWide()) {
+ registerToConstant.remove(register - 1);
}
}
private static boolean constantSpilledAtDefinition(
- ConstNumber constNumber, LinearScanRegisterAllocator allocator) {
- if (constNumber.outValue().isFixedRegisterValue()) {
+ ConstInstruction constInstruction, LinearScanRegisterAllocator allocator) {
+ assert constInstruction.isConstNumber() || constInstruction.isConstString();
+ if (constInstruction.outValue().isFixedRegisterValue()) {
return false;
}
LiveIntervals definitionIntervals =
- constNumber.outValue().getLiveIntervals().getSplitCovering(constNumber.getNumber());
+ constInstruction
+ .outValue()
+ .getLiveIntervals()
+ .getSplitCovering(constInstruction.getNumber());
return definitionIntervals.isSpilledAndRematerializable(allocator);
}
}
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 1c0e761..aca1f85 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
@@ -673,7 +673,7 @@
// const number instructions are for values that can be rematerialized instead of
// spilled.
assert instruction.getNumber() == -1;
- assert instruction.isMove() || instruction.isConstNumber();
+ assert instruction.isMove() || instruction.isConstNumber() || instruction.isConstString();
assert !instruction.isDebugInstruction();
return true;
}
@@ -1928,8 +1928,11 @@
newActive.add(splitChild);
// If the constant is split before its first actual use, mark the constant as being
// spilled. That will allows us to remove it afterwards if it is rematerializable.
- if (intervals.getValue().isConstNumber()
- && intervals.getStart() == intervals.getValue().definition.getNumber()
+ Value intervalsValue = intervals.getValue();
+ boolean isRematerializableConstantValue =
+ intervalsValue.isConstNumber() || intervalsValue.isConstString();
+ if (isRematerializableConstantValue
+ && intervals.getStart() == intervalsValue.definition.getNumber()
&& intervals.getUses().size() == 1) {
intervals.setSpilled(true);
}
@@ -1939,9 +1942,7 @@
LiveIntervals splitOfSplit = splitChild.splitBefore(splitChild.getFirstUse());
splitOfSplit.setRegister(intervals.getRegister());
inactive.add(splitOfSplit);
- } else if (intervals.getValue().isConstNumber()) {
- // TODO(ager): Do this for all constants. Currently we only rematerialize const
- // number and therefore we only do it for numbers at this point.
+ } else if (isRematerializableConstantValue) {
splitRangesForSpilledConstant(splitChild, registerNumber);
} else if (intervals.isArgumentInterval()) {
splitRangesForSpilledArgument(splitChild);
@@ -1972,6 +1973,7 @@
// register for as long as possible to avoid further moves.
assert spilled.isSpilled();
assert !spilled.getValue().isConstNumber();
+ assert !spilled.getValue().isConstString();
assert !spilled.isLinked() || spilled.isArgumentInterval();
boolean isSpillingToArgumentRegister =
(spilled.isArgumentInterval() || registerNumber < numberOfArgumentRegisters);
@@ -2004,7 +2006,7 @@
// spill we are running low on registers and this constant should get out of the way
// as much as possible.
assert spilled.isSpilled();
- assert spilled.getValue().isConstNumber();
+ assert spilled.getValue().isConstNumber() || spilled.getValue().isConstString();
assert !spilled.isLinked() || spilled.isArgumentInterval();
// Do not split range if constant is reused by one of the eleven following instruction.
int maxGapSize = 11 * INSTRUCTION_NUMBER_DELTA;
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 7e398e6..d7c6588 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -99,8 +99,8 @@
if (value.isArgument()) {
return true;
}
- // TODO(ager): rematerialize const string as well.
- if (!value.isConstNumber()) {
+ boolean isRematerializableConstantValue = value.isConstNumber() || value.isConstString();
+ if (!isRematerializableConstantValue) {
return false;
}
// If one of the non-spilled splits uses a register that is higher than U8BIT_MAX we cannot
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
index 645552f..afec916 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.ir.regalloc;
import com.android.tools.r8.code.MoveType;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.FixedRegisterValue;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -130,16 +132,22 @@
private Integer createMove(RegisterMove move) {
Instruction instruction;
if (move.definition != null) {
- if (move.definition.isArgument()) {
- Argument argument = move.definition.asArgument();
+ Instruction definition = move.definition;
+ if (definition.isArgument()) {
+ Argument argument = definition.asArgument();
int argumentRegister = argument.outValue().getLiveIntervals().getRegister();
Value to = new FixedRegisterValue(argument.outType(), move.dst);
Value from = new FixedRegisterValue(argument.outType(), argumentRegister);
instruction = new Move(to, from);
} else {
- ConstNumber number = move.definition.asConstNumber();
- Value to = new FixedRegisterValue(number.outType(), move.dst);
- instruction = new ConstNumber(to, number.getRawValue());
+ Value to = new FixedRegisterValue(definition.outType(), move.dst);
+ if (definition.isConstNumber()) {
+ instruction = new ConstNumber(to, definition.asConstNumber().getRawValue());
+ } else if (definition.isConstString()) {
+ instruction = new ConstString(to, definition.asConstString().getValue());
+ } else {
+ throw new Unreachable("Unexpected definition");
+ }
}
} else {
Value to = new FixedRegisterValue(move.type.toValueType(), move.dst);