001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.regalloc.ia32;
014
015import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.DUMMY_DEF;
016import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.DUMMY_USE;
017import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL;
018
019import java.util.Enumeration;
020
021import org.jikesrvm.VM;
022import org.jikesrvm.compilers.opt.OptOptions;
023import org.jikesrvm.compilers.opt.driver.CompilerPhase;
024import org.jikesrvm.compilers.opt.ir.BasicBlock;
025import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock;
026import org.jikesrvm.compilers.opt.ir.IR;
027import org.jikesrvm.compilers.opt.ir.IRTools;
028import org.jikesrvm.compilers.opt.ir.Instruction;
029import org.jikesrvm.compilers.opt.ir.Register;
030import org.jikesrvm.compilers.opt.ir.ia32.MIR_Nullary;
031import org.jikesrvm.compilers.opt.ir.ia32.MIR_UnaryNoRes;
032import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterSet;
033
034/**
035 * At the beginning of each basic block, the register allocator expects
036 * all floating-point stack locations to be available, and named
037 * FPi, 0 < i < 7
038 *
039 * <p>However, BURS may consume FP stack locations by inserting instructions
040 * that push or pop the floating-point stack.  This phase inserts dummy
041 * definitions and uses to indicate when symbolic FP registers are not
042 * available for register allocation since BURS has consumed a stack slot.
043 *
044 * For example,
045 * <pre>
046 *    FLD t1
047 *    ...
048 *    FSTP M, t1
049 * </pre>
050 *
051 * will be modified by this phase to indicate that FP6 is not available
052 * for allocation in the interval:
053 *
054 * <pre>
055 *   DUMMY_DEF FP6
056 *   FLD t1
057 *   .....
058 *   FSTP M, t1
059 *   DUMMY_USE FP6
060 * </pre>
061 *
062 * <p> Additionally, by convention, we will always clear the
063 * floating-point stack when delivering an exception.  To model this, we
064 * insert dummy defs and uses for each floating-point register at the
065 * beginning of each catch block.
066 */
067
068public final class ExpandFPRStackConvention extends CompilerPhase {
069
070  /**
071   * The number of FPRs available for allocation.
072   * Normally 7: we reserve one for final MIR expansion.
073   */
074  private static final int NUM_ALLOCATABLE_FPR = 7;
075
076  /**
077   * Return this instance of this phase. This phase contains no
078   * per-compilation instance fields.
079   * @param ir not used
080   * @return this
081   */
082  @Override
083  public CompilerPhase newExecution(IR ir) {
084    return this;
085  }
086
087  @Override
088  public boolean printingEnabled(OptOptions options, boolean before) {
089    return options.PRINT_CALLING_CONVENTIONS && !before;
090  }
091
092  @Override
093  public String getName() {
094    return "Expand Calling Convention";
095  }
096
097  /**
098   * Insert the needed dummy defs and uses.
099   */
100  @Override
101  public void perform(IR ir) {
102    if (SSE2_FULL) {
103      return;
104    }
105    PhysicalRegisterSet phys = (PhysicalRegisterSet)ir.regpool.getPhysicalRegisterSet();
106
107    for (Enumeration<BasicBlock> b = ir.getBasicBlocks(); b.hasMoreElements();) {
108      BasicBlock bb = b.nextElement();
109
110      if (bb instanceof ExceptionHandlerBasicBlock) {
111        // clear all floating-point state at the entry to a catch block
112        for (int i = 0; i < NUM_ALLOCATABLE_FPR; i++) {
113          Register fpr = phys.getFPR(i);
114          bb.prependInstruction(MIR_UnaryNoRes.create(DUMMY_USE, IRTools.D(fpr)));
115          bb.prependInstruction(MIR_Nullary.create(DUMMY_DEF, IRTools.D(fpr)));
116        }
117      }
118
119      // The following holds the floating point stack offset from its
120      // 'normal' position.
121      int fpStackOffset = 0;
122
123      for (Enumeration<Instruction> inst = bb.forwardInstrEnumerator(); inst.hasMoreElements();) {
124        Instruction s = inst.nextElement();
125        if (s.operator().isFpPop()) {
126          // A pop instruction 'ends' a dummy live range.
127          Register fpr = phys.getFPR(NUM_ALLOCATABLE_FPR - fpStackOffset);
128          s.insertAfter(MIR_UnaryNoRes.create(DUMMY_USE, IRTools.D(fpr)));
129          fpStackOffset--;
130        } else if (s.operator().isFpPush()) {
131          fpStackOffset++;
132          Register fpr = phys.getFPR(NUM_ALLOCATABLE_FPR - fpStackOffset);
133          s.insertBefore(MIR_Nullary.create(DUMMY_DEF, IRTools.D(fpr)));
134        }
135        if (VM.VerifyAssertions) VM._assert(fpStackOffset >= 0);
136        if (VM.VerifyAssertions) {
137          VM._assert(fpStackOffset < NUM_ALLOCATABLE_FPR);
138        }
139      }
140    }
141  }
142}