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     */
013    package org.jikesrvm.compilers.opt.instrsched;
014    
015    import org.jikesrvm.compilers.opt.ir.Instruction;
016    
017    /**
018     * Resource usage map representation
019     * Used by the scheduler to accommodate resource patterns
020     *
021     * @see OperatorClass
022     * @see org.jikesrvm.compilers.opt.ir.Operator
023     */
024    final class ResourceMap {
025      private static final int VERBOSE = 0;
026    
027      private static void debug(String s) {
028        System.out.println(s);
029      }
030    
031      private static String toBinaryPad32(int value) {
032        String s = Integer.toBinaryString(value);
033        return String.format("%032s", s);
034      }
035    
036      /** GROWABLE Resource Usage map. */
037      private int[] rumap;
038      /** Current size of the RU map. */
039      private int size;
040    
041      /** Grows the RU map to a given size. For internal use only. */
042      private void grow(int s) {
043        if (VERBOSE >= 2) {
044          debug("Growing from " + size + " to " + s);
045        }
046        if (size >= s) {
047          return;
048        }
049        int len = rumap.length;
050        if (len < s) {
051          for (; len < s; len <<= 1) ;
052          int[] t = new int[len];
053          for (int i = 0; i < rumap.length; i++) {
054            t[i] = rumap[i];
055          }
056          for (int i = rumap.length; i < len; i++) {
057            t[i] = OperatorClass.NONE;
058          }
059          rumap = t;
060        }
061        size = s;
062      }
063    
064      /**
065       * Creates new resource map.
066       */
067      public ResourceMap() {
068        this(4);
069      }
070    
071      /**
072       * Creates new resource map with desired initial length.
073       *
074       * @param length desired initial length of the resource map
075       */
076      public ResourceMap(int length) {
077        rumap = new int[length];
078        size = 0;
079        for (int i = 0; i < length; i++) {
080          rumap[i] = OperatorClass.NONE;
081        }
082      }
083    
084      /**
085       * Reserves resources for given instruction at given time.
086       *
087       * @param i instruction
088       * @param time time to schedule
089       * @return true if succeeded, false if there was a conflict
090       * @see #unschedule(Instruction)
091       */
092      public boolean schedule(Instruction i, int time) {
093        if (SchedulingInfo.isScheduled(i)) {
094          throw new InternalError("Already scheduled");
095        }
096        OperatorClass opc = i.operator().getOpClass();
097        if (VERBOSE >= 2) {
098          debug("Op Class=" + opc);
099        }
100        for (int alt = 0; alt < opc.masks.length; alt++) {
101          int[] ru = opc.masks[alt];
102          if (schedule(ru, time)) {
103            SchedulingInfo.setInfo(i, alt, time);
104            return true;
105          }
106        }
107        return false;
108      }
109    
110      /**
111       * Frees resources for given instruction.
112       *
113       * @param i instruction
114       * @see #schedule(Instruction,int)
115       */
116      public void unschedule(Instruction i) {
117        if (!SchedulingInfo.isScheduled(i)) {
118          throw new InternalError("Not scheduled");
119        }
120        OperatorClass opc = i.operator().getOpClass();
121        int[] ru = opc.masks[SchedulingInfo.getAlt(i)];
122        unschedule(ru, SchedulingInfo.getTime(i));
123        SchedulingInfo.resetInfo(i);
124      }
125    
126      /**
127       * Returns a string representation of the resource map.
128       *
129       * @return a string representation of the resource map
130       */
131      @Override
132      public String toString() {
133        StringBuilder sb = new StringBuilder();
134        for (int i = 0; i < size; i++) {
135          sb.append(toBinaryPad32(rumap[i])).append("\n");
136        }
137        return sb.toString();
138      }
139    
140      //
141      // Returns false if there is a resource conflict.
142    
143    
144      /**
145       * Binds resources for given resource usage pattern at given time.
146       * @param usage
147       * @param time
148       * @return {@code false} if there's a resource conflict, {@code true}
149       *  otherwise
150       */
151      private boolean schedule(int[] usage, int time) {
152        grow(time + usage.length);
153        if (VERBOSE >= 1) {
154          debug("Pattern (" + usage.length + ")");
155          for (int anUsage : usage) debug("   " + toBinaryPad32(anUsage));
156          debug("");
157        }
158        for (int i = 0; i < usage.length; i++) {
159          if ((usage[i] & rumap[time + i]) != 0) {
160            return false;
161          }
162        }
163        for (int i = 0; i < usage.length; i++) {
164          rumap[time + i] |= usage[i];
165        }
166        return true;
167      }
168    
169      /**
170       * Unbinds resources for given resource usage pattern at given time.
171       * @param usage
172       * @param time
173       */
174      private void unschedule(int[] usage, int time) {
175        for (int i = 0; i < usage.length; i++) {
176          rumap[time + i] &= ~usage[i];
177        }
178      }
179    }
180    
181    
182