1 /*
   2  * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.lir.alloc.trace.lsra;
  24 
  25 import static jdk.vm.ci.code.ValueUtil.asRegister;
  26 import static jdk.vm.ci.code.ValueUtil.isRegister;
  27 
  28 import org.graalvm.compiler.lir.LIRInstruction;
  29 
  30 import jdk.vm.ci.meta.AllocatableValue;
  31 import jdk.vm.ci.meta.Value;
  32 
  33 /**
  34  * Represents a fixed interval.
  35  */
  36 final class FixedInterval extends IntervalHint {
  37 
  38     static final class FixedList {
  39 
  40         public FixedInterval fixed;
  41 
  42         FixedList(FixedInterval fixed) {
  43             this.fixed = fixed;
  44         }
  45 
  46         /**
  47          * Gets the fixed list.
  48          */
  49         public FixedInterval getFixed() {
  50             return fixed;
  51         }
  52 
  53         /**
  54          * Sets the fixed list.
  55          */
  56         public void setFixed(FixedInterval list) {
  57             fixed = list;
  58         }
  59 
  60         /**
  61          * Adds an interval to a list sorted by {@linkplain FixedInterval#currentFrom() current
  62          * from} positions.
  63          *
  64          * @param interval the interval to add
  65          */
  66         public void addToListSortedByCurrentFromPositions(FixedInterval interval) {
  67             FixedInterval list = getFixed();
  68             FixedInterval prev = null;
  69             FixedInterval cur = list;
  70             while (cur.currentFrom() < interval.currentFrom()) {
  71                 prev = cur;
  72                 cur = cur.next;
  73             }
  74             FixedInterval result = list;
  75             if (prev == null) {
  76                 // add to head of list
  77                 result = interval;
  78             } else {
  79                 // add before 'cur'
  80                 prev.next = interval;
  81             }
  82             interval.next = cur;
  83             setFixed(result);
  84         }
  85 
  86     }
  87 
  88     /**
  89      * The fixed operand of this interval.
  90      */
  91     public final AllocatableValue operand;
  92 
  93     /**
  94      * The head of the list of ranges describing this interval. This list is sorted by
  95      * {@linkplain LIRInstruction#id instruction ids}.
  96      */
  97     private FixedRange first;
  98 
  99     /**
 100      * Iterator used to traverse the ranges of an interval.
 101      */
 102     private FixedRange current;
 103 
 104     /**
 105      * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
 106      */
 107     FixedInterval next;
 108 
 109     private int cachedTo; // cached value: to of last range (-1: not cached)
 110 
 111     public FixedRange first() {
 112         return first;
 113     }
 114 
 115     @Override
 116     public int from() {
 117         return first.from;
 118     }
 119 
 120     public int to() {
 121         if (cachedTo == -1) {
 122             cachedTo = calcTo();
 123         }
 124         assert cachedTo == calcTo() : "invalid cached value";
 125         return cachedTo;
 126     }
 127 
 128     // test intersection
 129     boolean intersects(TraceInterval i) {
 130         return first.intersects(i);
 131     }
 132 
 133     int intersectsAt(TraceInterval i) {
 134         return first.intersectsAt(i);
 135     }
 136 
 137     // range iteration
 138     void rewindRange() {
 139         current = first;
 140     }
 141 
 142     void nextRange() {
 143         assert this != EndMarker : "not allowed on sentinel";
 144         current = current.next;
 145     }
 146 
 147     int currentFrom() {
 148         return current.from;
 149     }
 150 
 151     int currentTo() {
 152         return current.to;
 153     }
 154 
 155     boolean currentAtEnd() {
 156         return current == FixedRange.EndMarker;
 157     }
 158 
 159     boolean currentIntersects(TraceInterval it) {
 160         return current.intersects(it);
 161     }
 162 
 163     int currentIntersectsAt(TraceInterval it) {
 164         return current.intersectsAt(it);
 165     }
 166 
 167     // range creation
 168     public void setFrom(int from) {
 169         assert !isEmpty();
 170         first().from = from;
 171     }
 172 
 173     private boolean isEmpty() {
 174         return first() == FixedRange.EndMarker;
 175     }
 176 
 177     public void addRange(int from, int to) {
 178         if (isEmpty()) {
 179             first = new FixedRange(from, to, first());
 180             return;
 181         }
 182         if (to <= to() && from >= from()) {
 183             return;
 184         }
 185         if (from() == to) {
 186             first().from = from;
 187         } else {
 188             first = new FixedRange(from, to, first());
 189         }
 190     }
 191 
 192     @Override
 193     public AllocatableValue location() {
 194         return operand;
 195     }
 196 
 197     /**
 198      * Sentinel interval to denote the end of an interval list.
 199      */
 200     static final FixedInterval EndMarker = new FixedInterval(Value.ILLEGAL);
 201 
 202     FixedInterval(AllocatableValue operand) {
 203         assert operand != null;
 204         this.operand = operand;
 205         this.first = FixedRange.EndMarker;
 206         this.current = FixedRange.EndMarker;
 207         this.next = FixedInterval.EndMarker;
 208         this.cachedTo = -1;
 209     }
 210 
 211     int calcTo() {
 212         assert first != FixedRange.EndMarker : "interval has no range";
 213 
 214         FixedRange r = first;
 215         while (r.next != FixedRange.EndMarker) {
 216             r = r.next;
 217         }
 218         return r.to;
 219     }
 220 
 221     // returns true if the opId is inside the interval
 222     boolean covers(int opId, LIRInstruction.OperandMode mode) {
 223         FixedRange cur = first;
 224 
 225         while (cur != FixedRange.EndMarker && cur.to < opId) {
 226             cur = cur.next;
 227         }
 228         if (cur != FixedRange.EndMarker) {
 229             assert cur.to != cur.next.from : "ranges not separated";
 230 
 231             if (mode == LIRInstruction.OperandMode.DEF) {
 232                 return cur.from <= opId && opId < cur.to;
 233             } else {
 234                 return cur.from <= opId && opId <= cur.to;
 235             }
 236         }
 237         return false;
 238     }
 239 
 240     // returns true if the interval has any hole between holeFrom and holeTo
 241     // (even if the hole has only the length 1)
 242     boolean hasHoleBetween(int holeFrom, int holeTo) {
 243         assert holeFrom < holeTo : "check";
 244         assert from() <= holeFrom && holeTo <= to() : "index out of interval";
 245 
 246         FixedRange cur = first;
 247         while (cur != FixedRange.EndMarker) {
 248             assert cur.to < cur.next.from : "no space between ranges";
 249 
 250             // hole-range starts before this range . hole
 251             if (holeFrom < cur.from) {
 252                 return true;
 253 
 254                 // hole-range completely inside this range . no hole
 255             } else {
 256                 if (holeTo <= cur.to) {
 257                     return false;
 258 
 259                     // overlapping of hole-range with this range . hole
 260                 } else {
 261                     if (holeFrom <= cur.to) {
 262                         return true;
 263                     }
 264                 }
 265             }
 266 
 267             cur = cur.next;
 268         }
 269 
 270         return false;
 271     }
 272 
 273     @Override
 274     public String toString() {
 275         if (this == EndMarker) {
 276             return "EndMarker [?,?]";
 277         }
 278         String from = "?";
 279         String to = "?";
 280         if (first != null && first != FixedRange.EndMarker) {
 281             from = String.valueOf(from());
 282             // to() may cache a computed value, modifying the current object, which is a bad idea
 283             // for a printing function. Compute it directly instead.
 284             to = String.valueOf(calcTo());
 285         }
 286         String locationString = "@" + this.operand;
 287         return asRegister(operand).number + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
 288     }
 289 
 290     /**
 291      * Gets a single line string for logging the details of this interval to a log stream.
 292      */
 293     @Override
 294     public String logString() {
 295         StringBuilder buf = new StringBuilder(100);
 296         buf.append("fix ").append(asRegister(operand).number).append(':').append(operand).append(' ');
 297 
 298         buf.append(" ranges{");
 299 
 300         // print ranges
 301         FixedRange cur = first;
 302         while (cur != FixedRange.EndMarker) {
 303             if (cur != first) {
 304                 buf.append(", ");
 305             }
 306             buf.append(cur);
 307             cur = cur.next;
 308             assert cur != null : "range list not closed with range sentinel";
 309         }
 310         buf.append("}");
 311         return buf.toString();
 312     }
 313 
 314 }