/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* 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/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.ir;
import java.util.HashMap;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.VM_TypeReference;
public abstract class OPT_AbstractRegisterPool {
/* inlined behavior of DoublyLinkedList */
private OPT_Register start, end;
/**
* Return the first symbolic register in this pool.
*/
public OPT_Register getFirstSymbolicRegister() {
return start;
}
private void registerListappend(OPT_Register reg) {
if (start == null) {
start = end = reg;
} else {
end.append(reg);
end = reg;
}
}
private void registerListremove(OPT_Register e) {
if (e == start) {
if (e == end) {
start = end = null;
} else {
OPT_Register next = e.next;
start = next;
next.prev = null;
}
} else if (e == end) {
OPT_Register prev = e.prev;
end = prev;
prev.next = null;
} else {
e.remove();
}
}
/* end of inlined behavior */
/**
* All registers are assigned unique numbers; currentNum is the counter
* containing the next available register number.
*/
protected int currentNum;
private OPT_Register makeNewReg() {
OPT_Register reg = new OPT_Register(currentNum);
currentNum++;
registerListappend(reg);
return reg;
}
/**
* Release a now unused register.
* NOTE: It is the CALLERS responsibility to ensure that the register is no
* longer used!!!!
* @param r the register to release
*/
public void release(OPT_RegisterOperand r) {
OPT_Register reg = r.getRegister();
if (reg.number == currentNum - 1) {
currentNum--;
registerListremove(end);
}
}
/**
* Remove register from register pool.
*/
public void removeRegister(OPT_Register reg) {
registerListremove(reg);
}
/**
* Gets a new address register.
*
* @return the newly created register object
*/
public OPT_Register getAddress() {
OPT_Register reg = makeNewReg();
reg.setAddress();
return reg;
}
/**
* Gets a new integer register.
*
* @return the newly created register object
*/
public OPT_Register getInteger() {
OPT_Register reg = makeNewReg();
reg.setInteger();
return reg;
}
/**
* Gets a new float register.
*
* @return the newly created register object
*/
public OPT_Register getFloat() {
OPT_Register reg = makeNewReg();
reg.setFloat();
return reg;
}
/**
* Gets a new double register.
*
* @return the newly created register object
*/
public OPT_Register getDouble() {
OPT_Register reg;
reg = makeNewReg();
reg.setDouble();
return reg;
}
/**
* Gets a new condition register.
*
* @return the newly created register object
*/
public OPT_Register getCondition() {
OPT_Register reg = makeNewReg();
reg.setCondition();
return reg;
}
/**
* Gets a new long register.
*
* @return the newly created register object
*/
public OPT_Register getLong() {
OPT_Register reg;
reg = makeNewReg();
reg.setLong();
return reg;
}
/**
* Gets a new validation register.
*
* @return the newly created register object
*/
public OPT_Register getValidation() {
OPT_Register reg = makeNewReg();
reg.setValidation();
return reg;
}
/**
* Get a new register of the same type as the argument register
*
* @param template the register to get the type from
* @return the newly created register object
*/
public OPT_Register getReg(OPT_Register template) {
switch (template.getType()) {
case OPT_Register.ADDRESS_TYPE:
return getAddress();
case OPT_Register.INTEGER_TYPE:
return getInteger();
case OPT_Register.FLOAT_TYPE:
return getFloat();
case OPT_Register.DOUBLE_TYPE:
return getDouble();
case OPT_Register.CONDITION_TYPE:
return getCondition();
case OPT_Register.LONG_TYPE:
return getLong();
case OPT_Register.VALIDATION_TYPE:
return getValidation();
}
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
return null;
}
/**
* Get a new register of the same type as the argument RegisterOperand
*
* @param template the register operand to get the type from
* @return the newly created register object
*/
public OPT_Register getReg(OPT_RegisterOperand template) {
return getReg(template.getRegister());
}
/**
* Get a new register of the appropriate type to hold values of 'type'
*
* @param type the type of values that the register will hold
* @return the newly created register object
*/
public OPT_Register getReg(VM_TypeReference type) {
if (type.isLongType()) {
return getLong();
} else if (type.isDoubleType()) {
return getDouble();
} else if (type.isFloatType()) {
return getFloat();
} else if (type == VM_TypeReference.VALIDATION_TYPE) {
return getValidation();
} else if (type.isWordType() || type.isReferenceType()) {
return getAddress();
} else {
return getInteger();
}
}
private final HashMap<OPT_Register, OPT_Register> _regPairs = new HashMap<OPT_Register, OPT_Register>();
/**
* MIR: Get the other half of the register pair that is
* associated with the argument register.
* Note: this isn't incredibly general, but all architectures we're currently
* targeting need at most 2 machine registers to hold Java data values, so
* for now don't bother implementing a general mechanism.
*
* @param reg a register that may already be part of a register pair
* @return the register that is the other half of the register pair,
* if the pairing doesn't already exist then it is created.
*/
public OPT_Register getSecondReg(OPT_Register reg) {
OPT_Register otherHalf = _regPairs.get(reg);
if (otherHalf == null) {
otherHalf = getReg(reg);
_regPairs.put(reg, otherHalf);
if (reg.isLocal()) otherHalf.setLocal();
if (reg.isSSA()) otherHalf.setSSA();
}
return otherHalf;
}
/**
* Make a temporary register operand to hold values of the specified type
* (a new register is allocated).
*
* @param type the type of values to be held in the temp register
* @return the new temp
*/
public OPT_RegisterOperand makeTemp(VM_TypeReference type) {
return new OPT_RegisterOperand(getReg(type), type);
}
/**
* Make a temporary register operand that is similar to the argument.
*
* @param template the register operand to use as a template.
* @return the new temp
*/
public OPT_RegisterOperand makeTemp(OPT_RegisterOperand template) {
OPT_RegisterOperand temp = new OPT_RegisterOperand(getReg(template), template.getType());
temp.addFlags(template.getFlags());
return temp;
}
/**
* Make a temporary register operand that can hold the values
* implied by the passed operand.
*
* @param op the operand to use as a template.
* @return the new temp
*/
public OPT_RegisterOperand makeTemp(OPT_Operand op) {
OPT_RegisterOperand result;
if (op.isRegister()) {
result = makeTemp((OPT_RegisterOperand) op);
} else {
result = makeTemp(op.getType());
}
return result;
}
/**
* Make a temporary to hold an address (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempAddress() {
return new OPT_RegisterOperand(getAddress(), VM_TypeReference.Address);
}
/**
* Make a temporary to hold an address (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempOffset() {
return new OPT_RegisterOperand(getAddress(), VM_TypeReference.Offset);
}
/**
* Make a temporary to hold an int (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempInt() {
return new OPT_RegisterOperand(getInteger(), VM_TypeReference.Int);
}
/**
* Make a temporary to hold a boolean (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempBoolean() {
return new OPT_RegisterOperand(getInteger(), VM_TypeReference.Boolean);
}
/**
* Make a temporary to hold a float (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempFloat() {
return new OPT_RegisterOperand(getFloat(), VM_TypeReference.Float);
}
/**
* Make a temporary to hold a double (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempDouble() {
return new OPT_RegisterOperand(getDouble(), VM_TypeReference.Double);
}
/**
* Make a temporary to hold a long (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempLong() {
return new OPT_RegisterOperand(getLong(), VM_TypeReference.Long);
}
/**
* Make a temporary to hold a condition code (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempCondition() {
OPT_Register reg = getCondition();
return new OPT_RegisterOperand(reg, VM_TypeReference.Int);
}
/**
* Make a temporary to hold a guard (validation) (allocating a new register).
*
* @return the newly created temporary
*/
public OPT_RegisterOperand makeTempValidation() {
OPT_Register reg = getValidation();
reg.setValidation();
return new OPT_RegisterOperand(reg, VM_TypeReference.VALIDATION_TYPE);
}
}