Merge "One step closer to actual JVM field resolution."
diff --git a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
new file mode 100644
index 0000000..adf82dd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
@@ -0,0 +1,364 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.cf;
+
+import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
+import static com.android.tools.r8.ir.code.IRCode.INSTRUCTION_NUMBER_DELTA;
+import static com.android.tools.r8.ir.regalloc.LiveIntervals.NO_REGISTER;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.StackValue;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.regalloc.LiveIntervals;
+import com.android.tools.r8.ir.regalloc.LiveIntervalsUse;
+import com.android.tools.r8.ir.regalloc.LiveRange;
+import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.utils.InternalOptions;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.PriorityQueue;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Allocator for assigning local-indexes to non-stack values.
+ *
+ * <p>This is mostly a very simple variant of {@link
+ * com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator} since for CF there are no register
+ * constraints and thus no need for spilling.
+ */
+public class CfRegisterAllocator implements RegisterAllocator {
+
+ private final IRCode code;
+ private final InternalOptions options;
+
+ // Mapping from basic blocks to the set of values live at entry to that basic block.
+ private Map<BasicBlock, Set<Value>> liveAtEntrySets;
+
+ // List of all top-level live intervals for all SSA values.
+ private final List<LiveIntervals> liveIntervals = new ArrayList<>();
+
+ // List of active intervals.
+ private final List<LiveIntervals> active = new LinkedList<>();
+
+ // List of intervals where the current instruction falls into one of their live range holes.
+ private final List<LiveIntervals> inactive = new LinkedList<>();
+
+ // List of intervals that no register has been allocated to sorted by first live range.
+ private final PriorityQueue<LiveIntervals> unhandled = new PriorityQueue<>();
+
+ // The set of registers that are free for allocation.
+ private final NavigableSet<Integer> freeRegisters = new TreeSet<>();
+
+ private int nextUnusedRegisterNumber = 0;
+
+ private int maxRegisterNumber = 0;
+
+ public CfRegisterAllocator(IRCode code, InternalOptions options) {
+ this.code = code;
+ this.options = options;
+ }
+
+ @Override
+ public int registersUsed() {
+ return maxRegisterNumber + 1;
+ }
+
+ @Override
+ public int getRegisterForValue(Value value, int instructionNumber) {
+ return getRegisterForValue(value);
+ }
+
+ public int getRegisterForValue(Value value) {
+ if (value instanceof FixedLocalValue) {
+ return ((FixedLocalValue) value).getRegister(this);
+ }
+ assert !value.getLiveIntervals().hasSplits();
+ return value.getLiveIntervals().getRegister();
+ }
+
+ @Override
+ public boolean argumentValueUsesHighRegister(Value value, int instructionNumber) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int getArgumentOrAllocateRegisterForValue(Value value, int instructionNumber) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void allocateRegisters(boolean debug) {
+ assert options.debug == debug;
+ allocateRegisters();
+ }
+
+ public void allocateRegisters() {
+ computeNeedsRegister();
+ computeLivenessInformation();
+ performLinearScan();
+ }
+
+ private void computeNeedsRegister() {
+ InstructionIterator it = code.instructionIterator();
+ while (it.hasNext()) {
+ Instruction next = it.next();
+ Value outValue = next.outValue();
+ if (outValue != null) {
+ outValue.setNeedsRegister(!(outValue instanceof StackValue));
+ }
+ }
+ }
+
+ private void computeLivenessInformation() {
+ code.numberInstructions();
+ liveAtEntrySets = code.computeLiveAtEntrySets();
+ computeLiveRanges();
+ }
+
+ private void computeLiveRanges() {
+ for (BasicBlock block : code.topologicallySortedBlocks()) {
+ Set<Value> live = new HashSet<>();
+ List<BasicBlock> successors = block.getSuccessors();
+ Set<Value> phiOperands = new HashSet<>();
+ for (BasicBlock successor : successors) {
+ live.addAll(liveAtEntrySets.get(successor));
+ int predIndex = successor.getPredecessors().indexOf(block);
+ for (Phi phi : successor.getPhis()) {
+ live.remove(phi);
+ phiOperands.add(phi.getOperand(predIndex));
+ assert phi.getDebugValues().stream().allMatch(Value::needsRegister);
+ phiOperands.addAll(phi.getDebugValues());
+ }
+ }
+ live.addAll(phiOperands);
+ List<Instruction> instructions = block.getInstructions();
+ for (Value value : live) {
+ int end = block.entry().getNumber() + instructions.size() * INSTRUCTION_NUMBER_DELTA;
+ // Make sure that phi operands do not overlap the phi live range. The phi operand is
+ // not live until the next instruction, but only until the gap before the next instruction
+ // where the phi value takes over.
+ if (phiOperands.contains(value)) {
+ end--;
+ }
+ addLiveRange(value, block, end);
+ }
+ InstructionListIterator it = block.listIterator(block.getInstructions().size());
+ while (it.hasPrevious()) {
+ Instruction instruction = it.previous();
+ int number = instruction.getNumber();
+ Value definition = instruction.outValue();
+ if (definition != null) {
+ // For instructions that define values which have no use create a live range covering
+ // the instruction. This will typically be instructions that can have side effects even
+ // if their output is not used.
+ if (!definition.isUsed()) {
+ addLiveRange(definition, block, number + INSTRUCTION_NUMBER_DELTA);
+ assert instruction.isArgument()
+ : "Arguments should be the only potentially unused local in CF";
+ }
+ live.remove(definition);
+ }
+ for (Value use : instruction.inValues()) {
+ if (use.needsRegister()) {
+ if (!live.contains(use)) {
+ live.add(use);
+ addLiveRange(use, block, number);
+ }
+ LiveIntervals useIntervals = use.getLiveIntervals();
+ useIntervals.addUse(new LiveIntervalsUse(number, U16BIT_MAX /* unconstrained */));
+ }
+ }
+ if (options.debug) {
+ for (Value use : instruction.getDebugValues()) {
+ assert use.needsRegister();
+ if (!live.contains(use)) {
+ live.add(use);
+ addLiveRange(use, block, number);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void addLiveRange(Value value, BasicBlock block, int end) {
+ int firstInstructionInBlock = block.entry().getNumber();
+ int instructionsSize = block.getInstructions().size() * INSTRUCTION_NUMBER_DELTA;
+ int lastInstructionInBlock =
+ firstInstructionInBlock + instructionsSize - INSTRUCTION_NUMBER_DELTA;
+ int instructionNumber;
+ if (value.isPhi()) {
+ instructionNumber = firstInstructionInBlock;
+ } else {
+ Instruction instruction = value.definition;
+ instructionNumber = instruction.getNumber();
+ }
+ if (value.getLiveIntervals() == null) {
+ Value current = value.getStartOfConsecutive();
+ LiveIntervals intervals = new LiveIntervals(current);
+ while (true) {
+ liveIntervals.add(intervals);
+ Value next = current.getNextConsecutive();
+ if (next == null) {
+ break;
+ }
+ LiveIntervals nextIntervals = new LiveIntervals(next);
+ intervals.link(nextIntervals);
+ current = next;
+ intervals = nextIntervals;
+ }
+ }
+ LiveIntervals intervals = value.getLiveIntervals();
+ if (firstInstructionInBlock <= instructionNumber
+ && instructionNumber <= lastInstructionInBlock) {
+ if (value.isPhi()) {
+ // Phis need to interfere with spill restore moves inserted before the instruction because
+ // the phi value is defined on the inflowing edge.
+ instructionNumber--;
+ }
+ intervals.addRange(new LiveRange(instructionNumber, end));
+ if (!value.isPhi()) {
+ intervals.addUse(new LiveIntervalsUse(instructionNumber, U16BIT_MAX /* unconstrained */));
+ }
+ } else {
+ intervals.addRange(new LiveRange(firstInstructionInBlock - 1, end));
+ }
+ }
+
+ private void performLinearScan() {
+ unhandled.addAll(liveIntervals);
+ while (!unhandled.isEmpty()) {
+ LiveIntervals unhandledInterval = unhandled.poll();
+ int start = unhandledInterval.getStart();
+ {
+ // Check for active intervals that expired or became inactive.
+ Iterator<LiveIntervals> it = active.iterator();
+ while (it.hasNext()) {
+ LiveIntervals activeIntervals = it.next();
+ if (start >= activeIntervals.getEnd()) {
+ it.remove();
+ freeRegistersForIntervals(activeIntervals);
+ } else if (!activeIntervals.overlapsPosition(start)) {
+ assert activeIntervals.getRegister() != NO_REGISTER;
+ it.remove();
+ inactive.add(activeIntervals);
+ freeRegistersForIntervals(activeIntervals);
+ }
+ }
+ }
+ IntList reactivedBeforeEnd = new IntArrayList(inactive.size());
+ {
+ // Check for inactive intervals that expired or become active.
+ Iterator<LiveIntervals> it = inactive.iterator();
+ while (it.hasNext()) {
+ LiveIntervals inactiveIntervals = it.next();
+ if (start >= inactiveIntervals.getEnd()) {
+ it.remove();
+ } else if (inactiveIntervals.overlapsPosition(start)) {
+ it.remove();
+ assert inactiveIntervals.getRegister() != NO_REGISTER;
+ active.add(inactiveIntervals);
+ takeRegistersForIntervals(inactiveIntervals);
+ } else if (inactiveIntervals.overlaps(unhandledInterval)) {
+ reactivedBeforeEnd.add(inactiveIntervals.getRegister());
+ takeRegistersForIntervals(inactiveIntervals);
+ }
+ }
+ }
+
+ // Perform the actual allocation.
+ assignRegisterToUnhandledInterval(
+ unhandledInterval, getNextFreeRegister(unhandledInterval.getType().isWide()));
+
+ // Add back the potentially free registers from the inactive set.
+ freeRegisters.addAll(reactivedBeforeEnd);
+ }
+ }
+
+ // Note that getNextFreeRegister will not take the register before it is committed to an interval.
+ private int getNextFreeRegister(boolean isWide) {
+ if (!freeRegisters.isEmpty()) {
+ if (isWide) {
+ for (Integer register : freeRegisters) {
+ if (freeRegisters.contains(register + 1) || nextUnusedRegisterNumber == register + 1) {
+ return register;
+ }
+ }
+ return nextUnusedRegisterNumber;
+ }
+ return freeRegisters.first();
+ }
+ return nextUnusedRegisterNumber;
+ }
+
+ private void freeRegistersForIntervals(LiveIntervals intervals) {
+ int register = intervals.getRegister();
+ freeRegisters.add(register);
+ if (intervals.getType().isWide()) {
+ freeRegisters.add(register + 1);
+ }
+ }
+
+ private void takeRegistersForIntervals(LiveIntervals intervals) {
+ int register = intervals.getRegister();
+ freeRegisters.remove(register);
+ if (intervals.getType().isWide()) {
+ freeRegisters.remove(register + 1);
+ }
+ }
+
+ private void assignRegisterToUnhandledInterval(LiveIntervals unhandledInterval, int register) {
+ assignRegister(unhandledInterval, register);
+ takeRegistersForIntervals(unhandledInterval);
+ updateRegisterState(register, unhandledInterval.getType().isWide());
+ active.add(unhandledInterval);
+ }
+
+ private void updateRegisterState(int register, boolean needsRegisterPair) {
+ int maxRegister = register + (needsRegisterPair ? 1 : 0);
+ if (maxRegister >= nextUnusedRegisterNumber) {
+ nextUnusedRegisterNumber = maxRegister + 1;
+ }
+ maxRegisterNumber = Math.max(maxRegisterNumber, maxRegister);
+ }
+
+ private void assignRegister(LiveIntervals intervals, int register) {
+ intervals.setRegister(register);
+ }
+
+ public Collection<Value> getLocalsAtPosition(int blockEntryInstruction) {
+ List<Value> values = new ArrayList<>(registersUsed());
+ for (LiveIntervals intervals : liveIntervals) {
+ addLiveValueFromIntervals(blockEntryInstruction, intervals, values);
+ }
+ return values;
+ }
+
+ private static void addLiveValueFromIntervals(
+ int position, LiveIntervals intervals, List<Value> values) {
+ if (intervals.overlapsPosition(position)) {
+ for (LiveRange range : intervals.getRanges()) {
+ if (range.start <= position && position < range.end) {
+ values.add(intervals.getValue());
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java b/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java
new file mode 100644
index 0000000..56ab3cd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.cf;
+
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.Value;
+
+/**
+ * Value that represents a shared physical location defined by the phi value.
+ *
+ * <p>This value is introduced to represent the store instructions used to unify the location of
+ * in-flowing values to phi's. After introducing this fixed location the graph is no longer in SSA
+ * since the fixed location signifies a place that can be written to from multiple places.
+ */
+public class FixedLocalValue extends Value {
+
+ private final Phi phi;
+
+ public FixedLocalValue(Phi phi) {
+ super(phi.getNumber(), phi.outType(), phi.getLocalInfo());
+ this.phi = phi;
+ }
+
+ public int getRegister(CfRegisterAllocator allocator) {
+ return allocator.getRegisterForValue(phi, -1);
+ }
+
+ @Override
+ public boolean isConstant() {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "fixed:v" + phi.getNumber();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
index 6242e9b..bb76dc7 100644
--- a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
@@ -21,7 +21,6 @@
import com.android.tools.r8.ir.code.Store;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.CfBuilder.FixedLocal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -37,22 +36,6 @@
}
public void insertLoadsAndStores() {
- // Insert phi stores in all predecessors.
- for (BasicBlock block : code.blocks) {
- if (!block.getPhis().isEmpty()) {
- for (int predIndex = 0; predIndex < block.getPredecessors().size(); predIndex++) {
- BasicBlock pred = block.getPredecessors().get(predIndex);
- List<Phi> phis = block.getPhis();
- List<Value> values = new ArrayList<>(phis.size());
- for (Phi phi : phis) {
- values.add(phi.getOperand(predIndex));
- }
- InstructionListIterator it = pred.listIterator(pred.getInstructions().size());
- it.previous();
- movePhis(phis, values, it);
- }
- }
- }
// Insert per-instruction loads and stores.
for (BasicBlock block : code.blocks) {
InstructionListIterator it = block.listIterator();
@@ -63,6 +46,29 @@
}
}
+ public void insertPhiMoves(CfRegisterAllocator allocator) {
+ // Insert phi stores in all predecessors.
+ for (BasicBlock block : code.blocks) {
+ if (!block.getPhis().isEmpty()) {
+ for (int predIndex = 0; predIndex < block.getPredecessors().size(); predIndex++) {
+ BasicBlock pred = block.getPredecessors().get(predIndex);
+ List<Phi> phis = block.getPhis();
+ List<PhiMove> moves = new ArrayList<>(phis.size());
+ for (Phi phi : phis) {
+ Value value = phi.getOperand(predIndex);
+ if (allocator.getRegisterForValue(phi) != allocator.getRegisterForValue(value)) {
+ moves.add(new PhiMove(phi, value));
+ }
+ }
+ InstructionListIterator it = pred.listIterator(pred.getInstructions().size());
+ it.previous();
+ movePhis(moves, it);
+ }
+ }
+ }
+ code.blocks.forEach(BasicBlock::clearUserInfo);
+ }
+
private StackValue createStackValue(Value value, int height) {
if (value.outType().isObject()) {
return StackValue.forObjectType(types.get(value), height);
@@ -111,24 +117,32 @@
add(new Pop(newOutValue), instruction, it);
}
- public void movePhis(List<Phi> phis, List<Value> values, InstructionListIterator it) {
+ private static class PhiMove {
+ final Phi phi;
+ final Value operand;
+
+ public PhiMove(Phi phi, Value operand) {
+ this.phi = phi;
+ this.operand = operand;
+ }
+ }
+
+ private void movePhis(List<PhiMove> moves, InstructionListIterator it) {
// TODO(zerny): Accounting for non-interfering phis would lower the max stack size.
int topOfStack = 0;
- List<StackValue> temps = new ArrayList<>(phis.size());
- for (int i = 0; i < phis.size(); i++) {
- Phi phi = phis.get(i);
- Value value = values.get(i);
- StackValue tmp = createStackValue(phi, topOfStack++);
- add(load(tmp, value), phi.getBlock(), Position.none(), it);
+ List<StackValue> temps = new ArrayList<>(moves.size());
+ for (PhiMove move : moves) {
+ StackValue tmp = createStackValue(move.phi, topOfStack++);
+ add(load(tmp, move.operand), move.phi.getBlock(), Position.none(), it);
temps.add(tmp);
- value.removePhiUser(phi);
+ move.operand.removePhiUser(move.phi);
}
- for (int i = phis.size() - 1; i >= 0; i--) {
- Phi phi = phis.get(i);
+ for (int i = moves.size() - 1; i >= 0; i--) {
+ PhiMove move = moves.get(i);
StackValue tmp = temps.get(i);
- FixedLocal out = new FixedLocal(phi);
- add(new Store(out, tmp), phi.getBlock(), Position.none(), it);
- phi.replaceUsers(out);
+ FixedLocalValue out = new FixedLocalValue(move.phi);
+ add(new Store(out, tmp), move.phi.getBlock(), Position.none(), it);
+ move.phi.replaceUsers(out);
}
}
diff --git a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
index 2789252..500cff3 100644
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
@@ -321,7 +321,6 @@
}
private static void run(String[] args) throws DxUsageMessage, IOException, CompilationException {
- System.out.println("CompatDx " + String.join(" ", args));
DxCompatOptions dexArgs = DxCompatOptions.parse(args);
if (dexArgs.help) {
printHelpOn(System.out);
@@ -348,11 +347,11 @@
throw new DxUsageMessage("No input files specified");
}
- if (!Log.ENABLED && (!dexArgs.noWarning || dexArgs.debug || dexArgs.verbose)) {
+ if (!Log.ENABLED && dexArgs.debug) {
System.out.println("Warning: logging is not enabled for this build.");
}
- if (dexArgs.dump) {
+ if (dexArgs.dump && dexArgs.verbose) {
System.out.println("Warning: dump is not supported");
}
@@ -377,11 +376,11 @@
}
}
- if (dexArgs.dumpTo != null) {
+ if (dexArgs.dumpTo != null && dexArgs.verbose) {
System.out.println("dump-to file not yet supported");
}
- if (dexArgs.positions == PositionInfo.NONE) {
+ if (dexArgs.positions == PositionInfo.NONE && dexArgs.verbose) {
System.out.println("Warning: no support for positions none.");
}
@@ -393,7 +392,7 @@
throw new Unimplemented("incremental merge not supported yet");
}
- if (dexArgs.forceJumbo) {
+ if (dexArgs.forceJumbo && dexArgs.verbose) {
System.out.println(
"Warning: no support for forcing jumbo-strings.\n"
+ "Strings will only use jumbo-string indexing if necessary.\n"
@@ -401,7 +400,7 @@
+ "supports correct handling of jumbo-strings (eg, D8/R8 does).");
}
- if (dexArgs.noOptimize) {
+ if (dexArgs.noOptimize && dexArgs.verbose) {
System.out.println("Warning: no support for not optimizing");
}
@@ -413,7 +412,7 @@
throw new Unimplemented("no support for dont-optimize-method list");
}
- if (dexArgs.statistics) {
+ if (dexArgs.statistics && dexArgs.verbose) {
System.out.println("Warning: no support for printing statistics");
}
@@ -426,16 +425,20 @@
}
if (dexArgs.noStrict) {
- System.out.println("Warning: conservative main-dex list not yet supported");
+ if (dexArgs.verbose) {
+ System.out.println("Warning: conservative main-dex list not yet supported");
+ }
} else {
- System.out.println("Warning: strict name checking not yet supported");
+ if (dexArgs.verbose) {
+ System.out.println("Warning: strict name checking not yet supported");
+ }
}
- if (dexArgs.minimalMainDex) {
+ if (dexArgs.minimalMainDex && dexArgs.verbose) {
System.out.println("Warning: minimal main-dex support is not yet supported");
}
- if (dexArgs.maxIndexNumber != 0) {
+ if (dexArgs.maxIndexNumber != 0 && dexArgs.verbose) {
System.out.println("Warning: internal maximum-index setting is not supported");
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 934d3db..3ec6b1a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -7,22 +7,29 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.utils.CfgPrinter;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Map;
+import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;
public class IRCode {
+ // When numbering instructions we number instructions only with even numbers. This allows us to
+ // use odd instruction numbers for the insertion of moves during spilling.
+ public static final int INSTRUCTION_NUMBER_DELTA = 2;
+
public final DexEncodedMethod method;
public LinkedList<BasicBlock> blocks;
@@ -49,6 +56,66 @@
allThrowingInstructionsHavePositions = computeAllThrowingInstructionsHavePositions();
}
+ /**
+ * Compute the set of live values at the entry to each block using a backwards data-flow analysis.
+ */
+ public Map<BasicBlock, Set<Value>> computeLiveAtEntrySets() {
+ Map<BasicBlock, Set<Value>> liveAtEntrySets = new IdentityHashMap<>();
+ Queue<BasicBlock> worklist = new ArrayDeque<>();
+ // Since this is a backwards data-flow analysis we process the blocks in reverse
+ // topological order to reduce the number of iterations.
+ BasicBlock[] sorted = topologicallySortedBlocks();
+ for (int i = sorted.length - 1; i >= 0; i--) {
+ worklist.add(sorted[i]);
+ }
+ while (!worklist.isEmpty()) {
+ BasicBlock block = worklist.poll();
+ Set<Value> live = new HashSet<>();
+ for (BasicBlock succ : block.getSuccessors()) {
+ Set<Value> succLiveAtEntry = liveAtEntrySets.get(succ);
+ if (succLiveAtEntry != null) {
+ live.addAll(succLiveAtEntry);
+ }
+ int predIndex = succ.getPredecessors().indexOf(block);
+ for (Phi phi : succ.getPhis()) {
+ live.add(phi.getOperand(predIndex));
+ assert phi.getDebugValues().stream().allMatch(Value::needsRegister);
+ live.addAll(phi.getDebugValues());
+ }
+ }
+ ListIterator<Instruction> iterator =
+ block.getInstructions().listIterator(block.getInstructions().size());
+ while (iterator.hasPrevious()) {
+ Instruction instruction = iterator.previous();
+ if (instruction.outValue() != null) {
+ live.remove(instruction.outValue());
+ }
+ for (Value use : instruction.inValues()) {
+ if (use.needsRegister()) {
+ live.add(use);
+ }
+ }
+ assert instruction.getDebugValues().stream().allMatch(Value::needsRegister);
+ live.addAll(instruction.getDebugValues());
+ }
+ for (Phi phi : block.getPhis()) {
+ live.remove(phi);
+ }
+ Set<Value> previousLiveAtEntry = liveAtEntrySets.put(block, live);
+ // If the live-at-entry set changed, add the predecessors to the worklist if they are not
+ // already there.
+ if (previousLiveAtEntry == null || !previousLiveAtEntry.equals(live)) {
+ for (BasicBlock pred : block.getPredecessors()) {
+ if (!worklist.contains(pred)) {
+ worklist.add(pred);
+ }
+ }
+ }
+ }
+ assert liveAtEntrySets.get(sorted[0]).size() == 0;
+ return liveAtEntrySets;
+ }
+
public void splitCriticalEdges() {
List<BasicBlock> newBlocks = new ArrayList<>();
int nextBlockNumber = getHighestBlockNumber() + 1;
@@ -438,7 +505,7 @@
for (BasicBlock block : blocks) {
for (Instruction instruction : block.getInstructions()) {
instruction.setNumber(nextInstructionNumber);
- nextInstructionNumber += LinearScanRegisterAllocator.INSTRUCTION_NUMBER_DELTA;
+ nextInstructionNumber += INSTRUCTION_NUMBER_DELTA;
}
}
return blocks;
@@ -450,7 +517,7 @@
Instruction i = it.next();
if (i.getNumber() == -1) {
i.setNumber(nextInstructionNumber);
- nextInstructionNumber += LinearScanRegisterAllocator.INSTRUCTION_NUMBER_DELTA;
+ nextInstructionNumber += INSTRUCTION_NUMBER_DELTA;
}
}
return nextInstructionNumber;
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValue.java b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
index 65c4d3f..94909db 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StackValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
@@ -38,6 +38,16 @@
}
@Override
+ public boolean needsRegister() {
+ return false;
+ }
+
+ @Override
+ public void setNeedsRegister(boolean value) {
+ assert !value;
+ }
+
+ @Override
public String toString() {
return "s" + height;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java
index 7bdf7ad..05c7c79 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Store.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.cf.FixedLocalValue;
import com.android.tools.r8.cf.LoadStoreHelper;
import com.android.tools.r8.cf.TypeVerificationHelper;
import com.android.tools.r8.cf.code.CfStore;
@@ -10,7 +11,6 @@
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.CfBuilder.FixedLocal;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.utils.InternalOptions;
@@ -72,6 +72,6 @@
@Override
public boolean canBeDeadCode(IRCode code, InternalOptions options) {
- return !(outValue instanceof FixedLocal);
+ return !(outValue instanceof FixedLocalValue);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index d4cc49c..0ad6c6c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
+import com.android.tools.r8.cf.CfRegisterAllocator;
import com.android.tools.r8.cf.LoadStoreHelper;
import com.android.tools.r8.cf.TypeVerificationHelper;
import com.android.tools.r8.cf.code.CfFrame;
@@ -24,7 +25,6 @@
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Load;
-import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.StackValue;
import com.android.tools.r8.ir.code.Store;
import com.android.tools.r8.ir.code.Value;
@@ -33,8 +33,6 @@
import com.android.tools.r8.utils.InternalOptions;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -50,39 +48,10 @@
private final DexEncodedMethod method;
private final IRCode code;
- private int maxLocals = -1;
-
private Map<Value, DexType> types;
- private Reference2IntMap<Value> registers;
private Map<BasicBlock, CfLabel> labels;
private List<CfInstruction> instructions;
-
- /**
- * Value that represents a shared physical location defined by the phi value.
- *
- * This value is introduced to represent the store instructions used to unify the location of
- * in-flowing values to phi's. After introducing this fixed location the graph is no longer in
- * SSA since the fixed location signifies a place that can be written to from multiple places.
- */
- public static class FixedLocal extends Value {
-
- private final Phi phi;
-
- public FixedLocal(Phi phi) {
- super(phi.getNumber(), phi.outType(), phi.getLocalInfo());
- this.phi = phi;
- }
-
- @Override
- public boolean isConstant() {
- return false;
- }
-
- @Override
- public String toString() {
- return "fixed:v" + phi.getNumber();
- }
- }
+ private CfRegisterAllocator registerAllocator;
// Internal abstraction of the stack values and height.
private static class Stack {
@@ -115,10 +84,14 @@
try {
types = new TypeVerificationHelper(code, factory).computeVerificationTypes();
splitExceptionalBlocks();
- new LoadStoreHelper(code, types).insertLoadsAndStores();
+ LoadStoreHelper loadStoreHelper = new LoadStoreHelper(code, types);
+ loadStoreHelper.insertLoadsAndStores();
DeadCodeRemover.removeDeadCode(code, rewriter, options);
removeUnneededLoadsAndStores();
- allocateLocalRegisters();
+ registerAllocator = new CfRegisterAllocator(code, options);
+ registerAllocator.allocateRegisters();
+ loadStoreHelper.insertPhiMoves(registerAllocator);
+ CodeRewriter.collapsTrivialGotos(method, code);
// TODO(zerny): Compute debug info.
CfCode code = buildCfCode();
return code;
@@ -193,29 +166,6 @@
}
}
- private void allocateLocalRegisters() {
- // TODO(zerny): Allocate locals based on live ranges.
- InstructionIterator it = code.instructionIterator();
- registers = new Reference2IntOpenHashMap<>();
- int nextFreeRegister = 0;
- while (it.hasNext()) {
- Instruction instruction = it.next();
- Value outValue = instruction.outValue();
- if (outValue instanceof FixedLocal) {
- // Phi stores are marked by a "fixed-local" value which share the same local index.
- FixedLocal fixed = (FixedLocal) outValue;
- if (!registers.containsKey(fixed.phi)) {
- registers.put(fixed.phi, nextFreeRegister);
- nextFreeRegister += fixed.requiredRegisters();
- }
- } else if (outValue != null && !(outValue instanceof StackValue)) {
- registers.put(instruction.outValue(), nextFreeRegister);
- nextFreeRegister += instruction.outValue().requiredRegisters();
- }
- }
- maxLocals = nextFreeRegister;
- }
-
private CfCode buildCfCode() {
Stack stack = new Stack();
List<CfTryCatch> tryCatchRanges = new ArrayList<>();
@@ -253,13 +203,14 @@
assert stack.isEmpty();
instructions.add(getLabel(nextBlock));
if (nextBlock.getPredecessors().size() > 1) {
- addFrame(Collections.emptyList(), types.keySet());
+ addFrame(nextBlock, Collections.emptyList());
}
}
block = nextBlock;
} while (block != null);
assert stack.isEmpty();
- return new CfCode(stack.maxHeight, maxLocals, instructions, tryCatchRanges);
+ return new CfCode(
+ stack.maxHeight, registerAllocator.registersUsed(), instructions, tryCatchRanges);
}
private void buildCfInstructions(BasicBlock block, boolean fallthrough, Stack stack) {
@@ -285,9 +236,10 @@
}
}
- private void addFrame(Collection<StackValue> stack, Collection<Value> locals) {
+ private void addFrame(BasicBlock block, Collection<StackValue> stack) {
// TODO(zerny): Support having values on the stack on control-edges.
assert stack.isEmpty();
+ Collection<Value> locals = registerAllocator.getLocalsAtPosition(block.entry().getNumber());
Int2ReferenceSortedMap<DexType> mapping = new Int2ReferenceAVLTreeMap<>();
for (Value local : locals) {
DexType type;
@@ -323,12 +275,7 @@
}
public int getLocalRegister(Value value) {
- if (value instanceof FixedLocal) {
- // Phi stores are marked by a "fixed-local" value which share the same local index.
- FixedLocal fixed = (FixedLocal) value;
- return registers.getInt(fixed.phi);
- }
- return registers.getInt(value);
+ return registerAllocator.getRegisterForValue(value);
}
public void add(CfInstruction instruction) {
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 43a91f3..928d3c1 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
@@ -57,7 +57,6 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Switch;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.BiMap;
@@ -510,7 +509,7 @@
}
private static int instructionNumberToIndex(int instructionNumber) {
- return instructionNumber / LinearScanRegisterAllocator.INSTRUCTION_NUMBER_DELTA;
+ return instructionNumber / IRCode.INSTRUCTION_NUMBER_DELTA;
}
// Helper used by the info objects.
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 55ecb45..b982b52 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
@@ -4,7 +4,9 @@
package com.android.tools.r8.ir.regalloc;
-import com.android.tools.r8.code.MoveType;
+import static com.android.tools.r8.ir.code.IRCode.INSTRUCTION_NUMBER_DELTA;
+import static com.android.tools.r8.ir.regalloc.LiveIntervals.NO_REGISTER;
+
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.ir.code.Add;
@@ -41,14 +43,12 @@
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.PriorityQueue;
-import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
@@ -67,7 +67,7 @@
* </ul>
*/
public class LinearScanRegisterAllocator implements RegisterAllocator {
- public static final int NO_REGISTER = Integer.MIN_VALUE;
+
public static final int REGISTER_CANDIDATE_NOT_FOUND = -1;
public static final int MIN_CONSTANT_FREE_FOR_POSITIONS = 5;
@@ -105,9 +105,6 @@
}
}
- // When numbering instructions we number instructions only with even numbers. This allows us to
- // use odd instruction numbers for the insertion of moves during spilling.
- public static final int INSTRUCTION_NUMBER_DELTA = 2;
// The max register number that will fit in any dex instruction encoding.
private static final int MAX_SMALL_REGISTER = Constants.U4BIT_MAX;
// We put one sentinel in front of the argument chain and one after the argument chain.
@@ -121,7 +118,7 @@
private final InternalOptions options;
// Mapping from basic blocks to the set of values live at entry to that basic block.
- private Map<BasicBlock, Set<Value>> liveAtEntrySets = new IdentityHashMap<>();
+ private Map<BasicBlock, Set<Value>> liveAtEntrySets;
// The sentinel value starting the chain of linked argument values.
private Value preArgumentSentinelValue = null;
@@ -488,7 +485,7 @@
boolean unused = intervals.isSpilledAndRematerializable(this);
if (!unused) {
used.add(realRegisterNumberFromAllocated(intervals.getRegister()));
- if (intervals.getType() == MoveType.WIDE) {
+ if (intervals.getType().isWide()) {
used.add(realRegisterNumberFromAllocated(intervals.getRegister() + 1));
}
}
@@ -535,7 +532,7 @@
private BasicBlock[] computeLivenessInformation() {
BasicBlock[] blocks = code.numberInstructions();
- computeLiveAtEntrySets();
+ liveAtEntrySets = code.computeLiveAtEntrySets();
computeLiveRanges();
return blocks;
}
@@ -933,7 +930,7 @@
for (int i = 0; i < numberOfRegister; i++) {
assert current != null;
current.setRegister(firstRegister + i);
- if (current.getType() == MoveType.WIDE) {
+ if (current.getType().isWide()) {
assert i < numberOfRegister;
i++;
}
@@ -974,7 +971,7 @@
private int getSpillRegister(LiveIntervals intervals) {
int registerNumber = nextUnusedRegisterNumber++;
maxRegisterNumber = registerNumber;
- if (intervals.getType() == MoveType.WIDE) {
+ if (intervals.getType().isWide()) {
nextUnusedRegisterNumber++;
maxRegisterNumber++;
}
@@ -1817,65 +1814,6 @@
}
}
- /**
- * Compute the set of live values at the entry to each block using a backwards data-flow
- * analysis.
- */
- private void computeLiveAtEntrySets() {
- Queue<BasicBlock> worklist = new LinkedList<>();
- // Since this is a backwards data-flow analysis we process the blocks in reverse
- // topological order to reduce the number of iterations.
- BasicBlock[] sorted = code.topologicallySortedBlocks();
- for (int i = sorted.length - 1; i >= 0; i--) {
- worklist.add(sorted[i]);
- }
- while (!worklist.isEmpty()) {
- BasicBlock block = worklist.poll();
- Set<Value> live = new HashSet<>();
- for (BasicBlock succ : block.getSuccessors()) {
- Set<Value> succLiveAtEntry = liveAtEntrySets.get(succ);
- if (succLiveAtEntry != null) {
- live.addAll(succLiveAtEntry);
- }
- int predIndex = succ.getPredecessors().indexOf(block);
- for (Phi phi : succ.getPhis()) {
- live.add(phi.getOperand(predIndex));
- assert phi.getDebugValues().stream().allMatch(Value::needsRegister);
- live.addAll(phi.getDebugValues());
- }
- }
- ListIterator<Instruction> iterator =
- block.getInstructions().listIterator(block.getInstructions().size());
- while (iterator.hasPrevious()) {
- Instruction instruction = iterator.previous();
- if (instruction.outValue() != null) {
- live.remove(instruction.outValue());
- }
- for (Value use : instruction.inValues()) {
- if (use.needsRegister()) {
- live.add(use);
- }
- }
- assert instruction.getDebugValues().stream().allMatch(Value::needsRegister);
- live.addAll(instruction.getDebugValues());
- }
- for (Phi phi : block.getPhis()) {
- live.remove(phi);
- }
- Set<Value> previousLiveAtEntry = liveAtEntrySets.put(block, live);
- // If the live at entry set changed for this block at the predecessors to the worklist if
- // they are not already there.
- if (previousLiveAtEntry == null || !previousLiveAtEntry.equals(live)) {
- for (BasicBlock pred : block.getPredecessors()) {
- if (!worklist.contains(pred)) {
- worklist.add(pred);
- }
- }
- }
- }
- assert liveAtEntrySets.get(sorted[0]).size() == 0;
- }
-
private void addLiveRange(Value v, BasicBlock b, int end) {
int firstInstructionInBlock = b.entry().getNumber();
int instructionsSize = b.getInstructions().size() * INSTRUCTION_NUMBER_DELTA;
@@ -2187,7 +2125,7 @@
private void freeRegistersForIntervals(LiveIntervals intervals) {
int register = intervals.getRegister();
freeRegisters.add(register);
- if (intervals.getType() == MoveType.WIDE) {
+ if (intervals.getType().isWide()) {
freeRegisters.add(register + 1);
}
}
@@ -2195,7 +2133,7 @@
private void takeRegistersForIntervals(LiveIntervals intervals) {
int register = intervals.getRegister();
freeRegisters.remove(register);
- if (intervals.getType() == MoveType.WIDE) {
+ if (intervals.getType().isWide()) {
freeRegisters.remove(register + 1);
}
}
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 4745a81..4c68c4a 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
@@ -4,11 +4,11 @@
package com.android.tools.r8.ir.regalloc;
import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
-import static com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator.NO_REGISTER;
import com.android.tools.r8.code.MoveType;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.CfgPrinter;
import java.util.ArrayList;
import java.util.Iterator;
@@ -17,8 +17,9 @@
public class LiveIntervals implements Comparable<LiveIntervals> {
+ public static final int NO_REGISTER = Integer.MIN_VALUE;
+
private final Value value;
- private final MoveType type;
private LiveIntervals nextConsecutive;
private LiveIntervals previousConsecutive;
private LiveIntervals splitParent;
@@ -39,18 +40,16 @@
// conservatively determine if it is safe to use rematerialization for this value.
private int maxNonSpilledRegister = NO_REGISTER;
- LiveIntervals(Value value) {
+ public LiveIntervals(Value value) {
this.value = value;
- this.type = MoveType.fromValueType(value.outType());
usedInMonitorOperations = value.usedInMonitorOperation();
splitParent = this;
value.setLiveIntervals(this);
}
- LiveIntervals(LiveIntervals splitParent) {
+ public LiveIntervals(LiveIntervals splitParent) {
this.splitParent = splitParent;
value = splitParent.value;
- type = splitParent.type;
usedInMonitorOperations = splitParent.usedInMonitorOperations;
}
@@ -62,16 +61,20 @@
return position % 2 == 1 ? position : position - 1;
}
- public MoveType getType() {
- return type;
- }
-
public Value getValue() {
return value;
}
+ public ValueType getType() {
+ return value.outType();
+ }
+
+ public MoveType getMoveType() {
+ return MoveType.fromValueType(getType());
+ }
+
public int requiredRegisters() {
- return type == MoveType.WIDE ? 2 : 1;
+ return getType().requiredRegisters();
}
public void setHint(LiveIntervals intervals) {
@@ -294,7 +297,7 @@
}
public boolean usesRegister(int n) {
- if (register == n || (getType() == MoveType.WIDE && register + 1 == n)) {
+ if (register == n || (getType().isWide() && register + 1 == n)) {
return true;
}
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveRange.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveRange.java
index 0d7bb80..711c400 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveRange.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveRange.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.regalloc;
-class LiveRange {
+public class LiveRange {
public final static LiveRange INFINITE = new LiveRange(0, Integer.MAX_VALUE);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
index dd857fc..8724d43 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
@@ -24,7 +24,7 @@
public RegisterMove(int dst, MoveType type, Instruction definition) {
this.dst = dst;
- this.src = LinearScanRegisterAllocator.NO_REGISTER;
+ this.src = LiveIntervals.NO_REGISTER;
this.type = type;
assert definition.isConstInstruction() || definition.isArgument();
this.definition = definition;
@@ -40,7 +40,7 @@
public boolean isBlocked(Set<RegisterMove> moveSet, Map<Integer, Integer> valueMap) {
for (RegisterMove move : moveSet) {
- if (move.src == LinearScanRegisterAllocator.NO_REGISTER) {
+ if (move.src == LiveIntervals.NO_REGISTER) {
continue;
}
if (move != this) {
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 9a22d76..32bdca4 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
@@ -50,7 +50,7 @@
public void addMove(RegisterMove move) {
moveSet.add(move);
- if (move.src != LinearScanRegisterAllocator.NO_REGISTER) {
+ if (move.src != LiveIntervals.NO_REGISTER) {
valueMap.put(move.src, move.src);
}
valueMap.put(move.dst, move.dst);
@@ -80,7 +80,7 @@
Integer generatedDest = createMove(move);
// Update the value map with the information that dest can be used instead of
// src starting now.
- if (move.src != LinearScanRegisterAllocator.NO_REGISTER) {
+ if (move.src != LiveIntervals.NO_REGISTER) {
valueMap.put(move.src, generatedDest);
}
// Iterate and find the moves that were blocked because they need to write to
@@ -110,9 +110,9 @@
private List<RegisterMove> findMovesWithSrc(int src, MoveType type) {
List<RegisterMove> result = new ArrayList<>();
- assert src != LinearScanRegisterAllocator.NO_REGISTER;
+ assert src != LiveIntervals.NO_REGISTER;
for (RegisterMove move : moveSet) {
- if (move.src == LinearScanRegisterAllocator.NO_REGISTER) {
+ if (move.src == LiveIntervals.NO_REGISTER) {
continue;
}
int moveSrc = valueMap.get(move.src);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java
index 70354fe..ebc95ec 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMove.java
@@ -20,8 +20,8 @@
this.type = type;
this.to = to;
this.from = from;
- assert to.getRegister() != LinearScanRegisterAllocator.NO_REGISTER;
- assert from.getRegister() != LinearScanRegisterAllocator.NO_REGISTER;
+ assert to.getRegister() != LiveIntervals.NO_REGISTER;
+ assert from.getRegister() != LiveIntervals.NO_REGISTER;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
index e466904..979b128 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
@@ -144,8 +144,8 @@
}
private MoveType moveTypeForIntervals(LiveIntervals to, LiveIntervals from) {
- MoveType toType = to.getType();
- MoveType fromType = from.getType();
+ MoveType toType = to.getMoveType();
+ MoveType fromType = from.getMoveType();
if (toType == MoveType.OBJECT || fromType == MoveType.OBJECT) {
assert fromType == MoveType.OBJECT || fromType == MoveType.SINGLE;
assert toType == MoveType.OBJECT || toType == MoveType.SINGLE;