1 /* 2 * Copyright (c) 2009, 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 org.graalvm.compiler.debug.Debug; 26 import org.graalvm.compiler.debug.Indent; 27 import org.graalvm.compiler.lir.alloc.trace.lsra.FixedInterval.FixedList; 28 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.AnyList; 29 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterBinding; 30 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.State; 31 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan; 32 33 /** 34 */ 35 class TraceIntervalWalker { 36 37 protected final TraceLinearScan allocator; 38 39 /** 40 * Sorted list of intervals, not live before the current position. 41 */ 42 protected AnyList unhandledAnyList; 43 44 /** 45 * Sorted list of intervals, live at the current position. 46 */ 47 protected AnyList activeAnyList; 48 protected FixedList activeFixedList; 49 50 /** 51 * Sorted list of intervals in a life time hole at the current position. 52 */ 53 protected FixedList inactiveFixedList; 54 55 /** 56 * The current position (intercept point through the intervals). 57 */ 58 protected int currentPosition; 59 60 /** 61 * Processes the {@code currentInterval} interval in an attempt to allocate a physical register 62 * to it and thus allow it to be moved to a list of {@linkplain #activeAnyList active} 63 * intervals. 64 * 65 * @param currentInterval The interval to be activated. 66 * 67 * @return {@code true} if a register was allocated to the {@code currentInterval} interval 68 */ 69 protected boolean activateCurrent(TraceInterval currentInterval) { 70 if (Debug.isLogEnabled()) { 71 logCurrentStatus(); 72 } 73 return true; 74 } 75 76 @SuppressWarnings("try") 77 protected void logCurrentStatus() { 78 try (Indent i = Debug.logAndIndent("active:")) { 79 logList(activeFixedList.getFixed()); 80 logList(activeAnyList.getAny()); 81 } 82 try (Indent i = Debug.logAndIndent("inactive(fixed):")) { 83 logList(inactiveFixedList.getFixed()); 84 } 85 } 86 87 private static void logList(FixedInterval i) { 88 for (FixedInterval interval = i; interval != FixedInterval.EndMarker; interval = interval.next) { 89 Debug.log("%s", interval.logString()); 90 } 91 } 92 93 private static void logList(TraceInterval i) { 94 for (TraceInterval interval = i; interval != TraceInterval.EndMarker; interval = interval.next) { 95 Debug.log("%s", interval.logString()); 96 } 97 } 98 99 void walkBefore(int lirOpId) { 100 walkTo(lirOpId - 1); 101 } 102 103 void walk() { 104 walkTo(Integer.MAX_VALUE); 105 } 106 107 /** 108 * Creates a new interval walker. 109 * 110 * @param allocator the register allocator context 111 * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed} 112 * intervals 113 * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed} 114 * intervals 115 */ 116 TraceIntervalWalker(TraceLinearScan allocator, FixedInterval unhandledFixed, TraceInterval unhandledAny) { 117 this.allocator = allocator; 118 119 unhandledAnyList = new AnyList(unhandledAny); 120 activeAnyList = new AnyList(TraceInterval.EndMarker); 121 activeFixedList = new FixedList(FixedInterval.EndMarker); 122 // we don't need a separate unhandled list for fixed. 123 inactiveFixedList = new FixedList(unhandledFixed); 124 currentPosition = -1; 125 } 126 127 protected void removeFromList(TraceInterval interval) { 128 activeAnyList.removeAny(interval); 129 } 130 131 /** 132 * Walks up to {@code from} and updates the state of {@link FixedInterval fixed intervals}. 133 * 134 * Fixed intervals can switch back and forth between the states {@link State#Active} and 135 * {@link State#Inactive} (and eventually to {@link State#Handled} but handled intervals are not 136 * managed). 137 */ 138 @SuppressWarnings("try") 139 private void walkToFixed(State state, int from) { 140 assert state == State.Active || state == State.Inactive : "wrong state"; 141 FixedInterval prevprev = null; 142 FixedInterval prev = (state == State.Active) ? activeFixedList.getFixed() : inactiveFixedList.getFixed(); 143 FixedInterval next = prev; 144 if (Debug.isLogEnabled()) { 145 try (Indent i = Debug.logAndIndent("walkToFixed(%s, %d):", state, from)) { 146 logList(next); 147 } 148 } 149 while (next.currentFrom() <= from) { 150 FixedInterval cur = next; 151 next = cur.next; 152 153 boolean rangeHasChanged = false; 154 while (cur.currentTo() <= from) { 155 cur.nextRange(); 156 rangeHasChanged = true; 157 } 158 159 // also handle move from inactive list to active list 160 rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from); 161 162 if (rangeHasChanged) { 163 // remove cur from list 164 if (prevprev == null) { 165 if (state == State.Active) { 166 activeFixedList.setFixed(next); 167 } else { 168 inactiveFixedList.setFixed(next); 169 } 170 } else { 171 prevprev.next = next; 172 } 173 prev = next; 174 TraceInterval.State newState; 175 if (cur.currentAtEnd()) { 176 // move to handled state (not maintained as a list) 177 newState = State.Handled; 178 } else { 179 if (cur.currentFrom() <= from) { 180 // sort into active list 181 activeFixedList.addToListSortedByCurrentFromPositions(cur); 182 newState = State.Active; 183 } else { 184 // sort into inactive list 185 inactiveFixedList.addToListSortedByCurrentFromPositions(cur); 186 newState = State.Inactive; 187 } 188 if (prev == cur) { 189 assert state == newState; 190 prevprev = prev; 191 prev = cur.next; 192 } 193 } 194 intervalMoved(cur, state, newState); 195 } else { 196 prevprev = prev; 197 prev = cur.next; 198 } 199 } 200 } 201 202 /** 203 * Walks up to {@code from} and updates the state of {@link TraceInterval intervals}. 204 * 205 * Trace intervals can switch once from {@link State#Unhandled} to {@link State#Active} and then 206 * to {@link State#Handled} but handled intervals are not managed. 207 */ 208 @SuppressWarnings("try") 209 private void walkToAny(int from) { 210 TraceInterval prevprev = null; 211 TraceInterval prev = activeAnyList.getAny(); 212 TraceInterval next = prev; 213 if (Debug.isLogEnabled()) { 214 try (Indent i = Debug.logAndIndent("walkToAny(%d):", from)) { 215 logList(next); 216 } 217 } 218 while (next.from() <= from) { 219 TraceInterval cur = next; 220 next = cur.next; 221 222 if (cur.to() <= from) { 223 // remove cur from list 224 if (prevprev == null) { 225 activeAnyList.setAny(next); 226 } else { 227 prevprev.next = next; 228 } 229 intervalMoved(cur, State.Active, State.Handled); 230 } else { 231 prevprev = prev; 232 } 233 prev = next; 234 } 235 } 236 237 /** 238 * Get the next interval from {@linkplain #unhandledAnyList} which starts before or at 239 * {@code toOpId}. The returned interval is removed. 240 * 241 * @postcondition all intervals in {@linkplain #unhandledAnyList} start after {@code toOpId}. 242 * 243 * @return The next interval or null if there is no {@linkplain #unhandledAnyList unhandled} 244 * interval at position {@code toOpId}. 245 */ 246 private TraceInterval nextInterval(int toOpId) { 247 TraceInterval any = unhandledAnyList.getAny(); 248 249 if (any != TraceInterval.EndMarker) { 250 TraceInterval currentInterval = unhandledAnyList.getAny(); 251 if (toOpId < currentInterval.from()) { 252 return null; 253 } 254 255 unhandledAnyList.setAny(currentInterval.next); 256 currentInterval.next = TraceInterval.EndMarker; 257 return currentInterval; 258 } 259 return null; 260 261 } 262 263 /** 264 * Walk up to {@code toOpId}. 265 * 266 * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeFixedList} 267 * and {@link #inactiveFixedList} are populated. 268 */ 269 @SuppressWarnings("try") 270 protected void walkTo(int toOpId) { 271 assert currentPosition <= toOpId : "can not walk backwards"; 272 for (TraceInterval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) { 273 int opId = currentInterval.from(); 274 275 // set currentPosition prior to call of walkTo 276 currentPosition = opId; 277 278 // update unhandled stack intervals 279 // updateUnhandledStackIntervals(opId); 280 281 // call walkTo even if currentPosition == id 282 walkToFixed(State.Active, opId); 283 walkToFixed(State.Inactive, opId); 284 walkToAny(opId); 285 286 try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) { 287 if (activateCurrent(currentInterval)) { 288 activeAnyList.addToListSortedByFromPositions(currentInterval); 289 intervalMoved(currentInterval, State.Unhandled, State.Active); 290 } 291 } 292 } 293 // set currentPosition prior to call of walkTo 294 currentPosition = toOpId; 295 296 if (currentPosition <= allocator.maxOpId()) { 297 // update unhandled stack intervals 298 // updateUnhandledStackIntervals(toOpId); 299 300 // call walkTo if still in range 301 walkToFixed(State.Active, toOpId); 302 walkToFixed(State.Inactive, toOpId); 303 walkToAny(toOpId); 304 } 305 } 306 307 private static void intervalMoved(IntervalHint interval, State from, State to) { 308 // intervalMoved() is called whenever an interval moves from one interval list to another. 309 // In the implementation of this method it is prohibited to move the interval to any list. 310 if (Debug.isLogEnabled()) { 311 Debug.log("interval moved from %s to %s: %s", from, to, interval.logString()); 312 } 313 } 314 }