/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * 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/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.regalloc; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.ir.BasicBlock; import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet; import org.jikesrvm.compilers.opt.ir.IR; import org.jikesrvm.compilers.opt.ir.Instruction; import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR; import org.jikesrvm.compilers.opt.ir.Register; import org.jikesrvm.compilers.opt.liveness.LiveInterval; import org.jikesrvm.compilers.opt.util.BitSet; /** * An instance of this class provides a mapping from symbolic register to * a set of restricted registers. * <p> * Each architecture will subclass this in a class * RegisterRestrictions. */ public abstract class GenericRegisterRestrictions { // for each symbolic register, the set of physical registers that are // illegal for assignment private final HashMap<Register, RestrictedRegisterSet> hash = new HashMap<Register, RestrictedRegisterSet>(); // a set of symbolic registers that must not be spilled. private final HashSet<Register> noSpill = new HashSet<Register>(); protected final GenericPhysicalRegisterSet phys; protected RegisterAllocatorState regAllocState; protected GenericRegisterRestrictions(GenericPhysicalRegisterSet phys) { this.phys = phys; } protected final void noteMustNotSpill(Register r) { noSpill.add(r); } public final boolean mustNotSpill(Register r) { return noSpill.contains(r); } /** * Records all the register restrictions dictated by an IR. * * PRECONDITION: the instructions in each basic block are numbered in * increasing order before calling this. * * @param ir the IR to process */ public final void init(IR ir) { LiveInterval livenessInformation = ir.getLivenessInformation(); this.regAllocState = ir.MIRInfo.regAllocState; // process each basic block for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) { BasicBlock b = e.nextElement(); processBlock(b, livenessInformation); } } /** * Records all the register restrictions dictated by live ranges on a * particular basic block.<p> * * PRECONDITION: the instructions in each basic block are numbered in * increasing order before calling this. * * @param bb the bb to process * @param liveness liveness information for the IR */ private void processBlock(BasicBlock bb, LiveInterval liveness) { ArrayList<LiveIntervalElement> symbolic = new ArrayList<LiveIntervalElement>(20); ArrayList<LiveIntervalElement> physical = new ArrayList<LiveIntervalElement>(20); // 1. walk through the live intervals and identify which correspond to // physical and symbolic registers for (Enumeration<LiveIntervalElement> e = liveness.enumerateLiveIntervals(bb); e.hasMoreElements();) { LiveIntervalElement li = e.nextElement(); Register r = li.getRegister(); if (r.isPhysical()) { if (r.isVolatile() || r.isNonVolatile()) { physical.add(li); } } else { symbolic.add(li); } } // 2. walk through the live intervals for physical registers. For // each such interval, record the conflicts where the live range // overlaps a live range for a symbolic register. for (LiveIntervalElement phys : physical) { for (LiveIntervalElement symb : symbolic) { if (overlaps(phys, symb)) { addRestriction(symb.getRegister(), phys.getRegister()); } } } // 3. Volatile registers used by CALL instructions do not appear in // the liveness information. Handle CALL instructions as a special // case. for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) { Instruction s = ie.nextElement(); if (s.operator().isCall() && !s.operator().isCallSaveVolatile()) { for (LiveIntervalElement symb : symbolic) { if (contains(symb, regAllocState.getDFN(s))) { forbidAllVolatiles(symb.getRegister()); } } } // Before OSR points, we need to save all FPRs, // On OptExecStateExtractor, all GPRs have to be recovered, // but not FPRS. // if (s.operator() == YIELDPOINT_OSR) { for (LiveIntervalElement symb : symbolic) { if (symb.getRegister().isFloatingPoint()) { if (contains(symb, regAllocState.getDFN(s))) { forbidAllVolatiles(symb.getRegister()); } } } } } // 3. architecture-specific restrictions addArchRestrictions(bb, symbolic); } /** * 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(BasicBlock bb, ArrayList<LiveIntervalElement> symbolics) {} /** * Does a live range R contain an instruction with number n?<p> * * PRECONDITION: the instructions in each basic block are numbered in * increasing order before calling this. * * @param R the live range * @param n the instruction number * * @return {@code true} if and only if the live range contains an instruction * with the given number */ protected final boolean contains(LiveIntervalElement R, int n) { int begin = -1; int end = Integer.MAX_VALUE; if (R.getBegin() != null) { begin = regAllocState.getDFN(R.getBegin()); } if (R.getEnd() != null) { end = regAllocState.getDFN(R.getEnd()); } return ((begin <= n) && (n <= end)); } /** * Do two live ranges overlap?<p> * * PRECONDITION: the instructions in each basic block are numbered in * increasing order before calling this. * * @param li1 first live range * @param li2 second live range * @return {@code true} if and only if the live ranges overlap */ private boolean overlaps(LiveIntervalElement li1, LiveIntervalElement li2) { // Under the following conditions: the live ranges do NOT overlap: // 1. begin2 >= end1 > -1 // 2. begin1 >= end2 > -1 // Under all other cases, the ranges overlap int begin1 = -1; int end1 = -1; int begin2 = -1; int end2 = -1; if (li1.getBegin() != null) { begin1 = regAllocState.getDFN(li1.getBegin()); } if (li2.getEnd() != null) { end2 = regAllocState.getDFN(li2.getEnd()); } if (end2 <= begin1 && end2 > -1) return false; if (li1.getEnd() != null) { end1 = regAllocState.getDFN(li1.getEnd()); } if (li2.getBegin() != null) { begin2 = regAllocState.getDFN(li2.getBegin()); } return end1 > begin2 || end1 <= -1; } /** * Records that it is illegal to assign a symbolic register symb to any * volatile physical registerss. * * @param symb the register that must not be assigned to a volatile * physical register */ final void forbidAllVolatiles(Register symb) { RestrictedRegisterSet r = hash.get(symb); if (r == null) { r = new RestrictedRegisterSet(phys); hash.put(symb, r); } r.setNoVolatiles(); } /** * Records that it is illegal to assign a symbolic register symb to any * of a set of physical registers. * * @param symb the symbolic register to be restricted * @param set the physical registers that the symbolic register * must not be assigned to */ protected final void addRestrictions(Register symb, BitSet set) { RestrictedRegisterSet r = hash.get(symb); if (r == null) { r = new RestrictedRegisterSet(phys); hash.put(symb, r); } r.addAll(set); } /** * Record thats it is illegal to assign a symbolic register symb to a * physical register p. * * @param symb the symbolic register to be restricted * @param p the physical register that the symbolic register * must not be assigned to */ protected final void addRestriction(Register symb, Register p) { RestrictedRegisterSet r = hash.get(symb); if (r == null) { r = new RestrictedRegisterSet(phys); hash.put(symb, r); } r.add(p); } /** * @param symb the register whose restrictions where interested in * @return the set of restricted physical register for a given symbolic * register, {@code null} if no restrictions. */ final RestrictedRegisterSet getRestrictions(Register symb) { return hash.get(symb); } /** * Is it forbidden to assign symbolic register symb to any volatile * register? * @param symb symbolic register to check * @return {@code true}: yes, all volatiles are forbidden. * {@code false} :maybe, maybe not */ public final boolean allVolatilesForbidden(Register symb) { if (VM.VerifyAssertions) { VM._assert(symb != null); } RestrictedRegisterSet s = getRestrictions(symb); if (s == null) return false; return s.getNoVolatiles(); } /** * Is it forbidden to assign symbolic register symb to physical register * phys? * * @param symb a symbolic register * @param phys a physical register * @return {@code true} if it's forbidden, false otherwise */ public final boolean isForbidden(Register symb, Register phys) { if (VM.VerifyAssertions) { VM._assert(symb != null); VM._assert(phys != null); } RestrictedRegisterSet s = getRestrictions(symb); if (s == null) return false; return s.contains(phys); } /** * Is it forbidden to assign symbolic register symb to physical register r * in instruction s? * * @param symb a symbolic register * @param r a physical register * @param s the instruction that's the scope for the check * @return {@code true} if it's forbidden, false otherwise */ public abstract boolean isForbidden(Register symb, Register r, Instruction s); /** * An instance of this class represents restrictions on physical register * assignment. */ private static final class RestrictedRegisterSet { /** * The set of registers to which assignment is forbidden. */ private final BitSet bitset; /** * additionally, are all volatile registers forbidden? */ private boolean noVolatiles = false; boolean getNoVolatiles() { return noVolatiles; } void setNoVolatiles() { noVolatiles = true; } RestrictedRegisterSet(GenericPhysicalRegisterSet phys) { bitset = new BitSet(phys); } void add(Register r) { bitset.add(r); } void addAll(BitSet set) { bitset.addAll(set); } boolean contains(Register r) { if (r.isVolatile() && noVolatiles) { return true; } else { return bitset.contains(r); } } } }