/*
* 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.ia32;
import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_PREFETCHNTA;
import static org.junit.Assert.*;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.OsrPoint;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_BinaryAcc;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_CacheOp;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Move;
import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.junit.runners.RequiresBuiltJikesRVM;
import org.jikesrvm.junit.runners.RequiresIA32;
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({RequiresBuiltJikesRVM.class, RequiresIA32.class, RequiresOptCompiler.class})
public class StackManagerTest {
private StackManager stackManager;
private int registerNumber;
@Before
public void setupStackManager() {
stackManager = new StackManager();
}
@Test
public void noScratchNeededForFMOV() {
RegisterOperand lhs = new RegisterOperand(createRegister(), TypeReference.Float);
RegisterOperand rhs = new RegisterOperand(createRegister(), TypeReference.Float);
Instruction fMov = MIR_Move.create(IA32_FMOV, lhs, rhs);
assertFalse(stackManager.needScratch(lhs.getRegister(), fMov));
assertFalse(stackManager.needScratch(rhs.getRegister(), fMov));
}
@Test
public void osrPointsNeverNeedScratchRegisters() {
Instruction osrPoint = OsrPoint.create(YIELDPOINT_OSR, null, 0);
assertFalse(stackManager.needScratch(createRegister(), osrPoint));
}
private Register createRegister() {
return new Register(registerNumber++);
}
@Test
public void instructionsWithMemoryOperandsAlwaysNeedScratch() {
RegisterOperand result = new RegisterOperand(createRegister(), TypeReference.Int);
MemoryOperand value = MemoryOperand.B(new RegisterOperand(createRegister(), TypeReference.Int), (byte) 4, null, null);
Instruction scratchFreeMove = MIR_Move.create(IA32_MOV, result, value);
assertTrue(stackManager.needScratch(result.getRegister(), scratchFreeMove));
}
@Test
public void instructionsMayNeedScratchDueToArchitectureRestrictions() {
RegisterOperand addr = new RegisterOperand(createRegister(), TypeReference.Address);
Instruction prefetch = MIR_CacheOp.create(IA32_PREFETCHNTA, addr);
assertTrue(stackManager.needScratch(addr.getRegister(), prefetch));
}
@Test
public void instructionsNeedAScratchIfOneRegisterAppearsMultipleTimes() {
Register reg = createRegister();
RegisterOperand result = new RegisterOperand(reg, TypeReference.Int);
RegisterOperand value = new RegisterOperand(reg, TypeReference.Int);
Instruction add = MIR_BinaryAcc.create(IA32_ADD, result, value);
assertTrue(stackManager.needScratch(reg, add));
}
@Test
public void normalInstructionsDoNotNeedScratch() {
RegisterOperand result = new RegisterOperand(createRegister(), TypeReference.Float);
RegisterOperand value = new RegisterOperand(createRegister(), TypeReference.Float);
Instruction floatingPointMove = MIR_Move.create(IA32_FLD, result, value);
assertFalse(stackManager.needScratch(result.getRegister(), floatingPointMove));
assertFalse(stackManager.needScratch(value.getRegister(), floatingPointMove));
}
}