/*
* 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.jikesrvm.classloader.ClassLoaderConstants.LongTypeCode;
import static org.jikesrvm.compilers.opt.ir.IRDumpTools.dumpIR;
import static org.jikesrvm.osr.OSRConstants.ACONST;
import static org.jikesrvm.osr.OSRConstants.ICONST;
import static org.jikesrvm.osr.OSRConstants.LCONST;
import static org.jikesrvm.osr.OSRConstants.PHYREG;
import static org.jikesrvm.osr.OSRConstants.SPILL;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.OptOptions;
import org.jikesrvm.compilers.opt.OptimizingCompilerException;
import org.jikesrvm.compilers.opt.driver.CompilerPhase;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.osr.LocalRegPair;
import org.jikesrvm.osr.MethodVariables;
import org.jikesrvm.osr.VariableMapElement;
import org.vmmagic.unboxed.Word;
/**
* Update GC maps after register allocation but before inserting spill
* code.
*/
public final class UpdateOSRMaps extends CompilerPhase {
@Override
public boolean shouldPerform(OptOptions options) {
return true;
}
/**
* Return this instance of this phase. This phase contains no
* per-compilation instance fields.
* @param ir not used
* @return this
*/
@Override
public CompilerPhase newExecution(IR ir) {
return this;
}
@Override
public String getName() {
return "Update OSRMaps";
}
@Override
public boolean printingEnabled(OptOptions options, boolean before) {
return false;
}
/**
* Iterate over the IR-based OSR map, and update symbolic registers
* with real reg number or spill locations.
* Verify there are only two types of operands:
* ConstantOperand
* RegisterOperand
* for integer constant, we save the value of the integer
*
* The LONG register has another half part.
*
* CodeSpill replaces any allocated symbolic register by
* physical registers.
*/
@Override
public void perform(IR ir) throws OptimizingCompilerException {
// list of OsrVariableMapElement
//LinkedList<VariableMapElement> mapList = ir.MIRInfo.osrVarMap.list;
//for (int numOsrs=0, m=mapList.size(); numOsrs<m; numOsrs++) {
// VariableMapElement elm = mapList.get(numOsrs);
/* for each osr instruction */
for (VariableMapElement elm : ir.MIRInfo.osrVarMap.list) {
// for each inlined method
//LinkedList<MethodVariables> mvarsList = elm.mvars; XXX Remove once proven correct
//for (int numMvars=0, n=mvarsList.size(); numMvars<n; numMvars++) {
// MethodVariables mvar = mvarsList.get(numMvars);
for (MethodVariables mvar : elm.mvars) {
// for each tuple
//LinkedList<LocalRegPair> tupleList = mvar.tupleList;
//for (int numTuple=0, k=tupleList.size(); numTuple<k; numTuple++) {
//LocalRegPair tuple = tupleList.get(numTuple);
for (LocalRegPair tuple : mvar.tupleList) {
Operand op = tuple.operand;
if (op.isRegister()) {
Register sym_reg = ((RegisterOperand) op).getRegister();
setRealPosition(ir, tuple, sym_reg);
// get another half part of long register
if (VM.BuildFor32Addr && (tuple.typeCode == LongTypeCode)) {
LocalRegPair other = tuple._otherHalf;
Operand other_op = other.operand;
if (VM.VerifyAssertions) VM._assert(other_op.isRegister());
Register other_reg = ((RegisterOperand) other_op).getRegister();
setRealPosition(ir, other, other_reg);
}
/* According to ConvertToLowLevelIR, StringConstant, LongConstant,
* NullConstant, FloatConstant, and DoubleConstant are all materialized
* The only thing left is the integer constants which could encode
* non-moveable objects.
* POTENTIAL DRAWBACKS: since any long, float, and double are moved
* to register and treated as use, it may consume more registers and
* add unnecessary MOVEs.
*
* Perhaps, ConvertToLowLevelIR can skip OsrPoint instruction.
*/
} else if (op.isIntConstant()) {
setTupleValue(tuple, ICONST, ((IntConstantOperand) op).value);
if (VM.BuildFor32Addr && (tuple.typeCode == LongTypeCode)) {
LocalRegPair other = tuple._otherHalf;
Operand other_op = other.operand;
if (VM.VerifyAssertions) VM._assert(other_op.isIntConstant());
setTupleValue(other, ICONST, ((IntConstantOperand) other_op).value);
}
} else if (op.isAddressConstant()) {
setTupleValue(tuple, ACONST, ((AddressConstantOperand) op).value.toWord());
} else if (VM.BuildFor64Addr && op.isLongConstant()) {
setTupleValue(tuple, LCONST, Word.fromLong(((LongConstantOperand) op).value));
} else {
throw new OptimizingCompilerException("LinearScan", "Unexpected operand type at ", op.toString());
} // for the op type
} // for each tuple
} // for each inlined method
} // for each osr instruction
}
void setRealPosition(IR ir, LocalRegPair tuple, Register sym_reg) {
if (VM.VerifyAssertions) VM._assert(sym_reg != null);
int REG_MASK = 0x01F;
// now it is not symbolic register anymore.
// is is really confusing that sometimes a sym reg is a phy,
// and sometimes not.
if (sym_reg.isAllocated()) {
setTupleValue(tuple, PHYREG, sym_reg.number & REG_MASK);
} else if (sym_reg.isPhysical()) {
setTupleValue(tuple, PHYREG, sym_reg.number & REG_MASK);
} else if (sym_reg.isSpilled()) {
int spillLocation = ir.MIRInfo.regAllocState.getSpill(sym_reg);
setTupleValue(tuple, SPILL, spillLocation);
} else {
dumpIR(ir, "PANIC");
throw new RuntimeException("LinearScan PANIC in OSRMAP, " + sym_reg + " is not alive");
}
}
static void setTupleValue(LocalRegPair tuple, byte type, int value) {
tuple.valueType = type;
tuple.value = Word.fromIntSignExtend(value);
}
static void setTupleValue(LocalRegPair tuple, byte type, Word value) {
tuple.valueType = type;
tuple.value = value;
}
}