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.lsra; 24 25 import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts; 26 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; 27 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; 28 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot; 29 import static jdk.vm.ci.code.ValueUtil.asRegister; 30 import static jdk.vm.ci.code.ValueUtil.isIllegal; 31 import static jdk.vm.ci.code.ValueUtil.isRegister; 32 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 33 34 import java.util.ArrayList; 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.IntList; 41 import org.graalvm.compiler.core.common.util.Util; 42 import org.graalvm.compiler.debug.GraalError; 43 import org.graalvm.compiler.lir.LIRInstruction; 44 import org.graalvm.compiler.lir.Variable; 45 46 import jdk.vm.ci.code.RegisterValue; 47 import jdk.vm.ci.code.StackSlot; 48 import jdk.vm.ci.meta.AllocatableValue; 49 import jdk.vm.ci.meta.Constant; 50 import jdk.vm.ci.meta.Value; 51 import jdk.vm.ci.meta.ValueKind; 52 53 /** 54 * Represents an interval in the {@linkplain LinearScan linear scan register allocator}. 55 */ 56 public final class Interval { 57 58 /** 59 * A pair of intervals. 60 */ 61 static final class Pair { 62 63 public final Interval first; 64 public final Interval second; 65 66 Pair(Interval first, Interval second) { 67 this.first = first; 68 this.second = second; 69 } 70 } 71 72 /** 73 * A set of interval lists, one per {@linkplain RegisterBinding binding} type. 74 */ 75 static final class RegisterBindingLists { 76 77 /** 78 * List of intervals whose binding is currently {@link RegisterBinding#Fixed}. 79 */ 80 public Interval fixed; 81 82 /** 83 * List of intervals whose binding is currently {@link RegisterBinding#Any}. 84 */ 85 public Interval any; 86 87 /** 88 * List of intervals whose binding is currently {@link RegisterBinding#Stack}. 89 */ 90 public Interval stack; 91 92 RegisterBindingLists(Interval fixed, Interval any, Interval stack) { 93 this.fixed = fixed; 94 this.any = any; 95 this.stack = stack; 96 } 97 98 /** 99 * Gets the list for a specified binding. 100 * 101 * @param binding specifies the list to be returned 102 * @return the list of intervals whose binding is {@code binding} 103 */ 104 public Interval get(RegisterBinding binding) { 105 switch (binding) { 106 case Any: 107 return any; 108 case Fixed: 109 return fixed; 110 case Stack: 111 return stack; 112 } 113 throw GraalError.shouldNotReachHere(); 114 } 115 116 /** 117 * Sets the list for a specified binding. 118 * 119 * @param binding specifies the list to be replaced 120 * @param list a list of intervals whose binding is {@code binding} 121 */ 122 public void set(RegisterBinding binding, Interval list) { 123 assert list != null; 124 switch (binding) { 125 case Any: 126 any = list; 127 break; 128 case Fixed: 129 fixed = list; 130 break; 131 case Stack: 132 stack = list; 133 break; 134 } 135 } 136 137 /** 138 * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from} 139 * positions. 140 * 141 * @param binding specifies the list to be updated 142 * @param interval the interval to add 143 */ 144 public void addToListSortedByCurrentFromPositions(RegisterBinding binding, Interval interval) { 145 Interval list = get(binding); 146 Interval prev = null; 147 Interval cur = list; 148 while (cur.currentFrom() < interval.currentFrom()) { 149 prev = cur; 150 cur = cur.next; 151 } 152 Interval result = list; 153 if (prev == null) { 154 // add to head of list 155 result = interval; 156 } else { 157 // add before 'cur' 158 prev.next = interval; 159 } 160 interval.next = cur; 161 set(binding, result); 162 } 163 164 /** 165 * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and 166 * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions. 167 * 168 * @param binding specifies the list to be updated 169 * @param interval the interval to add 170 */ 171 public void addToListSortedByStartAndUsePositions(RegisterBinding binding, Interval interval) { 172 Interval list = get(binding); 173 Interval prev = null; 174 Interval cur = list; 175 while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) { 176 prev = cur; 177 cur = cur.next; 178 } 179 if (prev == null) { 180 list = interval; 181 } else { 182 prev.next = interval; 183 } 184 interval.next = cur; 185 set(binding, list); 186 } 187 188 /** 189 * Removes an interval from a list. 190 * 191 * @param binding specifies the list to be updated 192 * @param i the interval to remove 193 */ 194 public void remove(RegisterBinding binding, Interval i) { 195 Interval list = get(binding); 196 Interval prev = null; 197 Interval cur = list; 198 while (cur != i) { 199 assert cur != null && cur != Interval.EndMarker : "interval has not been found in list: " + i; 200 prev = cur; 201 cur = cur.next; 202 } 203 if (prev == null) { 204 set(binding, cur.next); 205 } else { 206 prev.next = cur.next; 207 } 208 } 209 } 210 211 /** 212 * Constants denoting the register usage priority for an interval. The constants are declared in 213 * increasing order of priority are are used to optimize spilling when multiple overlapping 214 * intervals compete for limited registers. 215 */ 216 public enum RegisterPriority { 217 /** 218 * No special reason for an interval to be allocated a register. 219 */ 220 None, 221 222 /** 223 * Priority level for intervals live at the end of a loop. 224 */ 225 LiveAtLoopEnd, 226 227 /** 228 * Priority level for intervals that should be allocated to a register. 229 */ 230 ShouldHaveRegister, 231 232 /** 233 * Priority level for intervals that must be allocated to a register. 234 */ 235 MustHaveRegister; 236 237 public static final RegisterPriority[] VALUES = values(); 238 239 /** 240 * Determines if this priority is higher than or equal to a given priority. 241 */ 242 public boolean greaterEqual(RegisterPriority other) { 243 return ordinal() >= other.ordinal(); 244 } 245 246 /** 247 * Determines if this priority is lower than a given priority. 248 */ 249 public boolean lessThan(RegisterPriority other) { 250 return ordinal() < other.ordinal(); 251 } 252 } 253 254 /** 255 * Constants denoting whether an interval is bound to a specific register. This models platform 256 * dependencies on register usage for certain instructions. 257 */ 258 enum RegisterBinding { 259 /** 260 * Interval is bound to a specific register as required by the platform. 261 */ 262 Fixed, 263 264 /** 265 * Interval has no specific register requirements. 266 */ 267 Any, 268 269 /** 270 * Interval is bound to a stack slot. 271 */ 272 Stack; 273 274 public static final RegisterBinding[] VALUES = values(); 275 } 276 277 /** 278 * Constants denoting the linear-scan states an interval may be in with respect to the 279 * {@linkplain Interval#from() start} {@code position} of the interval being processed. 280 */ 281 enum State { 282 /** 283 * An interval that starts after {@code position}. 284 */ 285 Unhandled, 286 287 /** 288 * An interval that {@linkplain Interval#covers covers} {@code position} and has an assigned 289 * register. 290 */ 291 Active, 292 293 /** 294 * An interval that starts before and ends after {@code position} but does not 295 * {@linkplain Interval#covers cover} it due to a lifetime hole. 296 */ 297 Inactive, 298 299 /** 300 * An interval that ends before {@code position} or is spilled to memory. 301 */ 302 Handled; 303 } 304 305 /** 306 * Constants used in optimization of spilling of an interval. 307 */ 308 public enum SpillState { 309 /** 310 * Starting state of calculation: no definition found yet. 311 */ 312 NoDefinitionFound, 313 314 /** 315 * One definition has already been found. Two consecutive definitions are treated as one 316 * (e.g. a consecutive move and add because of two-operand LIR form). The position of this 317 * definition is given by {@link Interval#spillDefinitionPos()}. 318 */ 319 NoSpillStore, 320 321 /** 322 * One spill move has already been inserted. 323 */ 324 OneSpillStore, 325 326 /** 327 * The interval is spilled multiple times or is spilled in a loop. Place the store somewhere 328 * on the dominator path between the definition and the usages. 329 */ 330 SpillInDominator, 331 332 /** 333 * The interval should be stored immediately after its definition to prevent multiple 334 * redundant stores. 335 */ 336 StoreAtDefinition, 337 338 /** 339 * The interval starts in memory (e.g. method parameter), so a store is never necessary. 340 */ 341 StartInMemory, 342 343 /** 344 * The interval has more than one definition (e.g. resulting from phi moves), so stores to 345 * memory are not optimized. 346 */ 347 NoOptimization; 348 349 public static final EnumSet<SpillState> ALWAYS_IN_MEMORY = EnumSet.of(SpillInDominator, StoreAtDefinition, StartInMemory); 350 } 351 352 /** 353 * List of use positions. Each entry in the list records the use position and register priority 354 * associated with the use position. The entries in the list are in descending order of use 355 * position. 356 * 357 */ 358 public static final class UsePosList { 359 360 private IntList list; 361 362 /** 363 * Creates a use list. 364 * 365 * @param initialCapacity the initial capacity of the list in terms of entries 366 */ 367 public UsePosList(int initialCapacity) { 368 list = new IntList(initialCapacity * 2); 369 } 370 371 private UsePosList(IntList list) { 372 this.list = list; 373 } 374 375 /** 376 * Splits this list around a given position. All entries in this list with a use position 377 * greater or equal than {@code splitPos} are removed from this list and added to the 378 * returned list. 379 * 380 * @param splitPos the position for the split 381 * @return a use position list containing all entries removed from this list that have a use 382 * position greater or equal than {@code splitPos} 383 */ 384 public UsePosList splitAt(int splitPos) { 385 int i = size() - 1; 386 int len = 0; 387 while (i >= 0 && usePos(i) < splitPos) { 388 --i; 389 len += 2; 390 } 391 int listSplitIndex = (i + 1) * 2; 392 IntList childList = list; 393 list = IntList.copy(this.list, listSplitIndex, len); 394 childList.setSize(listSplitIndex); 395 UsePosList child = new UsePosList(childList); 396 return child; 397 } 398 399 /** 400 * Gets the use position at a specified index in this list. 401 * 402 * @param index the index of the entry for which the use position is returned 403 * @return the use position of entry {@code index} in this list 404 */ 405 public int usePos(int index) { 406 return list.get(index << 1); 407 } 408 409 /** 410 * Gets the register priority for the use position at a specified index in this list. 411 * 412 * @param index the index of the entry for which the register priority is returned 413 * @return the register priority of entry {@code index} in this list 414 */ 415 public RegisterPriority registerPriority(int index) { 416 return RegisterPriority.VALUES[list.get((index << 1) + 1)]; 417 } 418 419 public void add(int usePos, RegisterPriority registerPriority) { 420 assert list.size() == 0 || usePos(size() - 1) > usePos; 421 list.add(usePos); 422 list.add(registerPriority.ordinal()); 423 } 424 425 public int size() { 426 return list.size() >> 1; 427 } 428 429 public void removeLowestUsePos() { 430 list.setSize(list.size() - 2); 431 } 432 433 public void setRegisterPriority(int index, RegisterPriority registerPriority) { 434 list.set((index << 1) + 1, registerPriority.ordinal()); 435 } 436 437 @Override 438 public String toString() { 439 StringBuilder buf = new StringBuilder("["); 440 for (int i = size() - 1; i >= 0; --i) { 441 if (buf.length() != 1) { 442 buf.append(", "); 443 } 444 RegisterPriority prio = registerPriority(i); 445 buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio); 446 } 447 return buf.append("]").toString(); 448 } 449 } 450 451 /** 452 * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval 453 * prior to register allocation. 454 */ 455 public final AllocatableValue operand; 456 457 /** 458 * The operand number for this interval's {@linkplain #operand operand}. 459 */ 460 public final int operandNumber; 461 462 /** 463 * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this 464 * interval. In case of a spilled interval which is re-materialized this is 465 * {@link Value#ILLEGAL}. 466 */ 467 private AllocatableValue location; 468 469 /** 470 * The stack slot to which all splits of this interval are spilled if necessary. 471 */ 472 private AllocatableValue spillSlot; 473 474 /** 475 * The kind of this interval. 476 */ 477 private ValueKind<?> kind; 478 479 /** 480 * The head of the list of ranges describing this interval. This list is sorted by 481 * {@linkplain LIRInstruction#id instruction ids}. 482 */ 483 private Range first; 484 485 /** 486 * List of (use-positions, register-priorities) pairs, sorted by use-positions. 487 */ 488 private UsePosList usePosList; 489 490 /** 491 * Iterator used to traverse the ranges of an interval. 492 */ 493 private Range current; 494 495 /** 496 * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}. 497 */ 498 Interval next; 499 500 /** 501 * The linear-scan state of this interval. 502 */ 503 State state; 504 505 private int cachedTo; // cached value: to of last range (-1: not cached) 506 507 /** 508 * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split 509 * parent}, it points to itself. 510 */ 511 private Interval splitParent; 512 513 /** 514 * List of all intervals that are split off from this interval. This is only used if this is a 515 * {@linkplain #isSplitParent() split parent}. 516 */ 517 private List<Interval> splitChildren = Collections.emptyList(); 518 519 /** 520 * Current split child that has been active or inactive last (always stored in split parents). 521 */ 522 private Interval currentSplitChild; 523 524 /** 525 * Specifies if move is inserted between currentSplitChild and this interval when interval gets 526 * active the first time. 527 */ 528 private boolean insertMoveWhenActivated; 529 530 /** 531 * For spill move optimization. 532 */ 533 private SpillState spillState; 534 535 /** 536 * Position where this interval is defined (if defined only once). 537 */ 538 private int spillDefinitionPos; 539 540 /** 541 * This interval should be assigned the same location as the hint interval. 542 */ 543 private Interval locationHint; 544 545 /** 546 * The value with which a spilled child interval can be re-materialized. Currently this must be 547 * a Constant. 548 */ 549 private Constant materializedValue; 550 551 /** 552 * The number of times {@link #addMaterializationValue(Constant)} is called. 553 */ 554 private int numMaterializationValuesAdded; 555 556 void assignLocation(AllocatableValue newLocation) { 557 if (isRegister(newLocation)) { 558 assert this.location == null : "cannot re-assign location for " + this; 559 if (newLocation.getValueKind().equals(LIRKind.Illegal) && !kind.equals(LIRKind.Illegal)) { 560 this.location = asRegister(newLocation).asValue(kind); 561 return; 562 } 563 } else if (isIllegal(newLocation)) { 564 assert canMaterialize(); 565 } else { 566 assert this.location == null || isRegister(this.location) || (isVirtualStackSlot(this.location) && isStackSlot(newLocation)) : "cannot re-assign location for " + this; 567 assert isStackSlotValue(newLocation); 568 assert !newLocation.getValueKind().equals(LIRKind.Illegal); 569 assert newLocation.getValueKind().equals(this.kind); 570 } 571 this.location = newLocation; 572 } 573 574 /** 575 * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to 576 * this interval. 577 */ 578 public AllocatableValue location() { 579 return location; 580 } 581 582 public ValueKind<?> kind() { 583 assert !isRegister(operand) : "cannot access type for fixed interval"; 584 return kind; 585 } 586 587 public void setKind(ValueKind<?> kind) { 588 assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type"; 589 this.kind = kind; 590 } 591 592 public Range first() { 593 return first; 594 } 595 596 public int from() { 597 return first.from; 598 } 599 600 int to() { 601 if (cachedTo == -1) { 602 cachedTo = calcTo(); 603 } 604 assert cachedTo == calcTo() : "invalid cached value"; 605 return cachedTo; 606 } 607 608 int numUsePositions() { 609 return usePosList.size(); 610 } 611 612 public void setLocationHint(Interval interval) { 613 locationHint = interval; 614 } 615 616 public boolean isSplitParent() { 617 return splitParent == this; 618 } 619 620 boolean isSplitChild() { 621 return splitParent != this; 622 } 623 624 /** 625 * Gets the split parent for this interval. 626 */ 627 public Interval splitParent() { 628 assert splitParent.isSplitParent() : "not a split parent: " + this; 629 return splitParent; 630 } 631 632 /** 633 * Gets the canonical spill slot for this interval. 634 */ 635 public AllocatableValue spillSlot() { 636 return splitParent().spillSlot; 637 } 638 639 public void setSpillSlot(AllocatableValue slot) { 640 assert isStackSlotValue(slot); 641 assert splitParent().spillSlot == null || (isVirtualStackSlot(splitParent().spillSlot) && isStackSlot(slot)) : "connot overwrite existing spill slot"; 642 splitParent().spillSlot = slot; 643 } 644 645 Interval currentSplitChild() { 646 return splitParent().currentSplitChild; 647 } 648 649 void makeCurrentSplitChild() { 650 splitParent().currentSplitChild = this; 651 } 652 653 boolean insertMoveWhenActivated() { 654 return insertMoveWhenActivated; 655 } 656 657 void setInsertMoveWhenActivated(boolean b) { 658 insertMoveWhenActivated = b; 659 } 660 661 // for spill optimization 662 public SpillState spillState() { 663 return splitParent().spillState; 664 } 665 666 public int spillDefinitionPos() { 667 return splitParent().spillDefinitionPos; 668 } 669 670 public void setSpillState(SpillState state) { 671 assert state.ordinal() >= spillState().ordinal() : "state cannot decrease"; 672 splitParent().spillState = state; 673 } 674 675 public void setSpillDefinitionPos(int pos) { 676 assert spillState() == SpillState.SpillInDominator || spillState() == SpillState.NoDefinitionFound || spillDefinitionPos() == -1 : "cannot set the position twice"; 677 splitParent().spillDefinitionPos = pos; 678 } 679 680 // returns true if this interval has a shadow copy on the stack that is always correct 681 public boolean alwaysInMemory() { 682 return SpillState.ALWAYS_IN_MEMORY.contains(spillState()) && !canMaterialize(); 683 } 684 685 void removeFirstUsePos() { 686 usePosList.removeLowestUsePos(); 687 } 688 689 // test intersection 690 boolean intersects(Interval i) { 691 return first.intersects(i.first); 692 } 693 694 int intersectsAt(Interval i) { 695 return first.intersectsAt(i.first); 696 } 697 698 // range iteration 699 void rewindRange() { 700 current = first; 701 } 702 703 void nextRange() { 704 assert this != EndMarker : "not allowed on sentinel"; 705 current = current.next; 706 } 707 708 int currentFrom() { 709 return current.from; 710 } 711 712 int currentTo() { 713 return current.to; 714 } 715 716 boolean currentAtEnd() { 717 return current == Range.EndMarker; 718 } 719 720 boolean currentIntersects(Interval it) { 721 return current.intersects(it.current); 722 } 723 724 int currentIntersectsAt(Interval it) { 725 return current.intersectsAt(it.current); 726 } 727 728 /** 729 * Sentinel interval to denote the end of an interval list. 730 */ 731 static final Interval EndMarker = new Interval(Value.ILLEGAL, -1); 732 733 Interval(AllocatableValue operand, int operandNumber) { 734 assert operand != null; 735 this.operand = operand; 736 this.operandNumber = operandNumber; 737 if (isRegister(operand)) { 738 location = operand; 739 } else { 740 assert isIllegal(operand) || isVariable(operand); 741 } 742 this.kind = LIRKind.Illegal; 743 this.first = Range.EndMarker; 744 this.usePosList = new UsePosList(4); 745 this.current = Range.EndMarker; 746 this.next = EndMarker; 747 this.cachedTo = -1; 748 this.spillState = SpillState.NoDefinitionFound; 749 this.spillDefinitionPos = -1; 750 splitParent = this; 751 currentSplitChild = this; 752 } 753 754 /** 755 * Sets the value which is used for re-materialization. 756 */ 757 public void addMaterializationValue(Constant value) { 758 if (numMaterializationValuesAdded == 0) { 759 materializedValue = value; 760 } else { 761 // Interval is defined on multiple places -> no materialization is possible. 762 materializedValue = null; 763 } 764 numMaterializationValuesAdded++; 765 } 766 767 /** 768 * Returns true if this interval can be re-materialized when spilled. This means that no 769 * spill-moves are needed. Instead of restore-moves the {@link #materializedValue} is restored. 770 */ 771 public boolean canMaterialize() { 772 return getMaterializedValue() != null; 773 } 774 775 /** 776 * Returns a value which can be moved to a register instead of a restore-move from stack. 777 */ 778 public Constant getMaterializedValue() { 779 return splitParent().materializedValue; 780 } 781 782 int calcTo() { 783 assert first != Range.EndMarker : "interval has no range"; 784 785 Range r = first; 786 while (r.next != Range.EndMarker) { 787 r = r.next; 788 } 789 return r.to; 790 } 791 792 // consistency check of split-children 793 boolean checkSplitChildren() { 794 if (!splitChildren.isEmpty()) { 795 assert isSplitParent() : "only split parents can have children"; 796 797 for (int i = 0; i < splitChildren.size(); i++) { 798 Interval i1 = splitChildren.get(i); 799 800 assert i1.splitParent() == this : "not a split child of this interval"; 801 assert i1.kind().equals(kind()) : "must be equal for all split children"; 802 assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children"; 803 804 for (int j = i + 1; j < splitChildren.size(); j++) { 805 Interval i2 = splitChildren.get(j); 806 807 assert !i1.operand.equals(i2.operand) : "same register number"; 808 809 if (i1.from() < i2.from()) { 810 assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping"; 811 } else { 812 assert i2.from() < i1.from() : "intervals start at same opId"; 813 assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping"; 814 } 815 } 816 } 817 } 818 819 return true; 820 } 821 822 public Interval locationHint(boolean searchSplitChild) { 823 if (!searchSplitChild) { 824 return locationHint; 825 } 826 827 if (locationHint != null) { 828 assert locationHint.isSplitParent() : "ony split parents are valid hint registers"; 829 830 if (locationHint.location != null && isRegister(locationHint.location)) { 831 return locationHint; 832 } else if (!locationHint.splitChildren.isEmpty()) { 833 // search the first split child that has a register assigned 834 int len = locationHint.splitChildren.size(); 835 for (int i = 0; i < len; i++) { 836 Interval interval = locationHint.splitChildren.get(i); 837 if (interval.location != null && isRegister(interval.location)) { 838 return interval; 839 } 840 } 841 } 842 } 843 844 // no hint interval found that has a register assigned 845 return null; 846 } 847 848 Interval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, LinearScan allocator) { 849 assert isSplitParent() : "can only be called for split parents"; 850 assert opId >= 0 : "invalid opId (method cannot be called for spill moves)"; 851 852 if (splitChildren.isEmpty()) { 853 assert this.covers(opId, mode) : this + " does not cover " + opId; 854 return this; 855 } else { 856 Interval result = null; 857 int len = splitChildren.size(); 858 859 // in outputMode, the end of the interval (opId == cur.to()) is not valid 860 int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1); 861 862 int i; 863 for (i = 0; i < len; i++) { 864 Interval cur = splitChildren.get(i); 865 if (cur.from() <= opId && opId < cur.to() + toOffset) { 866 if (i > 0) { 867 // exchange current split child to start of list (faster access for next 868 // call) 869 Util.atPutGrow(splitChildren, i, splitChildren.get(0), null); 870 Util.atPutGrow(splitChildren, 0, cur, null); 871 } 872 873 // interval found 874 result = cur; 875 break; 876 } 877 } 878 879 assert checkSplitChild(result, opId, allocator, toOffset, mode); 880 return result; 881 } 882 } 883 884 private boolean checkSplitChild(Interval result, int opId, LinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) { 885 if (result == null) { 886 // this is an error 887 StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId); 888 if (!splitChildren.isEmpty()) { 889 Interval firstChild = splitChildren.get(0); 890 Interval lastChild = splitChildren.get(splitChildren.size() - 1); 891 msg.append(" (first = ").append(firstChild).append(", last = ").append(lastChild).append(")"); 892 } 893 throw new GraalError("Linear Scan Error: %s", msg); 894 } 895 896 if (!splitChildren.isEmpty()) { 897 for (Interval interval : splitChildren) { 898 if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) { 899 /* 900 * Should not happen: Try another compilation as it is very unlikely to happen 901 * again. 902 */ 903 throw new GraalError("two valid result intervals found for opId %d: %d and %d\n%s\n", opId, result.operandNumber, interval.operandNumber, 904 result.logString(allocator), interval.logString(allocator)); 905 } 906 } 907 } 908 assert result.covers(opId, mode) : "opId not covered by interval"; 909 return true; 910 } 911 912 // returns the interval that covers the given opId or null if there is none 913 Interval getIntervalCoveringOpId(int opId) { 914 assert opId >= 0 : "invalid opId"; 915 assert opId < to() : "can only look into the past"; 916 917 if (opId >= from()) { 918 return this; 919 } 920 921 Interval parent = splitParent(); 922 Interval result = null; 923 924 assert !parent.splitChildren.isEmpty() : "no split children available"; 925 int len = parent.splitChildren.size(); 926 927 for (int i = len - 1; i >= 0; i--) { 928 Interval cur = parent.splitChildren.get(i); 929 if (cur.from() <= opId && opId < cur.to()) { 930 assert result == null : "covered by multiple split children " + result + " and " + cur; 931 result = cur; 932 } 933 } 934 935 return result; 936 } 937 938 // returns the last split child that ends before the given opId 939 Interval getSplitChildBeforeOpId(int opId) { 940 assert opId >= 0 : "invalid opId"; 941 942 Interval parent = splitParent(); 943 Interval result = null; 944 945 assert !parent.splitChildren.isEmpty() : "no split children available"; 946 int len = parent.splitChildren.size(); 947 948 for (int i = len - 1; i >= 0; i--) { 949 Interval cur = parent.splitChildren.get(i); 950 if (cur.to() <= opId && (result == null || result.to() < cur.to())) { 951 result = cur; 952 } 953 } 954 955 assert result != null : "no split child found"; 956 return result; 957 } 958 959 // checks if opId is covered by any split child 960 boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) { 961 assert isSplitParent() : "can only be called for split parents"; 962 assert opId >= 0 : "invalid opId (method can not be called for spill moves)"; 963 964 if (splitChildren.isEmpty()) { 965 // simple case if interval was not split 966 return covers(opId, mode); 967 968 } else { 969 // extended case: check all split children 970 int len = splitChildren.size(); 971 for (int i = 0; i < len; i++) { 972 Interval cur = splitChildren.get(i); 973 if (cur.covers(opId, mode)) { 974 return true; 975 } 976 } 977 return false; 978 } 979 } 980 981 private RegisterPriority adaptPriority(RegisterPriority priority) { 982 /* 983 * In case of re-materialized values we require that use-operands are registers, because we 984 * don't have the value in a stack location. (Note that ShouldHaveRegister means that the 985 * operand can also be a StackSlot). 986 */ 987 if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) { 988 return RegisterPriority.MustHaveRegister; 989 } 990 return priority; 991 } 992 993 // Note: use positions are sorted descending . first use has highest index 994 int firstUsage(RegisterPriority minRegisterPriority) { 995 assert isVariable(operand) : "cannot access use positions for fixed intervals"; 996 997 for (int i = usePosList.size() - 1; i >= 0; --i) { 998 RegisterPriority registerPriority = adaptPriority(usePosList.registerPriority(i)); 999 if (registerPriority.greaterEqual(minRegisterPriority)) { 1000 return usePosList.usePos(i); 1001 } 1002 } 1003 return Integer.MAX_VALUE; 1004 } 1005 1006 int nextUsage(RegisterPriority minRegisterPriority, int from) { 1007 assert isVariable(operand) : "cannot access use positions for fixed intervals"; 1008 1009 for (int i = usePosList.size() - 1; i >= 0; --i) { 1010 int usePos = usePosList.usePos(i); 1011 if (usePos >= from && adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) { 1012 return usePos; 1013 } 1014 } 1015 return Integer.MAX_VALUE; 1016 } 1017 1018 int nextUsageExact(RegisterPriority exactRegisterPriority, int from) { 1019 assert isVariable(operand) : "cannot access use positions for fixed intervals"; 1020 1021 for (int i = usePosList.size() - 1; i >= 0; --i) { 1022 int usePos = usePosList.usePos(i); 1023 if (usePos >= from && adaptPriority(usePosList.registerPriority(i)) == exactRegisterPriority) { 1024 return usePos; 1025 } 1026 } 1027 return Integer.MAX_VALUE; 1028 } 1029 1030 int previousUsage(RegisterPriority minRegisterPriority, int from) { 1031 assert isVariable(operand) : "cannot access use positions for fixed intervals"; 1032 1033 int prev = -1; 1034 for (int i = usePosList.size() - 1; i >= 0; --i) { 1035 int usePos = usePosList.usePos(i); 1036 if (usePos > from) { 1037 return prev; 1038 } 1039 if (adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) { 1040 prev = usePos; 1041 } 1042 } 1043 return prev; 1044 } 1045 1046 public void addUsePos(int pos, RegisterPriority registerPriority) { 1047 assert covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this); 1048 1049 // do not add use positions for precolored intervals because they are never used 1050 if (registerPriority != RegisterPriority.None && isVariable(operand)) { 1051 if (DetailedAsserts.getValue()) { 1052 for (int i = 0; i < usePosList.size(); i++) { 1053 assert pos <= usePosList.usePos(i) : "already added a use-position with lower position"; 1054 if (i > 0) { 1055 assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending"; 1056 } 1057 } 1058 } 1059 1060 // Note: addUse is called in descending order, so list gets sorted 1061 // automatically by just appending new use positions 1062 int len = usePosList.size(); 1063 if (len == 0 || usePosList.usePos(len - 1) > pos) { 1064 usePosList.add(pos, registerPriority); 1065 } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) { 1066 assert usePosList.usePos(len - 1) == pos : "list not sorted correctly"; 1067 usePosList.setRegisterPriority(len - 1, registerPriority); 1068 } 1069 } 1070 } 1071 1072 public void addRange(int from, int to) { 1073 assert from < to : "invalid range"; 1074 assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval"; 1075 assert from <= first().to : "not inserting at begin of interval"; 1076 1077 if (first.from <= to) { 1078 assert first != Range.EndMarker; 1079 // join intersecting ranges 1080 first.from = Math.min(from, first().from); 1081 first.to = Math.max(to, first().to); 1082 } else { 1083 // insert new range 1084 first = new Range(from, to, first()); 1085 } 1086 } 1087 1088 Interval newSplitChild(LinearScan allocator) { 1089 // allocate new interval 1090 Interval parent = splitParent(); 1091 Interval result = allocator.createDerivedInterval(parent); 1092 result.setKind(kind()); 1093 1094 result.splitParent = parent; 1095 result.setLocationHint(parent); 1096 1097 // insert new interval in children-list of parent 1098 if (parent.splitChildren.isEmpty()) { 1099 assert isSplitParent() : "list must be initialized at first split"; 1100 1101 // Create new non-shared list 1102 parent.splitChildren = new ArrayList<>(4); 1103 parent.splitChildren.add(this); 1104 } 1105 parent.splitChildren.add(result); 1106 1107 return result; 1108 } 1109 1110 /** 1111 * Splits this interval at a specified position and returns the remainder as a new <i>child</i> 1112 * interval of this interval's {@linkplain #splitParent() parent} interval. 1113 * <p> 1114 * When an interval is split, a bi-directional link is established between the original 1115 * <i>parent</i> interval and the <i>children</i> intervals that are split off this interval. 1116 * When a split child is split again, the new created interval is a direct child of the original 1117 * parent. That is, there is no tree of split children stored, just a flat list. All split 1118 * children are spilled to the same {@linkplain #spillSlot spill slot}. 1119 * 1120 * @param splitPos the position at which to split this interval 1121 * @param allocator the register allocator context 1122 * @return the child interval split off from this interval 1123 */ 1124 Interval split(int splitPos, LinearScan allocator) { 1125 assert isVariable(operand) : "cannot split fixed intervals"; 1126 1127 // allocate new interval 1128 Interval result = newSplitChild(allocator); 1129 1130 // split the ranges 1131 Range prev = null; 1132 Range cur = first; 1133 while (cur != Range.EndMarker && cur.to <= splitPos) { 1134 prev = cur; 1135 cur = cur.next; 1136 } 1137 assert cur != Range.EndMarker : "split interval after end of last range"; 1138 1139 if (cur.from < splitPos) { 1140 result.first = new Range(splitPos, cur.to, cur.next); 1141 cur.to = splitPos; 1142 cur.next = Range.EndMarker; 1143 1144 } else { 1145 assert prev != null : "split before start of first range"; 1146 result.first = cur; 1147 prev.next = Range.EndMarker; 1148 } 1149 result.current = result.first; 1150 cachedTo = -1; // clear cached value 1151 1152 // split list of use positions 1153 result.usePosList = usePosList.splitAt(splitPos); 1154 1155 if (DetailedAsserts.getValue()) { 1156 for (int i = 0; i < usePosList.size(); i++) { 1157 assert usePosList.usePos(i) < splitPos; 1158 } 1159 for (int i = 0; i < result.usePosList.size(); i++) { 1160 assert result.usePosList.usePos(i) >= splitPos; 1161 } 1162 } 1163 return result; 1164 } 1165 1166 /** 1167 * Splits this interval at a specified position and returns the head as a new interval (this 1168 * interval is the tail). 1169 * 1170 * Currently, only the first range can be split, and the new interval must not have split 1171 * positions 1172 */ 1173 Interval splitFromStart(int splitPos, LinearScan allocator) { 1174 assert isVariable(operand) : "cannot split fixed intervals"; 1175 assert splitPos > from() && splitPos < to() : "can only split inside interval"; 1176 assert splitPos > first.from && splitPos <= first.to : "can only split inside first range"; 1177 assert firstUsage(RegisterPriority.None) > splitPos : "can not split when use positions are present"; 1178 1179 // allocate new interval 1180 Interval result = newSplitChild(allocator); 1181 1182 // the new interval has only one range (checked by assertion above, 1183 // so the splitting of the ranges is very simple 1184 result.addRange(first.from, splitPos); 1185 1186 if (splitPos == first.to) { 1187 assert first.next != Range.EndMarker : "must not be at end"; 1188 first = first.next; 1189 } else { 1190 first.from = splitPos; 1191 } 1192 1193 return result; 1194 } 1195 1196 // returns true if the opId is inside the interval 1197 boolean covers(int opId, LIRInstruction.OperandMode mode) { 1198 Range cur = first; 1199 1200 while (cur != Range.EndMarker && cur.to < opId) { 1201 cur = cur.next; 1202 } 1203 if (cur != Range.EndMarker) { 1204 assert cur.to != cur.next.from : "ranges not separated"; 1205 1206 if (mode == LIRInstruction.OperandMode.DEF) { 1207 return cur.from <= opId && opId < cur.to; 1208 } else { 1209 return cur.from <= opId && opId <= cur.to; 1210 } 1211 } 1212 return false; 1213 } 1214 1215 // returns true if the interval has any hole between holeFrom and holeTo 1216 // (even if the hole has only the length 1) 1217 boolean hasHoleBetween(int holeFrom, int holeTo) { 1218 assert holeFrom < holeTo : "check"; 1219 assert from() <= holeFrom && holeTo <= to() : "index out of interval"; 1220 1221 Range cur = first; 1222 while (cur != Range.EndMarker) { 1223 assert cur.to < cur.next.from : "no space between ranges"; 1224 1225 // hole-range starts before this range . hole 1226 if (holeFrom < cur.from) { 1227 return true; 1228 1229 // hole-range completely inside this range . no hole 1230 } else { 1231 if (holeTo <= cur.to) { 1232 return false; 1233 1234 // overlapping of hole-range with this range . hole 1235 } else { 1236 if (holeFrom <= cur.to) { 1237 return true; 1238 } 1239 } 1240 } 1241 1242 cur = cur.next; 1243 } 1244 1245 return false; 1246 } 1247 1248 @Override 1249 public String toString() { 1250 String from = "?"; 1251 String to = "?"; 1252 if (first != null && first != Range.EndMarker) { 1253 from = String.valueOf(from()); 1254 // to() may cache a computed value, modifying the current object, which is a bad idea 1255 // for a printing function. Compute it directly instead. 1256 to = String.valueOf(calcTo()); 1257 } 1258 String locationString = this.location == null ? "" : "@" + this.location; 1259 return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]"; 1260 } 1261 1262 /** 1263 * Gets the use position information for this interval. 1264 */ 1265 public UsePosList usePosList() { 1266 return usePosList; 1267 } 1268 1269 /** 1270 * Gets a single line string for logging the details of this interval to a log stream. 1271 * 1272 * @param allocator the register allocator context 1273 */ 1274 public String logString(LinearScan allocator) { 1275 StringBuilder buf = new StringBuilder(100); 1276 buf.append(operandNumber).append(':').append(operand).append(' '); 1277 if (!isRegister(operand)) { 1278 if (location != null) { 1279 buf.append("location{").append(location).append("} "); 1280 } 1281 } 1282 1283 buf.append("hints{").append(splitParent.operandNumber); 1284 Interval hint = locationHint(false); 1285 if (hint != null && hint.operandNumber != splitParent.operandNumber) { 1286 buf.append(", ").append(hint.operandNumber); 1287 } 1288 buf.append("} ranges{"); 1289 1290 // print ranges 1291 Range cur = first; 1292 while (cur != Range.EndMarker) { 1293 if (cur != first) { 1294 buf.append(", "); 1295 } 1296 buf.append(cur); 1297 cur = cur.next; 1298 assert cur != null : "range list not closed with range sentinel"; 1299 } 1300 buf.append("} uses{"); 1301 1302 // print use positions 1303 int prev = -1; 1304 for (int i = usePosList.size() - 1; i >= 0; --i) { 1305 assert prev < usePosList.usePos(i) : "use positions not sorted"; 1306 if (i != usePosList.size() - 1) { 1307 buf.append(", "); 1308 } 1309 buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i)); 1310 prev = usePosList.usePos(i); 1311 } 1312 buf.append("} spill-state{").append(spillState()).append("}"); 1313 if (canMaterialize()) { 1314 buf.append(" (remat:").append(getMaterializedValue().toString()).append(")"); 1315 } 1316 return buf.toString(); 1317 } 1318 1319 List<Interval> getSplitChildren() { 1320 return Collections.unmodifiableList(splitChildren); 1321 } 1322 }