blob: de6c3c6abb17ad8634e83b04057c54ccec1e77a8 [file] [log] [blame]
// 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.ir.regalloc;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InitClass;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Move;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
import com.android.tools.r8.utils.InternalOptions;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class RegisterMoveSchedulerTest extends TestBase {
private static class CollectMovesIterator implements InstructionListIterator {
private final LinkedList<Instruction> list = new LinkedList<>();
private final ListIterator<Instruction> it = list.listIterator();
public Move get(int i) {
return list.get(i).asMove();
}
public ConstNumber getConst(int i) {
return list.get(i).asConstNumber();
}
public int size() {
return list.size();
}
@Override
public void replaceCurrentInstruction(
Instruction newInstruction, AffectedValues affectedValues) {
throw new Unimplemented();
}
@Override
public Value insertConstNumberInstruction(
IRCode code, InternalOptions options, long value, TypeElement type) {
throw new Unimplemented();
}
@Override
public Value insertConstStringInstruction(AppView<?> appView, IRCode code, DexString value) {
throw new Unimplemented();
}
@Override
public InvokeMethod insertNullCheckInstruction(
AppView<?> appView,
IRCode code,
BasicBlockIterator blockIterator,
Value value,
Position position) {
throw new Unimplemented();
}
@Override
public boolean replaceCurrentInstructionByNullCheckIfPossible(
AppView<?> appView, ProgramMethod context) {
throw new Unimplemented();
}
@Override
public boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
AppView<?> appView, IRCode code, DexType type, Consumer<InitClass> consumer) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithConstClass(
AppView<?> appView,
IRCode code,
DexType type,
DebugLocalInfo localInfo,
AffectedValues affectedValues) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithConstInt(IRCode code, int value) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithConstString(
AppView<?> appView, IRCode code, DexString value, AffectedValues affectedValues) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithNullCheck(AppView<?> appView, Value object) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, AffectedValues affectedValues) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithThrow(
AppView<?> appView,
IRCode code,
BasicBlockIterator blockIterator,
Value exceptionValue,
Set<BasicBlock> blocksToRemove,
AffectedValues affectedValues) {
throw new Unimplemented();
}
@Override
public void replaceCurrentInstructionWithThrowNull(
AppView<?> appView,
IRCode code,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
AffectedValues affectedValues) {
throw new Unimplemented();
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public Instruction next() {
return it.next();
}
@Override
public boolean hasPrevious() {
return it.hasPrevious();
}
@Override
public Instruction previous() {
return it.previous();
}
@Override
public int nextIndex() {
return it.nextIndex();
}
@Override
public int previousIndex() {
return it.previousIndex();
}
@Override
public void remove() {
it.remove();
}
@Override
public void removeOrReplaceByDebugLocalRead() {
remove();
}
@Override
public void set(Instruction instruction) {
it.set(instruction);
}
@Override
public void set(Collection<Instruction> instructions) {
throw new Unimplemented();
}
@Override
public void add(Instruction instruction) {
it.add(instruction);
}
@Override
public InstructionListIterator addPossiblyThrowingInstructionsToPossiblyThrowingBlock(
IRCode code,
BasicBlockIterator blockIterator,
Collection<? extends Instruction> instructionsToAdd,
InternalOptions options) {
throw new Unimplemented();
}
@Override
public BasicBlock split(
IRCode code, ListIterator<BasicBlock> blockIterator, boolean keepCatchHandlers) {
throw new Unimplemented();
}
@Override
public BasicBlock split(IRCode code, int instructions,
ListIterator<BasicBlock> blockIterator) {
throw new Unimplemented();
}
@Override
public BasicBlock splitCopyCatchHandlers(
IRCode code,
BasicBlockIterator blockIterator,
InternalOptions options,
UnaryOperator<BasicBlock> repositioningBlock) {
throw new Unimplemented();
}
@Override
public BasicBlock inlineInvoke(
AppView<?> appView,
IRCode code,
IRCode inlinee,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
DexProgramClass downcast) {
throw new Unimplemented();
}
}
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
}
public RegisterMoveSchedulerTest(TestParameters parameters) {
parameters.assertNoneRuntime();
}
@Test
public void testSingleParallelMove() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 1, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(1, 0, TypeElement.getInt()));
scheduler.schedule();
assertEquals(3, moves.size());
Move tempMove = moves.get(0);
Move firstMove = moves.get(1);
Move secondMove = moves.get(2);
assertEquals(ValueType.INT, tempMove.outType());
assertEquals(ValueType.INT, firstMove.outType());
assertEquals(ValueType.INT, secondMove.outType());
assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
assertEquals(
tempMove.src().asFixedRegisterValue().getRegister(),
firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(temp, secondMove.src().asFixedRegisterValue().getRegister());
assertEquals(
firstMove.src().asFixedRegisterValue().getRegister(),
secondMove.dest().asFixedRegisterValue().getRegister());
}
@Test
public void testWideParallelMove() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 2, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(2, 0, TypeElement.getLong()));
scheduler.schedule();
assertEquals(3, moves.size());
Move tempMove = moves.get(0);
Move firstMove = moves.get(1);
Move secondMove = moves.get(2);
assertEquals(ValueType.LONG, tempMove.outType());
assertEquals(ValueType.LONG, firstMove.outType());
assertEquals(ValueType.LONG, secondMove.outType());
assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
assertEquals(
tempMove.src().asFixedRegisterValue().getRegister(),
firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(temp, secondMove.src().asFixedRegisterValue().getRegister());
assertEquals(
firstMove.src().asFixedRegisterValue().getRegister(),
secondMove.dest().asFixedRegisterValue().getRegister());
}
@Test
public void testMixedParralelMove() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(1, 0, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(0, 1, TypeElement.getInt()));
scheduler.schedule();
assertEquals(3, moves.size());
Move tempMove = moves.get(0).asMove();
Move firstMove = moves.get(1).asMove();
Move secondMove = moves.get(2).asMove();
assertEquals(ValueType.LONG, tempMove.outType());
assertEquals(ValueType.INT, firstMove.outType());
assertEquals(ValueType.LONG, secondMove.outType());
assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
assertEquals(
tempMove.src().asFixedRegisterValue().getRegister(),
firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(temp, secondMove.src().asFixedRegisterValue().getRegister());
assertEquals(
firstMove.src().asFixedRegisterValue().getRegister(),
secondMove.dest().asFixedRegisterValue().getRegister());
}
@Test
public void testMixedParralelMove2() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 1, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(1, 0, TypeElement.getLong()));
scheduler.schedule();
assertEquals(3, moves.size());
Move tempMove = moves.get(0).asMove();
Move firstMove = moves.get(1).asMove();
Move secondMove = moves.get(2).asMove();
assertEquals(ValueType.LONG, tempMove.outType());
assertEquals(ValueType.INT, firstMove.outType());
assertEquals(ValueType.LONG, secondMove.outType());
assertEquals(temp, tempMove.dest().asFixedRegisterValue().getRegister());
assertEquals(
tempMove.src().asFixedRegisterValue().getRegister(),
firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(temp, secondMove.src().asFixedRegisterValue().getRegister());
assertEquals(
firstMove.src().asFixedRegisterValue().getRegister(),
secondMove.dest().asFixedRegisterValue().getRegister());
}
@Test
public void testSlideWideMoves() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 1, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(2, 3, TypeElement.getLong()));
scheduler.schedule();
assertEquals(2, moves.size());
Move firstMove = moves.get(0).asMove();
Move secondMove = moves.get(1).asMove();
assertEquals(ValueType.LONG, firstMove.outType());
assertEquals(ValueType.LONG, secondMove.outType());
assertEquals(0, firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(1, firstMove.src().asFixedRegisterValue().getRegister());
assertEquals(2, secondMove.dest().asFixedRegisterValue().getRegister());
assertEquals(3, secondMove.src().asFixedRegisterValue().getRegister());
}
@Test
public void testSlideWideMoves2() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(2, 1, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(0, 3, TypeElement.getLong()));
scheduler.schedule();
assertEquals(3, moves.size());
assertEquals("42 <- 3", toString(moves.get(0)));
assertEquals("2 <- 1", toString(moves.get(1)));
assertEquals("0 <- 42", toString(moves.get(2)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
@Test
public void testWideBlockedByTwoSingle() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(2, 0, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(0, 2, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(1, 3, TypeElement.getInt()));
scheduler.schedule();
assertEquals(4, moves.size());
Move firstMove = moves.get(0).asMove();
Move secondMove = moves.get(1).asMove();
Move thirdMove = moves.get(2).asMove();
Move fourthMove = moves.get(3).asMove();
assertEquals(ValueType.LONG, firstMove.outType());
assertEquals(ValueType.INT, secondMove.outType());
assertEquals(ValueType.INT, thirdMove.outType());
assertEquals(ValueType.LONG, fourthMove.outType());
assertEquals(temp, firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(0, secondMove.dest().asFixedRegisterValue().getRegister());
assertEquals(1, thirdMove.dest().asFixedRegisterValue().getRegister());
assertEquals(2, fourthMove.dest().asFixedRegisterValue().getRegister());
}
@Test
public void testSingleBlockedBySecondPartOfWide() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 2, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(3, 0, TypeElement.getInt()));
scheduler.schedule();
assertEquals(3, moves.size());
Move firstMove = moves.get(0).asMove();
Move secondMove = moves.get(1).asMove();
Move thirdMove = moves.get(2).asMove();
assertEquals(ValueType.LONG, firstMove.outType());
assertEquals(ValueType.INT, secondMove.outType());
assertEquals(ValueType.LONG, thirdMove.outType());
assertEquals(temp, firstMove.dest().asFixedRegisterValue().getRegister());
assertEquals(2, firstMove.src().asFixedRegisterValue().getRegister());
assertEquals(3, secondMove.dest().asFixedRegisterValue().getRegister());
assertEquals(0, secondMove.src().asFixedRegisterValue().getRegister());
assertEquals(0, thirdMove.dest().asFixedRegisterValue().getRegister());
assertEquals(temp, thirdMove.src().asFixedRegisterValue().getRegister());
}
@Test
public void multipleWideMoves() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(14, 11, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(16, 13, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(10, 17, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(12, 19, TypeElement.getLong()));
scheduler.schedule();
// In order to resolve these moves, we need to use two temporary register pairs.
assertEquals(5, moves.size());
assertEquals("42 <- 13", toString(moves.get(0)));
assertEquals("14 <- 11", toString(moves.get(1)));
assertEquals("10 <- 17", toString(moves.get(2)));
assertEquals("16 <- 42", toString(moves.get(3)));
assertEquals("12 <- 19", toString(moves.get(4)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
@Test
public void multipleLiveTempRegisters() {
InternalOptions options = new InternalOptions();
AppView<AppInfo> appInfo =
AppView.createForD8(
AppInfo.createInitialAppInfo(
DexApplication.builder(options, null).build(),
GlobalSyntheticsStrategy.forNonSynthesizing()));
TypeElement objectType =
TypeElement.fromDexType(options.itemFactory.objectType, Nullability.maybeNull(), appInfo);
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(26, 22, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(29, 24, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(28, 26, objectType));
scheduler.addMove(new RegisterMove(23, 28, TypeElement.getLong()));
scheduler.schedule();
// For this example we need recursive unblocking.
assertEquals(5, moves.size());
assertEquals("42 <- 28", toString(moves.get(0)));
assertEquals("29 <- 24", toString(moves.get(1)));
assertEquals("23 <- 42", toString(moves.get(2)));
assertEquals("28 <- 26", toString(moves.get(3)));
assertEquals("26 <- 22", toString(moves.get(4)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
@Test
public void reuseTempRegister() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 1, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(1, 0, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(2, 3, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(3, 2, TypeElement.getInt()));
scheduler.schedule();
// Verify that the temp register has been reused.
assertEquals("42 <- 1", toString(moves.get(0)));
assertEquals("1 <- 0", toString(moves.get(1)));
assertEquals("0 <- 42", toString(moves.get(2)));
assertEquals("42 <- 3", toString(moves.get(3)));
assertEquals("3 <- 2", toString(moves.get(4)));
assertEquals("2 <- 42", toString(moves.get(5)));
assertEquals(1, scheduler.getUsedTempRegisters());
}
@Test
public void useDestinationRegisterAsTemporary() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(0, 1, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(1, 0, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(2, 3, TypeElement.getInt()));
scheduler.schedule();
// Verify that the temp register has been reused.
assertEquals("2 <- 1", toString(moves.get(0)));
assertEquals("1 <- 0", toString(moves.get(1)));
assertEquals("0 <- 2", toString(moves.get(2)));
assertEquals("2 <- 3", toString(moves.get(3)));
assertEquals(0, scheduler.getUsedTempRegisters());
}
@Test
public void openMoveCycle() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(2, 0, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(0, 2, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(4, 1, TypeElement.getInt()));
scheduler.schedule();
// The cycle is blocked by the move 4 <- 1, so we should emit this move first.
assertEquals(4, moves.size());
assertEquals("4 <- 1", toString(moves.get(0)));
assertEquals("42 <- 2", toString(moves.get(1)));
assertEquals("2 <- 0", toString(moves.get(2)));
assertEquals("0 <- 42", toString(moves.get(3)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
@Test
public void regressionTestBug378850589() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(9, 12, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(11, 8, TypeElement.getLong()));
scheduler.schedule();
assertEquals(3, moves.size());
assertEquals("42 <- 12", toString(moves.get(0)));
assertEquals("11 <- 8", toString(moves.get(1)));
assertEquals("9 <- 42", toString(moves.get(2)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
@Test
public void regressionTestBug379007412() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
int args = 3;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp, args);
scheduler.addMove(new RegisterMove(2, 8, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(21, 13, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(8, 15, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(3, 16, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(13, 21, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(15, 25, TypeElement.getLong()));
scheduler.schedule();
assertEquals(7, moves.size());
assertEquals("42 <- 21", toString(moves.get(0)));
assertEquals("21 <- 13", toString(moves.get(1)));
assertEquals("13 <- 42", toString(moves.get(2)));
assertEquals("2 <- 8", toString(moves.get(3)));
assertEquals("8 <- 15", toString(moves.get(4)));
assertEquals("3 <- 16", toString(moves.get(5)));
assertEquals("15 <- 25", toString(moves.get(6)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
@Test
public void reproNoSuchElementException() {
CollectMovesIterator moves = new CollectMovesIterator();
int temp = 42;
RegisterMoveScheduler scheduler = new RegisterMoveScheduler(moves, temp);
scheduler.addMove(new RegisterMove(10, 2, TypeElement.getInt()));
scheduler.addMove(new RegisterMove(2, 7, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(4, 11, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(6, 0, TypeElement.getLong()));
scheduler.addMove(new RegisterMove(8, 3, TypeElement.getLong()));
scheduler.addMove(
new RegisterMove(
11,
TypeElement.getInt(),
new ConstNumber(new Value(0, TypeElement.getInt(), null), 0)));
scheduler.schedule();
assertEquals(8, moves.size());
assertEquals("10 <- 2", toString(moves.get(0)));
assertEquals("5 <- 11", toString(moves.get(1)));
assertEquals("11 <- const 0", toString(moves.getConst(2)));
assertEquals("42 <- 7", toString(moves.get(3)));
assertEquals("8 <- 3", toString(moves.get(4)));
assertEquals("2 <- 42", toString(moves.get(5)));
assertEquals("4 <- 5", toString(moves.get(6)));
assertEquals("6 <- 0", toString(moves.get(7)));
assertEquals(2, scheduler.getUsedTempRegisters());
}
// Debugging aid.
private void printMoves(List<Instruction> moves) {
System.out.println("Generated moves:");
System.out.println("----------------");
for (Instruction move : moves) {
System.out.println(move.asMove().dest().asFixedRegisterValue().getRegister() + " <- " +
move.asMove().src().asFixedRegisterValue().getRegister() + " (" + move.outType() + ")");
}
System.out.println("----------------");
}
private String toString(ConstNumber move) {
return move.outValue().asFixedRegisterValue().getRegister()
+ " <- const "
+ move.asConstNumber().getRawValue();
}
private String toString(Move move) {
return move.outValue().asFixedRegisterValue().getRegister()
+ " <- "
+ move.getFirstOperand().asFixedRegisterValue().getRegister();
}
}