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.regalloc;
014    
015    import java.util.ArrayList;
016    import java.util.HashMap;
017    import java.util.HashSet;
018    import org.jikesrvm.compilers.opt.ir.Instruction;
019    import org.jikesrvm.compilers.opt.ir.Register;
020    
021    /**
022     * This class holds information on scratch register usage, needed to
023     * adjust GC Maps.
024     */
025    public final class ScratchMap {
026    
027      private static final boolean DEBUG = false;
028    
029      /**
030       * For each register, the set of intervals describing the register.
031       */
032      private final HashMap<Register, ArrayList<Interval>> map = new HashMap<Register, ArrayList<Interval>>();
033    
034      /**
035       * For each register, a pending (incomplete) interval under
036       * construction.
037       */
038      private final HashMap<Register, Interval> pending = new HashMap<Register, Interval>();
039    
040      /**
041       * For each GC Point s, a set of symbolic registers that are cached in
042       * dirty scratch registers before s.
043       */
044      private final HashMap<Instruction, HashSet<Register>> dirtyMap =
045          new HashMap<Instruction, HashSet<Register>>();
046    
047      /**
048       * Begin a new interval of scratch-ness for a symbolic register.
049       *
050       * @param r the symbolic register being moved into scratch
051       * @param scratch the physical register being used as a scratch
052       * @param begin the instruction before which the physical register is
053       * vacated.
054       */
055      void beginSymbolicInterval(Register r, Register scratch, Instruction begin) {
056        if (DEBUG) {
057          System.out.println("beginSymbolicInterval " + r + " " + scratch + " " + begin.scratch);
058        }
059    
060        SymbolicInterval i = new SymbolicInterval(r, scratch);
061        i.begin = begin;
062        ArrayList<Interval> v = findOrCreateIntervalSet(r);
063        v.add(i);
064        pending.put(r, i);
065      }
066    
067      /**
068       * End an interval of scratch-ness for a symbolic register.
069       *
070       * @param r the symbolic register being moved into scratch
071       * @param end the instruction before which the scratch interval ends
072       */
073      public void endSymbolicInterval(Register r, Instruction end) {
074        if (DEBUG) {
075          System.out.println("endSymbolicInterval " + r + " " + end.scratch);
076        }
077    
078        SymbolicInterval i = (SymbolicInterval) pending.get(r);
079        i.end = end;
080        pending.remove(i);
081      }
082    
083      /**
084       * Begin a new interval of scratch-ness for a physical register.
085       *
086       * @param r the physical register being used as a scratch
087       * @param begin the instruction before which the physical register is
088       * vacated.
089       */
090      void beginScratchInterval(Register r, Instruction begin) {
091        if (DEBUG) {
092          System.out.println("beginScratchInterval " + r + " " + begin.scratch);
093        }
094        PhysicalInterval p = new PhysicalInterval(r);
095        p.begin = begin;
096        ArrayList<Interval> v = findOrCreateIntervalSet(r);
097        v.add(p);
098        pending.put(r, p);
099      }
100    
101      /**
102       * End an interval of scratch-ness for a physical register.
103       *
104       * @param r the physical register being used as a scratch
105       * @param end the instruction before which the physical register is
106       * vacated.
107       */
108      public void endScratchInterval(Register r, Instruction end) {
109        if (DEBUG) {
110          System.out.println("endScratchInterval " + r + " " + end.scratch);
111        }
112        PhysicalInterval p = (PhysicalInterval) pending.get(r);
113        p.end = end;
114        pending.remove(r);
115      }
116    
117      /**
118       * Find or create the set of intervals corresponding to a register r.
119       */
120      private ArrayList<Interval> findOrCreateIntervalSet(Register r) {
121        ArrayList<Interval> v = map.get(r);
122        if (v == null) {
123          v = new ArrayList<Interval>();
124          map.put(r, v);
125        }
126        return v;
127      }
128    
129      /**
130       * Is the given physical register being used as a scratch register
131       * in the given instruction?
132       * @param r a physical register
133       * @param n the instruction's number
134       * @return {@code true} if the register is used as a scratch register
135       *  in the instruction, {@code false} otherwise
136       */
137      boolean isScratch(Register r, int n) {
138        ArrayList<Interval> v = map.get(r);
139        if (v == null) return false;
140        for (final Interval interval : v) {
141          if (interval.contains(n)) return true;
142        }
143        return false;
144      }
145    
146      /**
147       * If a symbolic register resides in a scratch register at an
148       * instruction numbered n, then return the scratch register. Else,
149       * return null.
150       */
151      Register getScratch(Register r, int n) {
152        ArrayList<Interval> v = map.get(r);
153        if (v == null) return null;
154        for (Interval i : v) {
155          if (i.contains(n)) return i.scratch;
156        }
157        return null;
158      }
159    
160      /**
161       * Is this map empty?
162       */
163      public boolean isEmpty() {
164        return map.isEmpty();
165      }
166    
167      /**
168       * Note that at GC point s, the real value of register symb is cached in
169       * a dirty scratch register.
170       */
171      public void markDirty(Instruction s, Register symb) {
172        HashSet<Register> set = dirtyMap.get(s);
173        if (set == null) {
174          set = new HashSet<Register>(3);
175          dirtyMap.put(s, set);
176        }
177        set.add(symb);
178      }
179    
180      /**
181       * At GC point s, is the value of register r cached in a dirty scratch
182       * register?
183       */
184      public boolean isDirty(Instruction s, Register r) {
185        HashSet<Register> set = dirtyMap.get(s);
186        if (set == null) {
187          return false;
188        } else {
189          return set.contains(r);
190        }
191      }
192    
193      /**
194       * Return a String representation.
195       */
196      @Override
197      public String toString() {
198        String result = "";
199        for (ArrayList<Interval> v : map.values()) {
200          for (Interval i : v) {
201            result += i + "\n";
202          }
203        }
204        return result;
205      }
206    
207      /**
208       * Super class of physical and symbolic intervals
209       */
210      private abstract static class Interval {
211        /**
212         * The instruction before which the scratch range begins.
213         */
214        Instruction begin;
215        /**
216         * The instruction before which the scratch range ends.
217         */
218        Instruction end;
219        /**
220         * The physical scratch register or register evicted.
221         */
222        final Register scratch;
223    
224        /**
225         * Initialize scratch register
226         */
227        Interval(Register scratch) {
228          this.scratch = scratch;
229        }
230    
231        /**
232         * Does this interval contain the instruction numbered n?
233         */
234        final boolean contains(int n) {
235          return (begin.scratch <= n && end.scratch > n);
236        }
237      }
238    
239      /**
240       * An object that represents an interval where a symbolic register
241       * resides in a scratch register.<p>
242       *
243       * Note that this interval must not span a basic block.
244       */
245      static final class SymbolicInterval extends Interval {
246        /**
247         * The symbolic register
248         */
249        final Register symbolic;
250    
251        SymbolicInterval(Register symbolic, Register scratch) {
252          super(scratch);
253          this.symbolic = symbolic;
254        }
255    
256        /**
257         * Return a string representation, assuming the 'scratch' field of
258         * Instruction identifies an instruction.
259         */
260        @Override
261        public String toString() {
262          return "SI: " + symbolic + " " + scratch + " [" + begin.scratch + "," + end.scratch + "]";
263        }
264      }
265    
266      /**
267       * An object that represents an interval where a physical register's
268       * contents are evicted so that the physical register can be used as a
269       * scratch.<p>
270       *
271       * Note that this interval must not span a basic block.
272       */
273      static final class PhysicalInterval extends Interval {
274        PhysicalInterval(Register scratch) {
275          super(scratch);
276        }
277    
278        /**
279         * Return a string representation, assuming the 'scratch' field of
280         * Instruction identifies an instruction.
281         */
282        @Override
283        public String toString() {
284          return "PI: " + scratch + " [" + begin.scratch + "," + end.scratch + "]";
285        }
286      }
287    }