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 static jdk.vm.ci.code.ValueUtil.asRegister;
  26 import static jdk.vm.ci.code.ValueUtil.isIllegal;
  27 import static jdk.vm.ci.code.ValueUtil.isRegister;
  28 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
  29 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
  30 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  31 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
  32 
  33 import java.util.ArrayList;
  34 import java.util.Arrays;
  35 import java.util.Collections;
  36 import java.util.EnumSet;
  37 import java.util.List;
  38 
  39 import org.graalvm.compiler.core.common.LIRKind;
  40 import org.graalvm.compiler.core.common.util.Util;
  41 import org.graalvm.compiler.debug.Assertions;
  42 import org.graalvm.compiler.debug.GraalError;
  43 import org.graalvm.compiler.lir.LIRInstruction;
  44 import org.graalvm.compiler.lir.Variable;
  45 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
  46 import org.graalvm.compiler.options.OptionValues;
  47 
  48 import jdk.vm.ci.code.RegisterValue;
  49 import jdk.vm.ci.code.StackSlot;
  50 import jdk.vm.ci.meta.AllocatableValue;
  51 import jdk.vm.ci.meta.JavaConstant;
  52 import jdk.vm.ci.meta.Value;
  53 import jdk.vm.ci.meta.ValueKind;
  54 
  55 /**
  56  * Represents an interval in the {@linkplain TraceLinearScan linear scan register allocator}.
  57  */
  58 final class TraceInterval extends IntervalHint {
  59 
  60     /**
  61      * Constants denoting the register usage priority for an interval. The constants are declared in
  62      * increasing order of priority are are used to optimize spilling when multiple overlapping
  63      * intervals compete for limited registers.
  64      */
  65     public enum RegisterPriority {
  66         /**
  67          * No special reason for an interval to be allocated a register.
  68          */
  69         None,
  70 
  71         /**
  72          * Priority level for intervals live at the end of a loop.
  73          */
  74         LiveAtLoopEnd,
  75 
  76         /**
  77          * Priority level for intervals that should be allocated to a register.
  78          */
  79         ShouldHaveRegister,
  80 
  81         /**
  82          * Priority level for intervals that must be allocated to a register.
  83          */
  84         MustHaveRegister;
  85 
  86         public static final RegisterPriority[] VALUES = values();
  87 
  88         /**
  89          * Determines if this priority is higher than or equal to a given priority.
  90          */
  91         public boolean greaterEqual(RegisterPriority other) {
  92             return ordinal() >= other.ordinal();
  93         }
  94 
  95         /**
  96          * Determines if this priority is lower than a given priority.
  97          */
  98         public boolean lessThan(RegisterPriority other) {
  99             return ordinal() < other.ordinal();
 100         }
 101 
 102         public CharSequence shortName() {
 103             return name().subSequence(0, 1);
 104         }
 105     }
 106 
 107     /**
 108      * Constants denoting whether an interval is bound to a specific register. This models platform
 109      * dependencies on register usage for certain instructions.
 110      */
 111     enum RegisterBinding {
 112         /**
 113          * Interval is bound to a specific register as required by the platform.
 114          */
 115         Fixed,
 116 
 117         /**
 118          * Interval has no specific register requirements.
 119          */
 120         Any,
 121 
 122         /**
 123          * Interval is bound to a stack slot.
 124          */
 125         Stack;
 126 
 127         public static final RegisterBinding[] VALUES = values();
 128     }
 129 
 130     /**
 131      * Constants denoting the linear-scan states an interval may be in with respect to the
 132      * {@linkplain TraceInterval#from() start} {@code position} of the interval being processed.
 133      */
 134     enum State {
 135         /**
 136          * An interval that starts after {@code position}.
 137          */
 138         Unhandled,
 139 
 140         /**
 141          * An interval that {@linkplain TraceInterval#covers covers} {@code position} and has an
 142          * assigned register.
 143          */
 144         Active,
 145 
 146         /**
 147          * An interval that starts before and ends after {@code position} but does not
 148          * {@linkplain TraceInterval#covers cover} it due to a lifetime hole.
 149          */
 150         Inactive,
 151 
 152         /**
 153          * An interval that ends before {@code position} or is spilled to memory.
 154          */
 155         Handled;
 156     }
 157 
 158     /**
 159      * Constants used in optimization of spilling of an interval.
 160      */
 161     public enum SpillState {
 162         /**
 163          * Starting state of calculation: no definition found yet.
 164          */
 165         NoDefinitionFound,
 166 
 167         /**
 168          * One definition has already been found. Two consecutive definitions are treated as one
 169          * (e.g. a consecutive move and add because of two-operand LIR form). The position of this
 170          * definition is given by {@link TraceInterval#spillDefinitionPos()}.
 171          */
 172         NoSpillStore,
 173 
 174         /**
 175          * A spill move has already been inserted.
 176          */
 177         SpillStore,
 178 
 179         /**
 180          * The interval starts in memory (e.g. method parameter), so a store is never necessary.
 181          */
 182         StartInMemory,
 183 
 184         /**
 185          * The interval has more than one definition (e.g. resulting from phi moves), so stores to
 186          * memory are not optimized.
 187          */
 188         NoOptimization;
 189 
 190         public static final EnumSet<SpillState> IN_MEMORY = EnumSet.of(SpillStore, StartInMemory);
 191     }
 192 
 193     /**
 194      * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
 195      * prior to register allocation.
 196      */
 197     public final Variable operand;
 198 
 199     /**
 200      * The operand number for this interval's {@linkplain #operand operand}.
 201      */
 202     public final int operandNumber;
 203 
 204     /**
 205      * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
 206      * interval. In case of a spilled interval which is re-materialized this is
 207      * {@link Value#ILLEGAL}.
 208      */
 209     private AllocatableValue location;
 210 
 211     /**
 212      * The stack slot to which all splits of this interval are spilled if necessary.
 213      */
 214     private AllocatableValue spillSlot;
 215 
 216     /**
 217      * The start of the range, inclusive.
 218      */
 219     private int intFrom;
 220 
 221     /**
 222      * The end of the range, exclusive.
 223      */
 224     private int intTo;
 225 
 226     /**
 227      * List of (use-positions, register-priorities) pairs, sorted by use-positions.
 228      */
 229     private int[] usePosListArray;
 230     private int usePosListSize;
 231 
 232     /**
 233      * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
 234      */
 235     TraceInterval next;
 236 
 237     /**
 238      * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split
 239      * parent}, it points to itself.
 240      */
 241     private TraceInterval splitParent;
 242 
 243     /**
 244      * List of all intervals that are split off from this interval. This is only used if this is a
 245      * {@linkplain #isSplitParent() split parent}.
 246      */
 247     private ArrayList<TraceInterval> splitChildren = null;
 248 
 249     /**
 250      * Current split child that has been active or inactive last (always stored in split parents).
 251      */
 252     private TraceInterval currentSplitChild;
 253 
 254     /**
 255      * Specifies if move is inserted between currentSplitChild and this interval when interval gets
 256      * active the first time.
 257      */
 258     private boolean insertMoveWhenActivated;
 259 
 260     /**
 261      * For spill move optimization.
 262      */
 263     private SpillState spillState;
 264 
 265     /**
 266      * Position where this interval is defined (if defined only once).
 267      */
 268     private int spillDefinitionPos;
 269 
 270     /**
 271      * This interval should be assigned the same location as the hint interval.
 272      */
 273     private IntervalHint locationHint;
 274 
 275     /**
 276      * The value with which a spilled child interval can be re-materialized. Currently this must be
 277      * a Constant.
 278      */
 279     private JavaConstant materializedValue;
 280 
 281     /**
 282      * Sentinel interval to denote the end of an interval list.
 283      */
 284     static final TraceInterval EndMarker = new TraceInterval(new Variable(ValueKind.Illegal, Integer.MAX_VALUE), -1);
 285 
 286     TraceInterval(Variable operand) {
 287         this(operand, operand.index);
 288     }
 289 
 290     private TraceInterval(Variable operand, int operandNumber) {
 291         assert operand != null;
 292         this.operand = operand;
 293         this.operandNumber = operandNumber;
 294         if (isRegister(operand)) {
 295             location = operand;
 296         } else {
 297             assert isIllegal(operand) || isVariable(operand);
 298         }
 299         this.intFrom = Integer.MAX_VALUE;
 300         this.intTo = Integer.MAX_VALUE;
 301         this.usePosListArray = new int[4 * 2];
 302         this.next = EndMarker;
 303         this.spillState = SpillState.NoDefinitionFound;
 304         this.spillDefinitionPos = -1;
 305         splitParent = this;
 306         currentSplitChild = this;
 307     }
 308 
 309     private boolean splitChildrenEmpty() {
 310         assert splitChildren == null || !splitChildren.isEmpty();
 311         return splitChildren == null;
 312     }
 313 
 314     void assignLocation(AllocatableValue newLocation) {
 315         if (isRegister(newLocation)) {
 316             assert this.location == null : "cannot re-assign location for " + this;
 317             if (newLocation.getValueKind().equals(LIRKind.Illegal) && !kind().equals(LIRKind.Illegal)) {
 318                 this.location = asRegister(newLocation).asValue(kind());
 319                 return;
 320             }
 321         } else if (isIllegal(newLocation)) {
 322             assert canMaterialize();
 323         } else {
 324             assert this.location == null || isRegister(this.location) || (isVirtualStackSlot(this.location) && isStackSlot(newLocation)) : "cannot re-assign location for " + this;
 325             assert isStackSlotValue(newLocation);
 326             assert !newLocation.getValueKind().equals(LIRKind.Illegal);
 327             assert newLocation.getValueKind().equals(this.kind());
 328         }
 329         this.location = newLocation;
 330     }
 331 
 332     /**
 333      * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
 334      * this interval.
 335      */
 336     @Override
 337     public AllocatableValue location() {
 338         return location;
 339     }
 340 
 341     private ValueKind<?> kind() {
 342         return operand.getValueKind();
 343     }
 344 
 345     public boolean isEmpty() {
 346         return intFrom == Integer.MAX_VALUE && intTo == Integer.MAX_VALUE;
 347     }
 348 
 349     public void setTo(int pos) {
 350         assert intFrom == Integer.MAX_VALUE || intFrom < pos;
 351         intTo = pos;
 352     }
 353 
 354     public void setFrom(int pos) {
 355         assert intTo == Integer.MAX_VALUE || pos < intTo;
 356         intFrom = pos;
 357     }
 358 
 359     @Override
 360     public int from() {
 361         return intFrom;
 362     }
 363 
 364     int to() {
 365         return intTo;
 366     }
 367 
 368     int numUsePositions() {
 369         return numUsePos();
 370     }
 371 
 372     public void setLocationHint(IntervalHint interval) {
 373         locationHint = interval;
 374     }
 375 
 376     public boolean hasHint() {
 377         return locationHint != null;
 378     }
 379 
 380     public boolean isSplitParent() {
 381         return splitParent == this;
 382     }
 383 
 384     boolean isSplitChild() {
 385         return splitParent != this;
 386     }
 387 
 388     /**
 389      * Gets the split parent for this interval.
 390      */
 391     public TraceInterval splitParent() {
 392         assert splitParent.isSplitParent() : "not a split parent: " + this;
 393         return splitParent;
 394     }
 395 
 396     /**
 397      * Gets the canonical spill slot for this interval.
 398      */
 399     public AllocatableValue spillSlot() {
 400         return splitParent().spillSlot;
 401     }
 402 
 403     public void setSpillSlot(AllocatableValue slot) {
 404         assert isStackSlotValue(slot);
 405         assert spillSlot() == null || (isVirtualStackSlot(spillSlot()) && isStackSlot(slot)) : String.format("cannot overwrite existing spill slot %s of interval %s with %s", spillSlot(), this, slot);
 406         splitParent().spillSlot = slot;
 407     }
 408 
 409     TraceInterval currentSplitChild() {
 410         return splitParent().currentSplitChild;
 411     }
 412 
 413     void makeCurrentSplitChild() {
 414         splitParent().currentSplitChild = this;
 415     }
 416 
 417     boolean insertMoveWhenActivated() {
 418         return insertMoveWhenActivated;
 419     }
 420 
 421     void setInsertMoveWhenActivated(boolean b) {
 422         insertMoveWhenActivated = b;
 423     }
 424 
 425     // for spill optimization
 426     public SpillState spillState() {
 427         return splitParent().spillState;
 428     }
 429 
 430     public int spillDefinitionPos() {
 431         return splitParent().spillDefinitionPos;
 432     }
 433 
 434     public void setSpillState(SpillState state) {
 435         assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
 436         splitParent().spillState = state;
 437     }
 438 
 439     public void setSpillDefinitionPos(int pos) {
 440         assert spillState() == SpillState.NoDefinitionFound || spillState() == SpillState.NoSpillStore || spillDefinitionPos() == -1 : "cannot set the position twice";
 441         int to = to();
 442         assert pos < to : String.format("Cannot spill %s at %d", this, pos);
 443         splitParent().spillDefinitionPos = pos;
 444     }
 445 
 446     /**
 447      * Returns true if this interval has a shadow copy on the stack that is correct after
 448      * {@code opId}.
 449      */
 450     public boolean inMemoryAt(int opId) {
 451         SpillState spillSt = spillState();
 452         return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
 453     }
 454 
 455     // test intersection
 456     boolean intersects(TraceInterval i) {
 457         return intersectsAt(i) != -1;
 458     }
 459 
 460     int intersectsAt(TraceInterval i) {
 461         TraceInterval i1;
 462         TraceInterval i2;
 463         if (i.from() < this.from()) {
 464             i1 = i;
 465             i2 = this;
 466         } else {
 467             i1 = this;
 468             i2 = i;
 469         }
 470         assert i1.from() <= i2.from();
 471 
 472         if (i1.to() <= i2.from()) {
 473             return -1;
 474         }
 475         return i2.from();
 476     }
 477 
 478     /**
 479      * Sets the value which is used for re-materialization.
 480      */
 481     public void addMaterializationValue(JavaConstant value) {
 482         if (materializedValue != null) {
 483             throw GraalError.shouldNotReachHere(String.format("Multiple materialization values for %s?", this));
 484         }
 485         materializedValue = value;
 486     }
 487 
 488     /**
 489      * Returns true if this interval can be re-materialized when spilled. This means that no
 490      * spill-moves are needed. Instead of restore-moves the {@link #materializedValue} is restored.
 491      */
 492     public boolean canMaterialize() {
 493         return getMaterializedValue() != null;
 494     }
 495 
 496     /**
 497      * Returns a value which can be moved to a register instead of a restore-move from stack.
 498      */
 499     public JavaConstant getMaterializedValue() {
 500         return splitParent().materializedValue;
 501     }
 502 
 503     // consistency check of split-children
 504     boolean checkSplitChildren() {
 505         if (!splitChildrenEmpty()) {
 506             assert isSplitParent() : "only split parents can have children";
 507 
 508             for (int i = 0; i < splitChildren.size(); i++) {
 509                 TraceInterval i1 = splitChildren.get(i);
 510 
 511                 assert i1.splitParent() == this : "not a split child of this interval";
 512                 assert i1.kind().equals(kind()) : "must be equal for all split children";
 513                 assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
 514 
 515                 for (int j = i + 1; j < splitChildren.size(); j++) {
 516                     TraceInterval i2 = splitChildren.get(j);
 517 
 518                     assert i1.operandNumber != i2.operandNumber : "same register number";
 519 
 520                     if (i1.from() < i2.from()) {
 521                         assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
 522                     } else {
 523                         assert i2.from() < i1.from() : "intervals start at same opId";
 524                         assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping";
 525                     }
 526                 }
 527             }
 528         }
 529 
 530         return true;
 531     }
 532 
 533     public IntervalHint locationHint(boolean searchSplitChild) {
 534         if (!searchSplitChild) {
 535             return locationHint;
 536         }
 537 
 538         if (locationHint != null) {
 539             assert !(locationHint instanceof TraceInterval) || ((TraceInterval) locationHint).isSplitParent() : "ony split parents are valid hint registers";
 540 
 541             if (locationHint.location() != null && isRegister(locationHint.location())) {
 542                 return locationHint;
 543             } else if (locationHint instanceof TraceInterval) {
 544                 TraceInterval hint = (TraceInterval) locationHint;
 545                 if (!hint.splitChildrenEmpty()) {
 546                     // search the first split child that has a register assigned
 547                     int len = hint.splitChildren.size();
 548                     for (int i = 0; i < len; i++) {
 549                         TraceInterval interval = hint.splitChildren.get(i);
 550                         if (interval.location != null && isRegister(interval.location)) {
 551                             return interval;
 552                         }
 553                     }
 554                 }
 555             }
 556         }
 557 
 558         // no hint interval found that has a register assigned
 559         return null;
 560     }
 561 
 562     TraceInterval getSplitChildAtOpIdOrNull(int opId, LIRInstruction.OperandMode mode) {
 563         /*
 564          * TODO(je) could be replace by a simple range check by caching `to` in the split parent
 565          * when creating split children.
 566          */
 567         return getSplitChildAtOpIdIntern(opId, mode, true);
 568     }
 569 
 570     TraceInterval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode) {
 571         return getSplitChildAtOpIdIntern(opId, mode, false);
 572     }
 573 
 574     private TraceInterval getSplitChildAtOpIdIntern(int opId, LIRInstruction.OperandMode mode, boolean returnNull) {
 575         assert isSplitParent() : "can only be called for split parents";
 576         assert opId >= 0 : "invalid opId (method cannot be called for spill moves)";
 577 
 578         if (splitChildrenEmpty()) {
 579             if (returnNull) {
 580                 return covers(opId, mode) ? this : null;
 581             }
 582             assert this.covers(opId, mode) : this + " does not cover " + opId;
 583             return this;
 584         } else {
 585             TraceInterval result = null;
 586             int len = splitChildren.size();
 587 
 588             // in outputMode, the end of the interval (opId == cur.to()) is not valid
 589             int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1);
 590 
 591             int i;
 592             for (i = 0; i < len; i++) {
 593                 TraceInterval cur = splitChildren.get(i);
 594                 if (cur.from() <= opId && opId < cur.to() + toOffset) {
 595                     if (i > 0) {
 596                         // exchange current split child to start of list (faster access for next
 597                         // call)
 598                         Util.atPutGrow(splitChildren, i, splitChildren.get(0), null);
 599                         Util.atPutGrow(splitChildren, 0, cur, null);
 600                     }
 601 
 602                     // interval found
 603                     result = cur;
 604                     break;
 605                 }
 606             }
 607 
 608             assert returnNull || checkSplitChild(result, opId, toOffset, mode);
 609             return result;
 610         }
 611     }
 612 
 613     private boolean checkSplitChild(TraceInterval result, int opId, int toOffset, LIRInstruction.OperandMode mode) {
 614         if (result == null) {
 615             // this is an error
 616             StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId);
 617             if (!splitChildrenEmpty()) {
 618                 TraceInterval firstChild = splitChildren.get(0);
 619                 TraceInterval lastChild = splitChildren.get(splitChildren.size() - 1);
 620                 msg.append(" (first = ").append(firstChild).append(", last = ").append(lastChild).append(")");
 621             }
 622             throw new GraalError("Linear Scan Error: %s", msg);
 623         }
 624 
 625         if (!splitChildrenEmpty()) {
 626             for (TraceInterval interval : splitChildren) {
 627                 if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) {
 628                     /*
 629                      * Should not happen: Try another compilation as it is very unlikely to happen
 630                      * again.
 631                      */
 632                     throw new GraalError("two valid result intervals found for opId %d: %d and %d\n%s\n", opId, result.operandNumber, interval.operandNumber,
 633                                     result.logString(), interval.logString());
 634                 }
 635             }
 636         }
 637         assert result.covers(opId, mode) : "opId not covered by interval";
 638         return true;
 639     }
 640 
 641     // returns the last split child that ends before the given opId
 642     TraceInterval getSplitChildBeforeOpId(int opId) {
 643         assert opId >= 0 : "invalid opId";
 644 
 645         TraceInterval parent = splitParent();
 646         TraceInterval result = null;
 647 
 648         assert !parent.splitChildrenEmpty() : "no split children available";
 649         int len = parent.splitChildren.size();
 650 
 651         for (int i = len - 1; i >= 0; i--) {
 652             TraceInterval cur = parent.splitChildren.get(i);
 653             if (cur.to() <= opId && (result == null || result.to() < cur.to())) {
 654                 result = cur;
 655             }
 656         }
 657 
 658         assert result != null : "no split child found";
 659         return result;
 660     }
 661 
 662     private RegisterPriority adaptPriority(RegisterPriority priority) {
 663         /*
 664          * In case of re-materialized values we require that use-operands are registers, because we
 665          * don't have the value in a stack location. (Note that ShouldHaveRegister means that the
 666          * operand can also be a StackSlot).
 667          */
 668         if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) {
 669             return RegisterPriority.MustHaveRegister;
 670         }
 671         return priority;
 672     }
 673 
 674     // Note: use positions are sorted descending . first use has highest index
 675     int firstUsage(RegisterPriority minRegisterPriority) {
 676         for (int i = numUsePos() - 1; i >= 0; --i) {
 677             RegisterPriority registerPriority = adaptPriority(getUsePosRegisterPriority(i));
 678             if (registerPriority.greaterEqual(minRegisterPriority)) {
 679                 return getUsePos(i);
 680             }
 681         }
 682         return Integer.MAX_VALUE;
 683     }
 684 
 685     int nextUsage(RegisterPriority minRegisterPriority, int from) {
 686         for (int i = numUsePos() - 1; i >= 0; --i) {
 687             int usePos = getUsePos(i);
 688             if (usePos >= from && adaptPriority(getUsePosRegisterPriority(i)).greaterEqual(minRegisterPriority)) {
 689                 return usePos;
 690             }
 691         }
 692         return Integer.MAX_VALUE;
 693     }
 694 
 695     int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
 696 
 697         for (int i = numUsePos() - 1; i >= 0; --i) {
 698             int usePos = getUsePos(i);
 699             if (usePos >= from && adaptPriority(getUsePosRegisterPriority(i)) == exactRegisterPriority) {
 700                 return usePos;
 701             }
 702         }
 703         return Integer.MAX_VALUE;
 704     }
 705 
 706     int previousUsage(RegisterPriority minRegisterPriority, int from) {
 707         int prev = -1;
 708         for (int i = numUsePos() - 1; i >= 0; --i) {
 709             int usePos = getUsePos(i);
 710             if (usePos > from) {
 711                 return prev;
 712             }
 713             if (adaptPriority(getUsePosRegisterPriority(i)).greaterEqual(minRegisterPriority)) {
 714                 prev = usePos;
 715             }
 716         }
 717         return prev;
 718     }
 719 
 720     public void addUsePos(int pos, RegisterPriority registerPriority, OptionValues options) {
 721         assert isEmpty() || covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
 722 
 723         // do not add use positions for precolored intervals because they are never used
 724         if (registerPriority != RegisterPriority.None) {
 725             if (Assertions.detailedAssertionsEnabled(options)) {
 726                 for (int i = 0; i < numUsePos(); i++) {
 727                     assert pos <= getUsePos(i) : "already added a use-position with lower position";
 728                     if (i > 0) {
 729                         assert getUsePos(i) < getUsePos(i - 1) : "not sorted descending";
 730                     }
 731                 }
 732             }
 733 
 734             // Note: addUse is called in descending order, so list gets sorted
 735             // automatically by just appending new use positions
 736             int len = numUsePos();
 737             if (len == 0 || getUsePos(len - 1) > pos) {
 738                 usePosAdd(pos, registerPriority);
 739             } else if (getUsePosRegisterPriority(len - 1).lessThan(registerPriority)) {
 740                 assert getUsePos(len - 1) == pos : "list not sorted correctly";
 741                 setUsePosRegisterPriority(len - 1, registerPriority);
 742             }
 743         }
 744     }
 745 
 746     public void addRange(int from, int to) {
 747         assert from < to : "invalid range";
 748 
 749         if (from < intFrom) {
 750             setFrom(from);
 751         }
 752         if (intTo == Integer.MAX_VALUE || intTo < to) {
 753             setTo(to);
 754         }
 755     }
 756 
 757     TraceInterval newSplitChild(TraceLinearScan allocator) {
 758         // allocate new interval
 759         TraceInterval parent = splitParent();
 760         TraceInterval result = allocator.createDerivedInterval(parent);
 761 
 762         result.splitParent = parent;
 763         result.setLocationHint(parent);
 764 
 765         // insert new interval in children-list of parent
 766         if (parent.splitChildrenEmpty()) {
 767             assert isSplitParent() : "list must be initialized at first split";
 768 
 769             // Create new non-shared list
 770             parent.splitChildren = new ArrayList<>(4);
 771             parent.splitChildren.add(this);
 772         }
 773         parent.splitChildren.add(result);
 774 
 775         return result;
 776     }
 777 
 778     /**
 779      * Splits this interval at a specified position and returns the remainder as a new <i>child</i>
 780      * interval of this interval's {@linkplain #splitParent() parent} interval.
 781      * <p>
 782      * When an interval is split, a bi-directional link is established between the original
 783      * <i>parent</i> interval and the <i>children</i> intervals that are split off this interval.
 784      * When a split child is split again, the new created interval is a direct child of the original
 785      * parent. That is, there is no tree of split children stored, just a flat list. All split
 786      * children are spilled to the same {@linkplain #spillSlot spill slot}.
 787      *
 788      * @param splitPos the position at which to split this interval
 789      * @param allocator the register allocator context
 790      * @return the child interval split off from this interval
 791      */
 792     TraceInterval split(int splitPos, TraceLinearScan allocator) {
 793 
 794         // allocate new interval
 795         TraceInterval result = newSplitChild(allocator);
 796 
 797         // split the ranges
 798         result.setTo(intTo);
 799         result.setFrom(splitPos);
 800         intTo = splitPos;
 801 
 802         // split list of use positions
 803         splitUsePosAt(result, splitPos);
 804 
 805         if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) {
 806             for (int i = 0; i < numUsePos(); i++) {
 807                 assert getUsePos(i) < splitPos;
 808             }
 809             for (int i = 0; i < result.numUsePos(); i++) {
 810                 assert result.getUsePos(i) >= splitPos;
 811             }
 812         }
 813         return result;
 814     }
 815 
 816     // returns true if the opId is inside the interval
 817     boolean covers(int opId, LIRInstruction.OperandMode mode) {
 818         if (mode == LIRInstruction.OperandMode.DEF) {
 819             return from() <= opId && opId < to();
 820         }
 821         return from() <= opId && opId <= to();
 822     }
 823 
 824     @Override
 825     public String toString() {
 826         String from = "?";
 827         String to = "?";
 828         if (!isEmpty()) {
 829             from = String.valueOf(from());
 830             to = String.valueOf(to());
 831         }
 832         String locationString = this.location == null ? "" : "@" + this.location;
 833         return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
 834     }
 835 
 836     /**
 837      * Gets a single line string for logging the details of this interval to a log stream.
 838      */
 839     @Override
 840     public String logString() {
 841         StringBuilder buf = new StringBuilder(100);
 842         buf.append("any ").append(operandNumber).append(':').append(operand).append(' ');
 843         if (!isRegister(operand)) {
 844             if (location != null) {
 845                 buf.append("location{").append(location).append("} ");
 846             }
 847         }
 848 
 849         buf.append("hints{").append(splitParent.operandNumber);
 850         IntervalHint hint = locationHint(false);
 851         if (hint != null) {
 852             buf.append(", ").append(hint.location());
 853         }
 854         buf.append("} ranges{");
 855 
 856         // print range
 857         buf.append("[" + from() + ", " + to() + "]");
 858         buf.append("} uses{");
 859 
 860         // print use positions
 861         int prev = -1;
 862         for (int i = numUsePos() - 1; i >= 0; --i) {
 863             assert prev < getUsePos(i) : "use positions not sorted";
 864             if (i != numUsePos() - 1) {
 865                 buf.append(", ");
 866             }
 867             buf.append(getUsePos(i)).append(':').append(getUsePosRegisterPriority(i).shortName());
 868             prev = getUsePos(i);
 869         }
 870         buf.append("} spill-state{").append(spillState()).append("}");
 871         if (canMaterialize()) {
 872             buf.append(" (remat:").append(getMaterializedValue().toString()).append(")");
 873         }
 874         return buf.toString();
 875     }
 876 
 877     List<TraceInterval> getSplitChildren() {
 878         return Collections.unmodifiableList(splitChildren);
 879     }
 880 
 881     /*
 882      * UsePos
 883      *
 884      * List of use positions. Each entry in the list records the use position and register priority
 885      * associated with the use position. The entries in the list are in descending order of use
 886      * position.
 887      *
 888      */
 889 
 890     /**
 891      * Gets the use position at a specified index in this list.
 892      *
 893      * @param index the index of the entry for which the use position is returned
 894      * @return the use position of entry {@code index} in this list
 895      */
 896     int getUsePos(int index) {
 897         return intListGet(index << 1);
 898     }
 899 
 900     int numUsePos() {
 901         return usePosListSize >> 1;
 902     }
 903 
 904     /**
 905      * Gets the register priority for the use position at a specified index in this list.
 906      *
 907      * @param index the index of the entry for which the register priority is returned
 908      * @return the register priority of entry {@code index} in this list
 909      */
 910     RegisterPriority getUsePosRegisterPriority(int index) {
 911         return RegisterPriority.VALUES[intListGet((index << 1) + 1)];
 912     }
 913 
 914     void removeFirstUsePos() {
 915         intListSetSize(usePosListSize - 2);
 916     }
 917 
 918     // internal
 919 
 920     private void setUsePosRegisterPriority(int pos, RegisterPriority registerPriority) {
 921         int index = (pos << 1) + 1;
 922         int value = registerPriority.ordinal();
 923         intListSet(index, value);
 924     }
 925 
 926     private void usePosAdd(int pos, RegisterPriority registerPriority) {
 927         assert usePosListSize == 0 || getUsePos(numUsePos() - 1) > pos;
 928         intListAdd(pos);
 929         intListAdd(registerPriority.ordinal());
 930     }
 931 
 932     private void splitUsePosAt(TraceInterval result, int splitPos) {
 933         int i = numUsePos() - 1;
 934         int len = 0;
 935         while (i >= 0 && getUsePos(i) < splitPos) {
 936             --i;
 937             len += 2;
 938         }
 939         int listSplitIndex = (i + 1) * 2;
 940         int[] array = new int[len];
 941         System.arraycopy(usePosListArray, listSplitIndex, array, 0, len);
 942         if (listSplitIndex < usePosListSize) {
 943             usePosListSize = listSplitIndex;
 944         } else {
 945             assert listSplitIndex == usePosListSize : "splitting cannot grow the use position array!";
 946         }
 947         result.usePosListArray = usePosListArray;
 948         result.usePosListSize = usePosListSize;
 949         usePosListArray = array;
 950         usePosListSize = len;
 951     }
 952 
 953     // IntList
 954 
 955     private int intListGet(int index) {
 956         if (index >= usePosListSize) {
 957             throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + usePosListSize);
 958         }
 959         return usePosListArray[index];
 960     }
 961 
 962     private void intListSet(int index, int value) {
 963         if (index >= usePosListSize) {
 964             throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + usePosListSize);
 965         }
 966         usePosListArray[index] = value;
 967     }
 968 
 969     private void intListAdd(int pos) {
 970         if (usePosListSize == usePosListArray.length) {
 971             int newSize = (usePosListSize * 3) / 2 + 1;
 972             usePosListArray = Arrays.copyOf(usePosListArray, newSize);
 973         }
 974         usePosListArray[usePosListSize++] = pos;
 975     }
 976 
 977     private void intListSetSize(int newSize) {
 978         if (newSize < usePosListSize) {
 979             usePosListSize = newSize;
 980         } else if (newSize > usePosListSize) {
 981             usePosListArray = Arrays.copyOf(usePosListArray, newSize);
 982         }
 983     }
 984 }