/* * 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.ia32; import java.util.ArrayList; import java.util.Enumeration; import org.jikesrvm.ArchitectureSpecific.OPT_PhysicalRegisterSet; import org.jikesrvm.compilers.opt.OPT_GenericRegisterRestrictions; import org.jikesrvm.compilers.opt.OPT_LiveIntervalElement; import org.jikesrvm.compilers.opt.ir.MIR_BinaryAcc; import org.jikesrvm.compilers.opt.ir.MIR_CacheOp; import org.jikesrvm.compilers.opt.ir.MIR_Compare; import org.jikesrvm.compilers.opt.ir.MIR_CondMove; import org.jikesrvm.compilers.opt.ir.MIR_DoubleShift; import org.jikesrvm.compilers.opt.ir.MIR_LowTableSwitch; import org.jikesrvm.compilers.opt.ir.MIR_Set; import org.jikesrvm.compilers.opt.ir.MIR_Test; import org.jikesrvm.compilers.opt.ir.MIR_Unary; import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_InstructionEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_MemoryOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_Operators; import org.jikesrvm.compilers.opt.ir.OPT_Register; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; import org.jikesrvm.compilers.opt.ir.ia32.OPT_BURSManagedFPROperand; /** * An instance of this class encapsulates restrictions on register * assignment. */ public class OPT_RegisterRestrictions extends OPT_GenericRegisterRestrictions implements OPT_Operators, OPT_PhysicalRegisterConstants { /** * Allow scratch registers in PEIs? */ public static final boolean SCRATCH_IN_PEI = true; /** * Default Constructor */ protected OPT_RegisterRestrictions(OPT_PhysicalRegisterSet phys) { super(phys); } /** * Add architecture-specific register restrictions for a basic block. * Override as needed. * * @param bb the basic block * @param symbolics the live intervals for symbolic registers on this * block */ public void addArchRestrictions(OPT_BasicBlock bb, ArrayList<OPT_LiveIntervalElement> symbolics) { // If there are any registers used in catch blocks, we want to ensure // that these registers are not used or evicted from scratch registers // at a relevant PEI, so that the assumptions of register homes in the // catch block remain valid. For now, we do this by forcing any // register used in such a PEI as not spilled. TODO: relax this // restriction for better code. for (OPT_InstructionEnumeration ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) { OPT_Instruction s = ie.next(); if (s.isPEI() && s.operator != IR_PROLOGUE) { if (bb.hasApplicableExceptionalOut(s) || !SCRATCH_IN_PEI) { for (Enumeration<OPT_Operand> e = s.getOperands(); e.hasMoreElements();) { OPT_Operand op = e.nextElement(); if (op != null && op.isRegister()) { noteMustNotSpill(op.asRegister().getRegister()); handle8BitRestrictions(s); } } } } // handle special cases switch (s.getOpcode()) { case MIR_LOWTABLESWITCH_opcode: { OPT_RegisterOperand op = MIR_LowTableSwitch.getIndex(s); noteMustNotSpill(op.getRegister()); } break; case IA32_MOVZX__B_opcode: case IA32_MOVSX__B_opcode: { if (MIR_Unary.getVal(s).isRegister()) { OPT_RegisterOperand val = MIR_Unary.getVal(s).asRegister(); restrictTo8Bits(val.getRegister()); } } break; case IA32_SET__B_opcode: { if (MIR_Set.getResult(s).isRegister()) { OPT_RegisterOperand op = MIR_Set.getResult(s).asRegister(); restrictTo8Bits(op.getRegister()); } } break; default: handle8BitRestrictions(s); break; } } for (OPT_InstructionEnumeration ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) { OPT_Instruction s = ie.next(); if (s.operator == IA32_FNINIT) { // No floating point register survives across an FNINIT for (OPT_LiveIntervalElement symb : symbolics) { if (symb.getRegister().isFloatingPoint()) { if (contains(symb, s.scratch)) { addRestrictions(symb.getRegister(), phys.getFPRs()); } } } } else if (s.operator == IA32_FCLEAR) { // Only some FPRs survive across an FCLEAR for (OPT_LiveIntervalElement symb : symbolics) { if (symb.getRegister().isFloatingPoint()) { if (contains(symb, s.scratch)) { int nSave = MIR_UnaryNoRes.getVal(s).asIntConstant().value; for (int i = nSave; i < NUM_FPRS; i++) { addRestriction(symb.getRegister(), phys.getFPR(i)); } } } } } } } /** * Does instruction s contain an 8-bit memory operand? */ final boolean has8BitMemoryOperand(OPT_Instruction s) { for (OPT_OperandEnumeration me = s.getMemoryOperands(); me.hasMoreElements();) { OPT_MemoryOperand mop = (OPT_MemoryOperand) me.next(); if (mop.size == 1) { return true; } } return false; } /** * Ensure that if an operand has an 8 bit memory operand that * all of its register operands are in 8 bit registers. * @param s the instruction to restrict */ final void handle8BitRestrictions(OPT_Instruction s) { for (OPT_OperandEnumeration me = s.getMemoryOperands(); me.hasMoreElements();) { OPT_MemoryOperand mop = (OPT_MemoryOperand) me.next(); if (mop.size == 1) { for (OPT_OperandEnumeration e2 = s.getRootOperands(); e2.hasMoreElements();) { OPT_Operand rootOp = e2.next(); if (rootOp.isRegister()) { restrictTo8Bits(rootOp.asRegister().getRegister()); } } } } } /** * Ensure that a particular register is only assigned to AL, BL, CL, or * DL, since these are the only 8-bit registers we normally address. */ final void restrictTo8Bits(OPT_Register r) { OPT_Register ESP = phys.getESP(); OPT_Register EBP = phys.getEBP(); OPT_Register ESI = phys.getESI(); OPT_Register EDI = phys.getEDI(); addRestriction(r, ESP); addRestriction(r, EBP); addRestriction(r, ESI); addRestriction(r, EDI); } /** * Given symbolic register r that appears in instruction s, does the * architecture demand that r be assigned to a physical register in s? */ public static boolean mustBeInRegister(OPT_Register r, OPT_Instruction s) { switch (s.getOpcode()) { case IA32_PREFETCHNTA_opcode: { OPT_RegisterOperand op = MIR_CacheOp.getAddress(s).asRegister(); if (op.register == r) return true; } break; case IA32_CVTSD2SI_opcode: case IA32_CVTSD2SS_opcode: case IA32_CVTSI2SD_opcode: case IA32_CVTSS2SD_opcode: case IA32_CVTSS2SI_opcode: case IA32_CVTTSD2SI_opcode: case IA32_CVTTSS2SI_opcode: case IA32_CVTSI2SS_opcode: { OPT_RegisterOperand op = MIR_Unary.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case IA32_ADDSS_opcode: case IA32_DIVSS_opcode: case IA32_MULSS_opcode: case IA32_SUBSS_opcode: case IA32_XORPS_opcode: case IA32_ADDSD_opcode: case IA32_DIVSD_opcode: case IA32_MULSD_opcode: case IA32_SUBSD_opcode: case IA32_XORPD_opcode: { OPT_RegisterOperand op = MIR_BinaryAcc.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case IA32_UCOMISD_opcode: case IA32_UCOMISS_opcode: { OPT_RegisterOperand op = MIR_Compare.getVal1(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case IA32_SHRD_opcode: case IA32_SHLD_opcode: { OPT_RegisterOperand op = MIR_DoubleShift.getSource(s); if (op.asRegister().getRegister() == r) return true; } break; case IA32_FCOMI_opcode: case IA32_FCOMIP_opcode: { OPT_Operand op = MIR_Compare.getVal2(s); if (!(op instanceof OPT_BURSManagedFPROperand)) { if (op.asRegister().getRegister() == r) return true; } } break; case IA32_IMUL2_opcode: { OPT_RegisterOperand op = MIR_BinaryAcc.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case MIR_LOWTABLESWITCH_opcode: { OPT_RegisterOperand op = MIR_LowTableSwitch.getIndex(s); if (op.asRegister().getRegister() == r) return true; } break; case IA32_CMOV_opcode: case IA32_FCMOV_opcode: { OPT_RegisterOperand op = MIR_CondMove.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case IA32_MOVZX__B_opcode: case IA32_MOVSX__B_opcode: { OPT_RegisterOperand op = MIR_Unary.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case IA32_MOVZX__W_opcode: case IA32_MOVSX__W_opcode: { OPT_RegisterOperand op = MIR_Unary.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } break; case IA32_SET__B_opcode: { if (MIR_Set.getResult(s).isRegister()) { OPT_RegisterOperand op = MIR_Set.getResult(s).asRegister(); if (op.asRegister().getRegister() == r) return true; } } break; case IA32_TEST_opcode: { // at least 1 of the two operands must be in a register if (!MIR_Test.getVal2(s).isConstant()) { if (MIR_Test.getVal1(s).isRegister()) { if (MIR_Test.getVal1(s).asRegister().getRegister() == r) return true; } else if (MIR_Test.getVal2(s).isRegister()) { if (MIR_Test.getVal2(s).asRegister().getRegister() == r) return true; } } } break; case IA32_BT_opcode: { // val2 of bit test must be either a constant or register if (!MIR_Test.getVal2(s).isConstant()) { if (MIR_Test.getVal2(s).isRegister()) { if (MIR_Test.getVal2(s).asRegister().getRegister() == r) return true; } } } break; default: break; } return false; } /** * Can physical register r hold an 8-bit value? */ private boolean okFor8(OPT_Register r) { OPT_Register ESP = phys.getESP(); OPT_Register EBP = phys.getEBP(); OPT_Register ESI = phys.getESI(); OPT_Register EDI = phys.getEDI(); return (r != ESP && r != EBP && r != ESI && r != EDI); } /** * Is it forbidden to assign symbolic register symb to physical register r * in instruction s? */ public boolean isForbidden(OPT_Register symb, OPT_Register r, OPT_Instruction s) { // Look at 8-bit restrictions. switch (s.operator.opcode) { case IA32_MOVZX__B_opcode: case IA32_MOVSX__B_opcode: { if (MIR_Unary.getVal(s).isRegister()) { OPT_RegisterOperand val = MIR_Unary.getVal(s).asRegister(); if (val.getRegister() == symb) { return !okFor8(r); } } } break; case IA32_SET__B_opcode: { if (MIR_Set.getResult(s).isRegister()) { OPT_RegisterOperand op = MIR_Set.getResult(s).asRegister(); if (op.asRegister().getRegister() == symb) { return !okFor8(r); } } } break; } if (has8BitMemoryOperand(s)) { return !okFor8(r); } // Otherwise, it's OK. return false; } }