/*
* 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.instrsched;
import org.jikesrvm.compilers.opt.ir.Instruction;
/**
* Resource usage map representation
* Used by the scheduler to accomodate resource patterns
*
* @see OperatorClass
* @see org.jikesrvm.compilers.opt.ir.Operator
*/
final class ResourceMap {
private static final int VERBOSE = 0;
private static void debug(String s) {
System.out.println(s);
}
private static String toBinaryPad32(int value) {
String s = Integer.toBinaryString(value);
return String.format("%032s", s);
}
/** GROWABLE Resource Usage map. */
private int[] rumap;
/** Current size of the RU map. */
private int size;
/** Grows the RU map to a given size. For internal use only. */
private void grow(int s) {
if (VERBOSE >= 2) {
debug("Growing from " + size + " to " + s);
}
if (size >= s) {
return;
}
int len = rumap.length;
if (len < s) {
for (; len < s; len <<= 1) ;
int[] t = new int[len];
for (int i = 0; i < rumap.length; i++) {
t[i] = rumap[i];
}
for (int i = rumap.length; i < len; i++) {
t[i] = OperatorClass.NONE;
}
rumap = t;
}
size = s;
}
/**
* Creates new resource map.
*/
public ResourceMap() {
this(4);
}
/**
* Creates new resource map with desired initial length.
*
* @param length desired initial length of the resource map
*/
public ResourceMap(int length) {
rumap = new int[length];
size = 0;
for (int i = 0; i < length; i++) {
rumap[i] = OperatorClass.NONE;
}
}
/**
* Reserves resources for given instruction at given time.
*
* @param i instruction
* @param time time to schedule
* @return true if succeeded, false if there was a conflict
* @see #unschedule(Instruction)
*/
public boolean schedule(Instruction i, int time) {
if (SchedulingInfo.isScheduled(i)) {
throw new InternalError("Already scheduled");
}
OperatorClass opc = i.operator().getOpClass();
if (VERBOSE >= 2) {
debug("Op Class=" + opc);
}
for (int alt = 0; alt < opc.masks.length; alt++) {
int[] ru = opc.masks[alt];
if (schedule(ru, time)) {
SchedulingInfo.setInfo(i, alt, time);
return true;
}
}
return false;
}
/**
* Frees resources for given instruction.
*
* @param i instruction
* @see #schedule(Instruction,int)
*/
public void unschedule(Instruction i) {
if (!SchedulingInfo.isScheduled(i)) {
throw new InternalError("Not scheduled");
}
OperatorClass opc = i.operator().getOpClass();
int[] ru = opc.masks[SchedulingInfo.getAlt(i)];
unschedule(ru, SchedulingInfo.getTime(i));
SchedulingInfo.resetInfo(i);
}
/**
* Returns a string representation of the resource map.
*
* @return a string representation of the resource map
*/
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size; i++) {
sb.append(toBinaryPad32(rumap[i])).append("\n");
}
return sb.toString();
}
// Binds resources for given resource usage pattern at given time.
// Returns false if there is a resource conflict.
// For internal use only.
private boolean schedule(int[] usage, int time) {
grow(time + usage.length);
if (VERBOSE >= 1) {
debug("Pattern (" + usage.length + ")");
for (int anUsage : usage) debug(" " + toBinaryPad32(anUsage));
debug("");
}
for (int i = 0; i < usage.length; i++) {
if ((usage[i] & rumap[time + i]) != 0) {
return false;
}
}
for (int i = 0; i < usage.length; i++) {
rumap[time + i] |= usage[i];
}
return true;
}
// Unbinds resources for given resource usage pattern at given time.
// For internal use only.
private void unschedule(int[] usage, int time) {
for (int i = 0; i < usage.length; i++) {
rumap[time + i] &= ~usage[i];
}
}
}