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;
014
015import java.util.Enumeration;
016import java.util.HashMap;
017import java.util.Map;
018
019import org.jikesrvm.compilers.opt.ir.BasicBlock;
020import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet;
021import org.jikesrvm.compilers.opt.ir.IR;
022import org.jikesrvm.compilers.opt.ir.Instruction;
023import org.jikesrvm.compilers.opt.ir.Register;
024
025/**
026 * The register allocator currently caches a bunch of state in the IR;
027 * This class provides accessors to this state.
028 * <ul>
029 *   <li>TODO: Consider caching the state in a lookaside structure.
030 *   <li>TODO: Currently, the physical registers are STATIC! fix this.
031 * </ul>
032 */
033public class RegisterAllocatorState {
034
035  private final int[] spills;
036
037  private final CompoundInterval[] intervals;
038
039  private Map<Instruction, Integer> depthFirstNumbers;
040
041  RegisterAllocatorState(int registerCount) {
042    spills = new int[registerCount];
043    intervals = new CompoundInterval[registerCount];
044  }
045
046  /**
047   * Resets the physical register info.
048   *
049   * @param ir the IR whose info is to be reset
050   */
051  void resetPhysicalRegisters(IR ir) {
052    GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
053    for (Enumeration<Register> e = phys.enumerateAll(); e.hasMoreElements();) {
054      Register reg = e.nextElement();
055      reg.deallocateRegister();
056      reg.mapsToRegister = null;  // mapping from real to symbolic
057      reg.defList = null;
058      reg.useList = null;
059      setSpill(reg, 0);
060    }
061  }
062
063  void setSpill(Register reg, int spill) {
064    reg.spillRegister();
065    spills[reg.number] = spill;
066  }
067
068  public int getSpill(Register reg) {
069    return spills[reg.number];
070  }
071
072  /**
073   * Records that register A and register B are associated with each other
074   * in a bijection.<p>
075   *
076   * The register allocator uses this state to indicate that a symbolic
077   * register is presently allocated to a physical register.
078   *
079   * @param A first register
080   * @param B second register
081   */
082  void mapOneToOne(Register A, Register B) {
083    Register aFriend = getMapping(A);
084    Register bFriend = getMapping(B);
085    if (aFriend != null) {
086      aFriend.mapsToRegister = null;
087    }
088    if (bFriend != null) {
089      bFriend.mapsToRegister = null;
090    }
091    A.mapsToRegister = B;
092    B.mapsToRegister = A;
093  }
094
095  /**
096   * @param r a register
097   * @return the register currently mapped 1-to-1 to r
098   */
099  Register getMapping(Register r) {
100    return r.mapsToRegister;
101  }
102
103  /**
104   * Clears any 1-to-1 mapping for a register.
105   *
106   * @param r the register whose mapping is to be cleared
107   */
108  void clearOneToOne(Register r) {
109    if (r != null) {
110      Register s = getMapping(r);
111      if (s != null) {
112        s.mapsToRegister = null;
113      }
114      r.mapsToRegister = null;
115    }
116  }
117
118  /**
119   *  Returns the interval associated with the passed register.
120   *  @param reg the register
121   *  @return the live interval or {@code null}
122   */
123  CompoundInterval getInterval(Register reg) {
124    return intervals[reg.number];
125  }
126
127  /**
128   * Initializes data structures for depth first numbering.
129   * @param instructionCount an estimate of the total number of instructions.
130   */
131  void initializeDepthFirstNumbering(int instructionCount) {
132    int noRehashCapacity = (int) (instructionCount * 1.5f);
133    depthFirstNumbers = new HashMap<Instruction, Integer>(noRehashCapacity);
134  }
135
136  /**
137   *  Associates the passed live interval with the passed register.
138   *
139   *  @param reg the register
140   *  @param interval the live interval
141   */
142  void setInterval(Register reg, CompoundInterval interval) {
143    intervals[reg.number] = interval;
144  }
145
146  /**
147   *  Associates the passed dfn number with the instruction
148   *  @param inst the instruction
149   *  @param dfn the dfn number
150   */
151  void setDFN(Instruction inst, int dfn) {
152    depthFirstNumbers.put(inst, Integer.valueOf(dfn));
153  }
154
155  /**
156   *  returns the dfn associated with the passed instruction
157   *  @param inst the instruction
158   *  @return the associated dfn
159   */
160  public int getDFN(Instruction inst) {
161    return depthFirstNumbers.get(inst);
162  }
163
164  /**
165   *  Prints the DFN numbers associated with each instruction.
166   *
167   *  @param ir the IR that contains the instructions
168   */
169  void printDfns(IR ir) {
170    System.out.println("DFNS: **** " + ir.getMethod() + "****");
171    for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst =
172        inst.nextInstructionInCodeOrder()) {
173      System.out.println(getDFN(inst) + " " + inst);
174    }
175  }
176
177  /**
178   * @param live the live interval
179   * @param bb the basic block for the live interval
180   * @return the Depth-first-number of the beginning of the live interval. If the
181   * interval is open-ended, the dfn for the beginning of the basic block will
182   * be returned instead.
183   */
184  int getDfnBegin(LiveIntervalElement live, BasicBlock bb) {
185    Instruction begin = live.getBegin();
186    int dfnBegin;
187    if (begin != null) {
188      dfnBegin = getDFN(begin);
189    } else {
190      dfnBegin = getDFN(bb.firstInstruction());
191    }
192    return dfnBegin;
193  }
194
195  /**
196   * @param live the live interval
197   * @param bb the basic block for the live interval
198   * @return the Depth-first-number of the end of the live interval. If the
199   * interval is open-ended, the dfn for the end of the basic block will
200   * be returned instead.
201   */
202  int getDfnEnd(LiveIntervalElement live, BasicBlock bb) {
203    Instruction end = live.getEnd();
204    int dfnEnd;
205    if (end != null) {
206      dfnEnd = getDFN(end);
207    } else {
208      dfnEnd = getDFN(bb.lastInstruction());
209    }
210    return dfnEnd;
211  }
212
213}