/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.regalloc;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
import static org.jikesrvm.compilers.opt.ir.Operators.FENCE;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.ir.Binary;
import org.jikesrvm.compilers.opt.ir.Empty;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.junit.runners.RequiresBuiltJikesRVM;
import org.jikesrvm.junit.runners.RequiresOptCompiler;
import org.jikesrvm.junit.runners.VMRequirements;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
@RunWith(VMRequirements.class)
@Category({RequiresOptCompiler.class})
public class ScratchMapTest {
private static final int REGISTER_COUNT = 100;
private RegisterAllocatorState regAllocState;
private ScratchMap scratchMap;
@Before
public void createNewScratchMap() {
regAllocState = new RegisterAllocatorState(REGISTER_COUNT);
scratchMap = new ScratchMap(regAllocState);
}
@Test
public void newMapIsEmpty() {
ScratchMap scratchMap = new ScratchMap(regAllocState);
assertThat(scratchMap.isEmpty(), is(true));
}
@Category(RequiresBuiltJikesRVM.class) // because of TypeReference
@Test
public void markDirtyMarksRegistersAsDirty() {
Register resultReg = createRegister(0);
RegisterOperand result = new RegisterOperand(resultReg, TypeReference.Int);
Register op1Reg = new Register(1);
Register op2Reg = new Register(2);
RegisterOperand op1 = new RegisterOperand(op1Reg, TypeReference.Int);
RegisterOperand op2 = new RegisterOperand(op2Reg, TypeReference.Int);
Instruction add = Binary.create(INT_ADD, result, op1, op2);
scratchMap.markDirty(add, op2Reg);
assertThat(scratchMap.isDirty(add, op2Reg), is(true));
}
@Category(RequiresBuiltJikesRVM.class) // because of TypeReference
@Test
public void markingRegistersAsDirtyMoreThanOnceIsHarmless() {
Register resultReg = createRegister(0);
RegisterOperand result = new RegisterOperand(resultReg, TypeReference.Int);
Register op1Reg = new Register(1);
Register op2Reg = new Register(2);
RegisterOperand op1 = new RegisterOperand(op1Reg, TypeReference.Int);
RegisterOperand op2 = new RegisterOperand(op2Reg, TypeReference.Int);
Instruction add = Binary.create(INT_ADD, result, op1, op2);
scratchMap.markDirty(add, op2Reg);
scratchMap.markDirty(add, op2Reg);
assertThat(scratchMap.isDirty(add, op2Reg), is(true));
}
@Test
public void markDirtyDoesNotCheckThatRegisterIsUsedInInstruction() {
Register symb = createRegister(0);
Instruction inst = createInstruction();
scratchMap.markDirty(inst, symb);
assertThat(scratchMap.isDirty(inst, symb), is(true));
}
@Test
public void beginSymbolicIntervalCreatesANewInterval() {
Register symb = createRegister(0);
Register scratch = createRegister(0);
Instruction inst = createInstruction();
scratchMap.beginSymbolicInterval(symb, scratch, inst);
assertThat(scratchMap.isEmpty(), is(false));
}
@Test(expected = NullPointerException.class)
public void endSymbolicIntervalRemovesInformationAboutScratchRegisterFromPendingMap() {
Register symb = createRegister(0);
Register scratch = createRegister(1);
Instruction begin = createInstruction();
scratchMap.beginSymbolicInterval(symb, scratch, begin);
Instruction end = createInstruction();
scratchMap.endSymbolicInterval(symb, end);
scratchMap.endSymbolicInterval(symb, end);
}
private Register createRegister(int regNum) {
return new Register(regNum);
}
@Test
public void beginSymbolicIntervalAllowsRegisterAndItsScratchRegisterToBeTheSame() {
Register symb = createRegister(0);
Instruction inst = createInstruction();
scratchMap.beginSymbolicInterval(symb, symb, inst);
}
@Test(expected = NullPointerException.class)
public void endSymbolicIntervalForNotStartedIntervalCausesNPE() {
Register symb = createRegister(0);
Instruction inst = createInstruction();
scratchMap.endSymbolicInterval(symb, inst);
}
private Instruction createInstruction() {
Instruction fence = Empty.create(FENCE);
return fence;
}
@Test
public void beginScratchIntervalCreatesANewInterval() {
Register scratch = createRegister(0);
Instruction inst = createInstruction();
scratchMap.beginScratchInterval(scratch, inst);
assertThat(scratchMap.isEmpty(), is(false));
}
@Test
public void beginScratchIntervalSavesInformationAboutScratchRegister() {
Register scratch = createRegister(0);
Instruction begin = createInstruction();
int instructionCount = 10;
regAllocState.initializeDepthFirstNumbering(instructionCount);
int instNumber = 2;
regAllocState.setDFN(begin, instNumber);
scratchMap.beginScratchInterval(scratch, begin);
Instruction end = createInstruction();
regAllocState.setDFN(end, instNumber + 1);
scratchMap.endScratchInterval(scratch, end);
Register scratchReg = scratchMap.getScratch(scratch, instNumber);
assertThat(scratchReg, is(scratch));
assertThat(scratchMap.isScratch(scratchReg, instNumber), is(true));
}
@Test(expected = NullPointerException.class)
public void endScratchIntervalRemovesInformationAboutScratchRegisterFromPendingMap() {
Register scratch = createRegister(0);
Instruction begin = createInstruction();
scratchMap.beginScratchInterval(scratch, begin);
Instruction end = createInstruction();
scratchMap.endScratchInterval(scratch, end);
scratchMap.endScratchInterval(scratch, end);
}
@Test(expected = NullPointerException.class)
public void endScratchIntervalForNotStartedIntervalCausesNPE() {
Register scratch = createRegister(0);
Instruction inst = createInstruction();
scratchMap.endScratchInterval(scratch, inst);
}
}