/*
* 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 org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.OPT_CompilerPhase;
import org.jikesrvm.compilers.opt.OPT_Options;
import org.jikesrvm.compilers.opt.ir.MIR_Nullary;
import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_ExceptionHandlerBasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_IRTools;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_InstructionEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_Operators;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.ia32.OPT_PhysicalRegisterSet;
import org.jikesrvm.ia32.VM_ArchConstants;
/**
* At the beginning of each basic block, the register allocator expects
* all floating-point stack locations to be available, and named
* FPi, 0 < i < 7
*
* <p>However, BURS may consume FP stack locations by inserting instructions
* that push or pop the floating-point stack. This phase inserts dummy
* definitions and uses to indicate when symbolic FP registers are not
* available for register allocation since BURS has consumed a stack slot.
*
* For example,
* <pre>
* FLD t1
* ...
* FSTP M, t1
* </pre>
*
* will be modified by this phase to indicate that FP6 is not available
* for allocation in the interval:
*
* <pre>
* DUMMY_DEF FP6
* FLD t1
* .....
* FSTP M, t1
* DUMMY_USE FP6
* </pre>
*
* <p> Additionally, by convention, we will always clear the
* floating-point stack when delivering an exception. To model this, we
* insert dummy defs and uses for each floating-point register at the
* beginning of each catch block.
*/
final class OPT_ExpandFPRStackConvention extends OPT_CompilerPhase implements OPT_Operators {
/**
* The number of FPRs available for allocation.
* Normally 7: we reserve one for final MIR expansion.
*/
private static final int NUM_ALLOCATABLE_FPR = 7;
/**
* Return this instance of this phase. This phase contains no
* per-compilation instance fields.
* @param ir not used
* @return this
*/
public OPT_CompilerPhase newExecution(OPT_IR ir) {
return this;
}
public boolean printingEnabled(OPT_Options options, boolean before) {
return options.PRINT_CALLING_CONVENTIONS && !before;
}
public String getName() {
return "Expand Calling Convention";
}
/**
* Insert the needed dummy defs and uses.
*/
public void perform(OPT_IR ir) {
if (VM_ArchConstants.SSE2_FULL) {
return;
}
OPT_PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
for (OPT_BasicBlockEnumeration b = ir.getBasicBlocks(); b.hasMoreElements();) {
OPT_BasicBlock bb = b.nextElement();
if (bb instanceof OPT_ExceptionHandlerBasicBlock) {
// clear all floating-point state at the entry to a catch block
for (int i = 0; i < NUM_ALLOCATABLE_FPR; i++) {
OPT_Register fpr = phys.getFPR(i);
bb.prependInstruction(MIR_UnaryNoRes.create(DUMMY_USE, OPT_IRTools.D(fpr)));
bb.prependInstruction(MIR_Nullary.create(DUMMY_DEF, OPT_IRTools.D(fpr)));
}
}
// 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.nextElement();
if (s.operator().isFpPop()) {
// A pop instruction 'ends' a dummy live range.
OPT_Register fpr = phys.getFPR(NUM_ALLOCATABLE_FPR - fpStackOffset);
s.insertAfter(MIR_UnaryNoRes.create(DUMMY_USE, OPT_IRTools.D(fpr)));
fpStackOffset--;
} else if (s.operator().isFpPush()) {
fpStackOffset++;
OPT_Register fpr = phys.getFPR(NUM_ALLOCATABLE_FPR - fpStackOffset);
s.insertBefore(MIR_Nullary.create(DUMMY_DEF, OPT_IRTools.D(fpr)));
}
if (VM.VerifyAssertions) VM._assert(fpStackOffset >= 0);
if (VM.VerifyAssertions) {
VM._assert(fpStackOffset < NUM_ALLOCATABLE_FPR);
}
}
}
}
}