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    //OperatorClass.java
014    package org.jikesrvm.compilers.opt.instrsched;
015    
016    import org.jikesrvm.*;
017    import org.jikesrvm.compilers.opt.ir.*;
018    import java.util.ArrayList;
019    
020    /**
021     * Generated from a template.
022     * Consists of an operator class and information about resource usage
023     * There is only one instance of each OperatorClass, which is stored
024     * as a static final field in OperatorClass.  You can compare
025     * OperatorClasses using ==.
026     * Every Operator contains one of these.
027     *
028     * @see Operator
029     * @see Operators
030     */
031    public final class OperatorClass implements Operators {
032    
033       // debug level (0 = no debug)
034       private static final int verbose = 0;
035    
036       private static void debug(String s) {
037          System.err.println(s);
038       }
039       private static String SPACES = null;
040       private static void debug(int depth, String s) {
041          if (SPACES == null) SPACES = dup(7200, ' ');
042          debug(SPACES.substring(0,depth*2)+s);
043       }
044    
045       // Padding
046       // For internal use only.
047       private static final String ZEROS = dup(32, '0');
048       private static String toBinaryPad32(int value) {
049          String s = Integer.toBinaryString(value);
050          return ZEROS.substring(s.length())+s;
051       }
052    
053       // Returns a special resource type embodying all resources of a given class.
054       // For internal use only.
055       private static int all_units(int rclass) { return rclass | 0x80000000; }
056    
057       /**
058        * Empty Resources Mask
059        */
060       static int NONE = 0;
061    
062       /**
063        * All Resources Mask
064        */
065       static int ALL = 0;          // will be filled in
066    
067       // Generates an array of resource masks, and updating the static field
068       // ALL to contain all of the masks.
069       // For internal use only.
070       private static int M = 1;    // current mask
071       private static int[] genMasks(int number) {
072          int[] rs = new int[number + 1];
073          int rall = 0;
074          for (int i = 0; i < number; i++) {
075             if (VM.VerifyAssertions && M == 0)
076                throw new InternalError("Exceeded 32 resources");
077             //System.err.println("Scheduler: Resource "+M);
078             rs[i] = M;
079             ALL |= M;
080             rall |= M;
081             M <<= 1;
082          }
083          rs[number] = rall;
084          return rs;
085       }
086    
087       /**
088        * Resource Masks
089        */
090       private static final int[][] resources = {
091          null
092       };
093    
094       /**
095        * Total number of resources
096        */
097       static final int N = resources.length - 1;
098    
099       /**
100        * Resource Names
101        */
102       private static final String[] resource_names = {
103          null
104       };
105    
106       /**
107        * Resources
108        */
109    
110    
111       /**
112        * Id of the operator class
113        */
114       private int id = 0;
115    
116       /**
117        * Maximum Latency of any instruction
118        */
119       private int maxlat = 0;
120    
121       /**
122        * Returns the maximum latency of any instruction in the class.
123        * Note: it is faster to simply check the field directly, if possible.
124        */
125       public int maxLatency() { return maxlat; }
126    
127       /**
128        * Latencies to other classes
129        */
130       private final ArrayList<Integer> latencies;
131    
132       // Returns latency lookup in the hashtable for a given operator class.
133       // For internal use only.
134       private Object latObj(OperatorClass opclass) {
135          int latsize = latencies.size();
136          Object latObj = null;
137          if (latsize > opclass.id) latObj = latencies.get(opclass.id);
138    
139          // walk through backwards, since any_insn (most general) is first
140          ArrayList<OperatorClass> opcrc = opclass.rclasses;
141          for (int i = opcrc.size(); latObj == null && i > 0; i--) {
142             OperatorClass rc = opcrc.get(i - 1);
143             if (latsize > rc.id) latObj = latencies.get(rc.id);
144          }
145    
146          for (int i = rclasses.size(); latObj == null && i > 0; i--) {
147             OperatorClass rc = rclasses.get(i - 1);
148             latObj = rc.latObj(opclass);
149          }
150    
151          return latObj;
152       }
153    
154       /**
155        * Sets the operator class (for hierarchy)
156        *
157        * @param opClass operator class
158        */
159       public void setOpClass(OperatorClass opClass) {
160          rclasses.add(opClass);
161       }
162    
163       /**
164        * Returns the latency between instructions in this class and given class
165        *
166        * @param opclass destination operator class
167        * @return latency to given operator class
168        */
169       public int latency(OperatorClass opclass) {
170          return (Integer) latObj(opclass);
171       }
172    
173       /**
174        * Sets the latency between instructions in this class and given class
175        *
176        * @param opclass destination operator class
177        * @param latency desired latency
178        */
179       public void setLatency(OperatorClass opclass, int latency) {
180          int latencies_size = latencies.size();
181          if (opclass.id < latencies_size) {
182             latencies.set(opclass.id, latency);
183          }
184          else {
185             for(; latencies_size < opclass.id; latencies_size++) {
186                latencies.add(null);
187             }
188             latencies.add(latency);
189          }
190       }
191       /**
192        * Sets the latency between instructions in given class and this class
193        *
194        * @param opclass source operator class
195        * @param latency desired latency
196        */
197       public void setRevLatency(OperatorClass opclass, int latency) {
198          opclass.setLatency(this, latency);
199       }
200    
201       /*
202        * Operator Classes
203        */
204    
205       // Global class embodying all operator classes.  For internal use only.
206       private static final OperatorClass any_insn = new OperatorClass(0);
207    
208    
209       /**
210        * Map from resource to operator class representing that resource
211        */
212       private static OperatorClass[] res2class = {
213          null
214       };
215    
216       private static final OperatorClass
217       pseudo_ops = new OperatorClass(
218          0+N+1,
219          new ResourceReservation[] {
220          }
221       );
222       static {
223          LABEL.setOpClass(pseudo_ops);
224          BBEND.setOpClass(pseudo_ops);
225          UNINT_BEGIN.setOpClass(pseudo_ops);
226          UNINT_END.setOpClass(pseudo_ops);
227    
228    
229          pseudo_ops.setLatency(any_insn, 0);
230    
231       }
232    
233       /**
234        * Resource Classes used by this Operator Class
235        */
236       final ArrayList<OperatorClass> rclasses;
237    
238       /**
239        * Resource Usage Masks
240        */
241       int[][] masks;
242    
243       // For internal use only.
244       private OperatorClass(int _id) {
245          id = _id;
246          rclasses = new ArrayList<OperatorClass>();
247          latencies = new ArrayList<Integer>();
248       }
249    
250       // For internal use only.
251       private OperatorClass(int _id, ResourceReservation[] pat) {
252          this(_id);
253          allocateMasks(pat);
254          if (verbose >= 2) debug(masks.length+" masks allocated for "+pat.length+
255                                  " requests");
256          int[] assign = new int[pat.length];
257          int comb = fillMasks(pat, assign, 0, 0, 0);
258          if (false && comb != masks.length)
259             throw new InternalError("Insufficient Resources");
260       }
261    
262       /**
263        * Returns the string representation of this operator class.
264        */
265       public String toString() {
266          StringBuffer sb = new StringBuffer("Size=");
267          sb.append(masks.length).append('\n');
268         for (int[] mask : masks) {
269           for (int v : mask)
270             sb.append(toBinaryPad32(v)).append('\n');
271           sb.append('\n');
272         }
273          return sb.toString();
274       }
275    
276       // For internal use only.
277       private void allocateMasks(ResourceReservation[] pat) {
278          ResourceReservation.sort(pat);
279          int maxlen = 0;
280          int size = 1;
281          ResourceReservation r = new ResourceReservation(-1, -1, -1000);
282          int len = -1;
283          OperatorClass[] rss = new OperatorClass[N];
284          for (ResourceReservation p : pat) {
285             rss[p.rclass()] = res2class[p.rclass()];
286             boolean same = p.equals(r);
287             if (!p.conflicts(r)) {
288                r = p;
289                if (r.isGlobal())
290                   len = 1;
291                else
292                   len = resources[r.rclass()].length - 1;
293             } else if (r.isGlobal()) {
294                throw new InternalError("Insufficient Resources");
295             } else {
296                len--;
297             }
298             size *= len;
299             if (same)
300                size /= 2;
301             if (p.start + p.duration > maxlen)
302                maxlen = p.start + p.duration;
303          }
304          rclasses.add(any_insn);
305          for (int i = 0; i < N; i++)
306             if (rss[i] != null)
307                rclasses.add(rss[i]);
308          masks = new int[size][];
309          for (int i = 0; i < size; i++)
310             masks[i] = new int[maxlen];
311       }
312    
313       // For internal debug use only.
314       static int depth = 0;
315    
316       // For internal use only.
317       private int fillMasks(ResourceReservation[] pat, int[] assign,
318                                   int all, int rrq, int comb) {
319          if (rrq == pat.length) {
320             for (int i = 0; i < masks[comb].length; i++)
321                masks[comb][i] = 0;
322             StringBuffer dbSB;
323             if (verbose >= 1) dbSB = new StringBuffer();
324             for (int i = 0; i < pat.length; i++) {
325                ResourceReservation pi = pat[i];
326                int rc = pi.rclass();
327                int mask = resources[rc][assign[i]];
328                if (verbose >= 1) dbSB.append(toBinaryPad32(mask)).append(" ");
329                for (int j = 0; j < pi.duration; j++)
330                   masks[comb][pi.start + j] |= mask;
331                if (maxlat < pi.duration)
332                   maxlat = pi.duration;
333             }
334             if (verbose >= 1) debug(dbSB.toString());
335             return comb + 1;
336          }
337          int rc = pat[rrq].rclass();
338          int start = 0;
339          int end = resources[rc].length - 1;
340          if (rrq != 0 && pat[rrq].equals(pat[rrq-1]))
341             start = assign[rrq-1] + 1;
342          boolean ignore = ((rrq != 0 && !pat[rrq].conflicts(pat[rrq-1])) ||
343                            pat[rrq].isGlobal());
344          if (pat[rrq].isGlobal()) {
345             start = end;
346             end++;
347          }
348    
349          for (int i = start; i < end; i++)
350             if (ignore || (resources[rc][i] & all) == 0) {
351                if (verbose >= 2) debug(depth, rrq+": Res#"+rc+"; Trying "+i+
352                                        "; reserved='"+toBinaryPad32(all)+"'");
353    
354                depth++;
355                assign[rrq] = i;
356                comb = fillMasks(pat, assign, all | resources[rc][i], rrq+1, comb);
357                depth--;
358             }
359    
360          return comb;
361       }
362    
363       // Generates a string of a given length filled by a given character.
364       // For internal use only.
365       private static String dup(int len, char c) {
366          StringBuffer sb = new StringBuffer();
367          for (int i = 0; i < len; i++)
368             sb.append(c);
369          return sb.toString();
370       }
371    }