/*
* 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.ia32;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.VM_TypeReference;
import org.jikesrvm.compilers.opt.OPT_LiveIntervalElement;
import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException;
import org.jikesrvm.compilers.opt.ir.Empty;
import org.jikesrvm.compilers.opt.ir.MIR_CondBranch;
import org.jikesrvm.compilers.opt.ir.MIR_CondBranch2;
import org.jikesrvm.compilers.opt.ir.MIR_Move;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_InstructionEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_MachineSpecificIR;
import org.jikesrvm.compilers.opt.ir.OPT_Operand;
import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_Operator;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADVISE_ESP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DUMMY_DEF;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DUMMY_USE;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_CURRENT_PROCESSOR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_JTOC_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FCLEAR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FMOV;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FMOV_ENDING_LIVE_RANGE;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FNINIT;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_JCC;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2ADDR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ADD_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_AND_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_MOVE_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NEG_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_OR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHL_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SUB_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_USHR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_XOR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.NOP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PREFETCH_opcode;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand;
/**
* Wrappers around IA32-specific IR common to both 32 & 64 bit
*/
public abstract class OPT_MachineSpecificIRIA extends OPT_MachineSpecificIR {
/**
* Wrappers around IA32-specific IR (32-bit specific)
*/
public static final class IA32 extends OPT_MachineSpecificIRIA {
public static final IA32 singleton = new IA32();
/* common to all ISAs */
@Override
public boolean mayEscapeThread(OPT_Instruction instruction) {
switch (instruction.getOpcode()) {
case PREFETCH_opcode:
return false;
case GET_JTOC_opcode:
case GET_CURRENT_PROCESSOR_opcode:
return true;
default:
throw new OPT_OptimizingCompilerException("OPT_SimpleEscapge: Unexpected " + instruction);
}
}
@Override
public boolean mayEscapeMethod(OPT_Instruction instruction) {
return mayEscapeThread(instruction); // at this stage we're no more specific
}
}
/**
* Wrappers around EMT64-specific IR (64-bit specific)
*/
public static final class EM64T extends OPT_MachineSpecificIRIA {
public static final EM64T singleton = new EM64T();
/* common to all ISAs */
@Override
public boolean mayEscapeThread(OPT_Instruction instruction) {
switch (instruction.getOpcode()) {
case PREFETCH_opcode:
return false;
case GET_JTOC_opcode:
case GET_CURRENT_PROCESSOR_opcode:
case LONG_OR_opcode:
case LONG_AND_opcode:
case LONG_XOR_opcode:
case LONG_SUB_opcode:
case LONG_SHL_opcode:
case LONG_ADD_opcode:
case LONG_SHR_opcode:
case LONG_USHR_opcode:
case LONG_NEG_opcode:
case LONG_MOVE_opcode:
case LONG_2ADDR_opcode:
return true;
default:
throw new OPT_OptimizingCompilerException("OPT_SimpleEscapge: Unexpected " + instruction);
}
}
@Override
public boolean mayEscapeMethod(OPT_Instruction instruction) {
return mayEscapeThread(instruction); // at this stage we're no more specific
}
}
/*
* Generic (32/64 neutral) IA support
*/
/* common to all ISAs */
@Override
public boolean isConditionOperand(OPT_Operand operand) {
return operand instanceof OPT_IA32ConditionOperand;
}
@Override
public void mutateMIRCondBranch(OPT_Instruction cb) {
MIR_CondBranch.mutate(cb,
IA32_JCC,
MIR_CondBranch2.getCond1(cb),
MIR_CondBranch2.getTarget1(cb),
MIR_CondBranch2.getBranchProfile1(cb));
}
@Override
public boolean isHandledByRegisterUnknown(char opcode) {
return (opcode == PREFETCH_opcode);
}
/* unique to IA */
@Override
public boolean isAdviseESP(OPT_Operator operator) {
return operator == ADVISE_ESP;
}
@Override
public boolean isFClear(OPT_Operator operator) {
return operator == IA32_FCLEAR;
}
@Override
public boolean isFNInit(OPT_Operator operator) {
return operator == IA32_FNINIT;
}
@Override
public boolean isBURSManagedFPROperand(OPT_Operand operand) {
return operand instanceof OPT_BURSManagedFPROperand;
}
@Override
public int getBURSManagedFPRValue(OPT_Operand operand) {
return ((OPT_BURSManagedFPROperand) operand).regNum;
}
/**
* Mutate FMOVs that end live ranges
*
* @param live The live interval for a basic block/reg pair
* @param register The register for this live interval
* @param dfnbegin The (adjusted) begin for this interval
* @param dfnend The (adjusted) end for this interval
*/
@Override
public boolean mutateFMOVs(OPT_LiveIntervalElement live, OPT_Register register, int dfnbegin, int dfnend) {
OPT_Instruction end = live.getEnd();
if (end != null && end.operator == IA32_FMOV) {
if (dfnend == dfnbegin) {
// if end, an FMOV, both begins and ends the live range,
// then end is dead. Change it to a NOP and return null.
Empty.mutate(end, NOP);
return false;
} else {
if (!end.isPEI()) {
if (VM.VerifyAssertions) {
OPT_Operand value = MIR_Move.getValue(end);
VM._assert(value.isRegister());
VM._assert(MIR_Move.getValue(end).asRegister().getRegister() == register);
}
end.operator = IA32_FMOV_ENDING_LIVE_RANGE;
}
}
}
return true;
}
/**
* Rewrite floating point registers to reflect changes in stack
* height induced by BURS.
*
* Side effect: update the fpStackHeight in MIRInfo
*/
public void rewriteFPStack(OPT_IR ir) {
OPT_PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
for (OPT_BasicBlockEnumeration b = ir.getBasicBlocks(); b.hasMoreElements();) {
OPT_BasicBlock bb = b.nextElement();
// The following holds the floating point stack offset from its
// 'normal' position.
int fpStackOffset = 0;
for (OPT_InstructionEnumeration inst = bb.forwardInstrEnumerator(); inst.hasMoreElements();) {
OPT_Instruction s = inst.next();
for (OPT_OperandEnumeration ops = s.getOperands(); ops.hasMoreElements();) {
OPT_Operand op = ops.next();
if (op.isRegister()) {
OPT_RegisterOperand rop = op.asRegister();
OPT_Register r = rop.getRegister();
// Update MIR state for every phyiscal FPR we see
if (r.isPhysical() && r.isFloatingPoint() && s.operator() != DUMMY_DEF && s.operator() != DUMMY_USE) {
int n = OPT_PhysicalRegisterSet.getFPRIndex(r);
if (fpStackOffset != 0) {
n += fpStackOffset;
rop.setRegister(phys.getFPR(n));
}
ir.MIRInfo.fpStackHeight = Math.max(ir.MIRInfo.fpStackHeight, n + 1);
}
} else if (op instanceof OPT_BURSManagedFPROperand) {
int regNum = ((OPT_BURSManagedFPROperand) op).regNum;
s.replaceOperand(op, new OPT_RegisterOperand(phys.getFPR(regNum), VM_TypeReference.Double));
}
}
// account for any effect s has on the floating point stack
// position.
if (s.operator().isFpPop()) {
fpStackOffset--;
} else if (s.operator().isFpPush()) {
fpStackOffset++;
}
if (VM.VerifyAssertions) VM._assert(fpStackOffset >= 0);
}
}
}
}