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 */ 23package org.graalvm.compiler.lir.alloc.trace.lsra; 24 25import static jdk.vm.ci.code.ValueUtil.asRegister; 26import static jdk.vm.ci.code.ValueUtil.isRegister; 27 28import org.graalvm.compiler.lir.LIRInstruction; 29 30import jdk.vm.ci.meta.AllocatableValue; 31import jdk.vm.ci.meta.Value; 32 33/** 34 * Represents a fixed interval. 35 */ 36final class FixedInterval extends IntervalHint { 37 38 /** 39 * The fixed operand of this interval. 40 */ 41 public final AllocatableValue operand; 42 43 /** 44 * The head of the list of ranges describing this interval. This list is sorted by 45 * {@linkplain LIRInstruction#id instruction ids}. 46 */ 47 private FixedRange first; 48 49 /** 50 * Iterator used to traverse the ranges of an interval. 51 */ 52 private FixedRange current; 53 54 /** 55 * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}. 56 */ 57 FixedInterval next; 58 59 private int cachedTo; // cached value: to of last range (-1: not cached) 60 61 public FixedRange first() { 62 return first; 63 } 64 65 @Override 66 public int from() { 67 return first.from; 68 } 69 70 public int to() { 71 if (cachedTo == -1) { 72 cachedTo = calcTo(); 73 } 74 assert cachedTo == calcTo() : "invalid cached value"; 75 return cachedTo; 76 } 77 78 // test intersection 79 boolean intersects(TraceInterval i) { 80 return first.intersects(i); 81 } 82 83 int intersectsAt(TraceInterval i) { 84 return first.intersectsAt(i); 85 } 86 87 // range iteration 88 void rewindRange() { 89 current = first; 90 } 91 92 void nextRange() { 93 assert this != EndMarker : "not allowed on sentinel"; 94 current = current.next; 95 } 96 97 int currentFrom() { 98 return current.from; 99 } 100 101 int currentTo() { 102 return current.to; 103 } 104 105 boolean currentAtEnd() { 106 return current == FixedRange.EndMarker; 107 } 108 109 boolean currentIntersects(TraceInterval it) { 110 return current.intersects(it); 111 } 112 113 int currentIntersectsAt(TraceInterval it) { 114 return current.intersectsAt(it); 115 } 116 117 // range creation 118 public void setFrom(int from) { 119 assert !isEmpty(); 120 first().from = from; 121 } 122 123 private boolean isEmpty() { 124 return first() == FixedRange.EndMarker; 125 } 126 127 public void addRange(int from, int to) { 128 if (isEmpty()) { 129 first = new FixedRange(from, to, first()); 130 return; 131 } 132 if (to <= to() && from >= from()) { 133 return; 134 } 135 if (from() == to) { 136 first().from = from; 137 } else { 138 first = new FixedRange(from, to, first()); 139 } 140 } 141 142 @Override 143 public AllocatableValue location() { 144 return operand; 145 } 146 147 /** 148 * Sentinel interval to denote the end of an interval list. 149 */ 150 static final FixedInterval EndMarker = new FixedInterval(Value.ILLEGAL); 151 152 FixedInterval(AllocatableValue operand) { 153 assert operand != null; 154 this.operand = operand; 155 this.first = FixedRange.EndMarker; 156 this.current = FixedRange.EndMarker; 157 this.next = FixedInterval.EndMarker; 158 this.cachedTo = -1; 159 } 160 161 int calcTo() { 162 assert first != FixedRange.EndMarker : "interval has no range"; 163 164 FixedRange r = first; 165 while (r.next != FixedRange.EndMarker) { 166 r = r.next; 167 } 168 return r.to; 169 } 170 171 // returns true if the opId is inside the interval 172 boolean covers(int opId, LIRInstruction.OperandMode mode) { 173 FixedRange cur = first; 174 175 while (cur != FixedRange.EndMarker && cur.to < opId) { 176 cur = cur.next; 177 } 178 if (cur != FixedRange.EndMarker) { 179 assert cur.to != cur.next.from : "ranges not separated"; 180 181 if (mode == LIRInstruction.OperandMode.DEF) { 182 return cur.from <= opId && opId < cur.to; 183 } else { 184 return cur.from <= opId && opId <= cur.to; 185 } 186 } 187 return false; 188 } 189 190 // returns true if the interval has any hole between holeFrom and holeTo 191 // (even if the hole has only the length 1) 192 boolean hasHoleBetween(int holeFrom, int holeTo) { 193 assert holeFrom < holeTo : "check"; 194 assert from() <= holeFrom && holeTo <= to() : "index out of interval"; 195 196 FixedRange cur = first; 197 while (cur != FixedRange.EndMarker) { 198 assert cur.to < cur.next.from : "no space between ranges"; 199 200 // hole-range starts before this range . hole 201 if (holeFrom < cur.from) { 202 return true; 203 204 // hole-range completely inside this range . no hole 205 } else { 206 if (holeTo <= cur.to) { 207 return false; 208 209 // overlapping of hole-range with this range . hole 210 } else { 211 if (holeFrom <= cur.to) { 212 return true; 213 } 214 } 215 } 216 217 cur = cur.next; 218 } 219 220 return false; 221 } 222 223 @Override 224 public String toString() { 225 if (this == EndMarker) { 226 return "EndMarker [?,?]"; 227 } 228 String from = "?"; 229 String to = "?"; 230 if (first != null && first != FixedRange.EndMarker) { 231 from = String.valueOf(from()); 232 // to() may cache a computed value, modifying the current object, which is a bad idea 233 // for a printing function. Compute it directly instead. 234 to = String.valueOf(calcTo()); 235 } 236 String locationString = "@" + this.operand; 237 return asRegister(operand).number + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]"; 238 } 239 240 /** 241 * Gets a single line string for logging the details of this interval to a log stream. 242 */ 243 @Override 244 public String logString() { 245 StringBuilder buf = new StringBuilder(100); 246 buf.append("fix ").append(asRegister(operand).number).append(':').append(operand).append(' '); 247 248 buf.append(" ranges{"); 249 250 // print ranges 251 FixedRange cur = first; 252 while (cur != FixedRange.EndMarker) { 253 if (cur != first) { 254 buf.append(", "); 255 } 256 buf.append(cur); 257 cur = cur.next; 258 assert cur != null : "range list not closed with range sentinel"; 259 } 260 buf.append("}"); 261 return buf.toString(); 262 } 263 264} 265