001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.compilers.opt.regalloc; 014 015 import java.lang.reflect.Constructor; 016 import java.util.ArrayList; 017 import java.util.Comparator; 018 import java.util.Enumeration; 019 import java.util.HashMap; 020 import java.util.HashSet; 021 import java.util.Iterator; 022 import java.util.Map; 023 import java.util.SortedSet; 024 import java.util.TreeSet; 025 026 import org.jikesrvm.VM; 027 import org.jikesrvm.ArchitectureSpecificOpt.PhysicalRegisterConstants; 028 import org.jikesrvm.ArchitectureSpecificOpt.PhysicalRegisterSet; 029 import org.jikesrvm.ArchitectureSpecificOpt.RegisterRestrictions; 030 import org.jikesrvm.ArchitectureSpecificOpt.StackManager; 031 import org.jikesrvm.compilers.opt.OptOptions; 032 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 033 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 034 import org.jikesrvm.compilers.opt.driver.OptimizationPlanAtomicElement; 035 import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement; 036 import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 037 import org.jikesrvm.compilers.opt.ir.BasicBlock; 038 import org.jikesrvm.compilers.opt.ir.ControlFlowGraph; 039 import org.jikesrvm.compilers.opt.ir.GCIRMapElement; 040 import org.jikesrvm.compilers.opt.ir.IR; 041 import org.jikesrvm.compilers.opt.ir.Instruction; 042 import org.jikesrvm.compilers.opt.ir.Operators; 043 import org.jikesrvm.compilers.opt.ir.RegSpillListElement; 044 import org.jikesrvm.compilers.opt.ir.Register; 045 import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 046 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 047 import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 048 import org.jikesrvm.compilers.opt.ir.operand.Operand; 049 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 050 import org.jikesrvm.compilers.opt.util.GraphEdge; 051 import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode; 052 import org.jikesrvm.osr.OSRConstants; 053 import org.jikesrvm.osr.LocalRegPair; 054 import org.jikesrvm.osr.MethodVariables; 055 import org.jikesrvm.osr.VariableMapElement; 056 import org.vmmagic.unboxed.Word; 057 058 /** 059 * Main driver for linear scan register allocation. 060 */ 061 public final class LinearScan extends OptimizationPlanCompositeElement { 062 063 /** 064 * Build this phase as a composite of others. 065 */ 066 LinearScan() { 067 super("Linear Scan Composite Phase", 068 new OptimizationPlanElement[]{new OptimizationPlanAtomicElement(new IntervalAnalysis()), 069 new OptimizationPlanAtomicElement(new RegisterRestrictionsPhase()), 070 new OptimizationPlanAtomicElement(new LinearScanPhase()), 071 new OptimizationPlanAtomicElement(new UpdateGCMaps1()), 072 new OptimizationPlanAtomicElement(new SpillCode()), 073 new OptimizationPlanAtomicElement(new UpdateGCMaps2()), 074 new OptimizationPlanAtomicElement(new UpdateOSRMaps()),}); 075 } 076 077 /** 078 * Mark FMOVs that end a live range? 079 */ 080 private static final boolean MUTATE_FMOV = VM.BuildForIA32; 081 082 /* 083 * debug flags 084 */ 085 private static final boolean DEBUG = false; 086 private static final boolean VERBOSE_DEBUG = false; 087 private static final boolean GC_DEBUG = false; 088 private static final boolean DEBUG_COALESCE = false; 089 090 /** 091 * Register allocation is required 092 */ 093 @Override 094 public boolean shouldPerform(OptOptions options) { 095 return true; 096 } 097 098 @Override 099 public String getName() { 100 return "Linear Scan Composite Phase"; 101 } 102 103 @Override 104 public boolean printingEnabled(OptOptions options, boolean before) { 105 return false; 106 } 107 108 /** 109 * Associates the passed live interval with the passed register, using 110 * the scratchObject field of Register. 111 * 112 * @param reg the register 113 * @param interval the live interval 114 */ 115 static void setInterval(Register reg, CompoundInterval interval) { 116 reg.scratchObject = interval; 117 } 118 119 /** 120 * Returns the interval associated with the passed register. 121 * @param reg the register 122 * @return the live interval or {@code null} 123 */ 124 static CompoundInterval getInterval(Register reg) { 125 return (CompoundInterval) reg.scratchObject; 126 } 127 128 /** 129 * returns the dfn associated with the passed instruction 130 * @param inst the instruction 131 * @return the associated dfn 132 */ 133 static int getDFN(Instruction inst) { 134 return inst.scratch; 135 } 136 137 /** 138 * Associates the passed dfn number with the instruction 139 * @param inst the instruction 140 * @param dfn the dfn number 141 */ 142 static void setDFN(Instruction inst, int dfn) { 143 inst.scratch = dfn; 144 } 145 146 /** 147 * Print the DFN numbers associated with each instruction 148 */ 149 static void printDfns(IR ir) { 150 System.out.println("DFNS: **** " + ir.getMethod() + "****"); 151 for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst = 152 inst.nextInstructionInCodeOrder()) { 153 System.out.println(getDFN(inst) + " " + inst); 154 } 155 } 156 157 /** 158 * Return the Depth-first-number of the end of the live interval. 159 * Return the dfn for the end of the basic block if the interval is 160 * open-ended. 161 */ 162 static int getDfnEnd(LiveIntervalElement live, BasicBlock bb) { 163 Instruction end = live.getEnd(); 164 int dfnEnd; 165 if (end != null) { 166 dfnEnd = getDFN(end); 167 } else { 168 dfnEnd = getDFN(bb.lastInstruction()); 169 } 170 return dfnEnd; 171 } 172 173 /** 174 * Return the Depth-first-number of the beginning of the live interval. 175 * Return the dfn for the beginning of the basic block if the interval is 176 * open-ended. 177 */ 178 static int getDfnBegin(LiveIntervalElement live, BasicBlock bb) { 179 Instruction begin = live.getBegin(); 180 int dfnBegin; 181 if (begin != null) { 182 dfnBegin = getDFN(begin); 183 } else { 184 dfnBegin = getDFN(bb.firstInstruction()); 185 } 186 return dfnBegin; 187 } 188 189 public static final class LinearScanState { 190 /** 191 * The live interval information, a set of Basic Intervals 192 * sorted by increasing start point 193 */ 194 public final ArrayList<BasicInterval> intervals = new ArrayList<BasicInterval>(); 195 196 /** 197 * Was any register spilled? 198 */ 199 public boolean spilledSomething = false; 200 201 /** 202 * Analysis information used by linear scan. 203 */ 204 public ActiveSet active; 205 } 206 207 /** 208 * A phase to compute register restrictions. 209 */ 210 static final class RegisterRestrictionsPhase extends CompilerPhase { 211 212 /** 213 * Return this instance of this phase. This phase contains no 214 * per-compilation instance fields. 215 * @param ir not used 216 * @return this 217 */ 218 @Override 219 public CompilerPhase newExecution(IR ir) { 220 return this; 221 } 222 223 @Override 224 public boolean shouldPerform(OptOptions options) { 225 return true; 226 } 227 228 @Override 229 public String getName() { 230 return "Register Restrictions"; 231 } 232 233 @Override 234 public boolean printingEnabled(OptOptions options, boolean before) { 235 return false; 236 } 237 238 /** 239 * @param ir the IR 240 */ 241 @Override 242 public void perform(IR ir) { 243 244 // The registerManager has already been initialized 245 GenericStackManager sm = ir.stackManager; 246 247 // Set up register restrictions 248 sm.computeRestrictions(ir); 249 } 250 } 251 252 public static final class LinearScanPhase extends CompilerPhase 253 implements PhysicalRegisterConstants, Operators { 254 255 /** 256 * An object which manages spill location assignments. 257 */ 258 private SpillLocationManager spillManager; 259 260 /** 261 * The governing IR 262 * Also used by ClassWriter 263 */ 264 public IR ir; 265 266 /** 267 * Constructor for this compiler phase 268 */ 269 private static final Constructor<CompilerPhase> constructor = getCompilerPhaseConstructor(LinearScanPhase.class); 270 271 /** 272 * Get a constructor object for this compiler phase 273 * @return compiler phase constructor 274 */ 275 @Override 276 public Constructor<CompilerPhase> getClassConstructor() { 277 return constructor; 278 } 279 280 /** 281 * Register allocation is required 282 */ 283 @Override 284 public boolean shouldPerform(OptOptions options) { 285 return true; 286 } 287 288 @Override 289 public String getName() { 290 return "Linear Scan"; 291 } 292 293 @Override 294 public boolean printingEnabled(OptOptions options, boolean before) { 295 return false; 296 } 297 298 /** 299 * Perform the linear scan register allocation algorithm.<p> 300 * 301 * See TOPLAS 21(5), Sept 1999, p 895-913 302 * @param ir the IR 303 */ 304 @Override 305 public void perform(IR ir) { 306 307 this.ir = ir; 308 309 // The registerManager has already been initialized 310 //GenericStackManager sm = ir.stackManager; 311 312 // Get register restrictions 313 // RegisterRestrictions restrict = sm.getRestrictions(); - unused 314 315 // Create the object that manages spill locations 316 spillManager = new SpillLocationManager(ir); 317 318 // Create an (empty) set of active intervals. 319 ActiveSet active = new ActiveSet(ir, spillManager); 320 ir.MIRInfo.linearScanState.active = active; 321 322 // Intervals sorted by increasing start point 323 for (BasicInterval b : ir.MIRInfo.linearScanState.intervals) { 324 325 MappedBasicInterval bi = (MappedBasicInterval) b; 326 CompoundInterval ci = bi.container; 327 328 active.expireOldIntervals(bi); 329 330 // If the interval does not correspond to a physical register 331 // then we process it. 332 if (!ci.getRegister().isPhysical()) { 333 // Update register allocation based on the new interval. 334 active.allocate(bi, ci); 335 } else { 336 // Mark the physical register as currently allocated. 337 ci.getRegister().allocateRegister(); 338 } 339 active.add(bi); 340 } 341 342 // update the state. 343 if (active.spilledSomething()) { 344 ir.MIRInfo.linearScanState.spilledSomething = true; 345 } 346 } 347 } 348 349 /** 350 * Implements a basic live interval (no holes), which is a pair 351 * <pre> 352 * begin - the starting point of the interval 353 * end - the ending point of the interval 354 * </pre> 355 * 356 * <p> Begin and end are numbers given to each instruction by a numbering pass. 357 */ 358 static class BasicInterval { 359 360 /** 361 * DFN of the beginning instruction of this interval 362 */ 363 private final int begin; 364 /** 365 * DFN of the last instruction of this interval 366 */ 367 private int end; 368 369 /** 370 * Default constructor. 371 */ 372 BasicInterval(int begin, int end) { 373 this.begin = begin; 374 this.end = end; 375 } 376 377 /** 378 * @return the DFN signifying the beginning of this basic interval 379 */ 380 final int getBegin() { 381 return begin; 382 } 383 384 /** 385 * @return the DFN signifying the end of this basic interval 386 */ 387 final int getEnd() { 388 return end; 389 } 390 391 /** 392 * Extend a live interval to a new endpoint 393 */ 394 final void setEnd(int newEnd) { 395 end = newEnd; 396 } 397 398 /** 399 * Does this interval start after dfn? 400 * @param dfn the depth first numbering to compare to 401 */ 402 final boolean startsAfter(int dfn) { 403 return begin > dfn; 404 } 405 406 /** 407 * Does this interval start before dfn? 408 * @param dfn the depth first numbering to compare to 409 */ 410 final boolean startsBefore(int dfn) { 411 return begin < dfn; 412 } 413 414 /** 415 * Does this interval contain a dfn? 416 * @param dfn the depth first numbering to compare to 417 */ 418 final boolean contains(int dfn) { 419 return begin <= dfn && end >= dfn; 420 } 421 422 /** 423 * Does this interval start before another? 424 * @param i the interval to compare with 425 */ 426 final boolean startsBefore(BasicInterval i) { 427 return begin < i.begin; 428 } 429 430 /** 431 * Does this interval end after another? 432 * @param i the interval to compare with 433 */ 434 final boolean endsAfter(BasicInterval i) { 435 return end > i.end; 436 } 437 438 /** 439 * Does this interval represent the same range as another? 440 * @param i the interval to compare with 441 */ 442 final boolean sameRange(BasicInterval i) { 443 return begin == i.begin && end == i.end; 444 } 445 446 /** 447 * Redefine equals 448 */ 449 @Override 450 public boolean equals(Object o) { 451 if (!(o instanceof BasicInterval)) return false; 452 453 BasicInterval i = (BasicInterval) o; 454 return sameRange(i); 455 } 456 457 /** 458 * Does this interval end before dfn 459 * @param dfn the depth first numbering to compare to 460 */ 461 final boolean endsBefore(int dfn) { 462 return end < dfn; 463 } 464 465 /** 466 * Does this interval end after dfn 467 * @param dfn the depth first numbering to compare to 468 */ 469 final boolean endsAfter(int dfn) { 470 return end > dfn; 471 } 472 473 /** 474 * Does this interval intersect with another? 475 */ 476 final boolean intersects(BasicInterval i) { 477 int iBegin = i.getBegin(); 478 int iEnd = i.getEnd(); 479 return !(endsBefore(iBegin + 1) || startsAfter(iEnd - 1)); 480 } 481 482 /** 483 * Return a String representation 484 */ 485 @Override 486 public String toString() { 487 String s = "[ " + begin + ", " + end + " ] "; 488 return s; 489 } 490 } 491 492 /** 493 * A basic interval contained in a CompoundInterval. 494 */ 495 static class MappedBasicInterval extends BasicInterval { 496 final CompoundInterval container; 497 498 MappedBasicInterval(BasicInterval b, CompoundInterval c) { 499 super(b.begin, b.end); 500 this.container = c; 501 } 502 503 MappedBasicInterval(int begin, int end, CompoundInterval c) { 504 super(begin, end); 505 this.container = c; 506 } 507 508 /** 509 * Redefine equals 510 */ 511 @Override 512 public boolean equals(Object o) { 513 if (super.equals(o)) { 514 MappedBasicInterval i = (MappedBasicInterval) o; 515 return container == i.container; 516 } else { 517 return false; 518 } 519 } 520 521 @Override 522 public String toString() { 523 return "<" + container.getRegister() + ">:" + super.toString(); 524 } 525 526 } 527 528 /** 529 * Implements a live interval with holes; ie; a list of basic live 530 * intervals. 531 */ 532 static class CompoundInterval extends IncreasingStartIntervalSet { 533 /** Support for Set serialization */ 534 static final long serialVersionUID = 7423553044815762071L; 535 /** 536 * Is this compound interval fully contained in infrequent code? 537 */ 538 private boolean _infrequent = true; 539 540 final void setFrequent() { _infrequent = false; } 541 542 final boolean isInfrequent() { return _infrequent; } 543 544 /** 545 * The register this compound interval represents 546 */ 547 private final Register reg; 548 549 /** 550 * A spill location assigned for this interval. 551 */ 552 private SpillLocationInterval spillInterval; 553 554 SpillLocationInterval getSpillInterval() { return spillInterval; } 555 556 /** 557 * Return the register this interval represents 558 */ 559 Register getRegister() { 560 return reg; 561 } 562 563 /** 564 * Create a new compound interval of a single Basic interval 565 */ 566 CompoundInterval(int dfnBegin, int dfnEnd, Register register) { 567 BasicInterval newInterval = new MappedBasicInterval(dfnBegin, dfnEnd, this); 568 add(newInterval); 569 reg = register; 570 } 571 572 /** 573 * Create a new compound interval of a single Basic interval 574 */ 575 CompoundInterval(BasicInterval i, Register register) { 576 BasicInterval newInterval = new MappedBasicInterval(i.getBegin(), i.getEnd(), this); 577 add(newInterval); 578 reg = register; 579 } 580 581 /** 582 * Dangerous constructor: use with care. 583 */ 584 CompoundInterval(Register r) { 585 reg = r; 586 } 587 588 /** 589 * Copy the ranges into a new interval associated with a register r. 590 */ 591 CompoundInterval copy(Register r) { 592 CompoundInterval result = new CompoundInterval(r); 593 594 for (Iterator<BasicInterval> i = iterator(); i.hasNext();) { 595 BasicInterval b = i.next(); 596 result.add(b); 597 } 598 return result; 599 } 600 601 /** 602 * Copy the ranges into a new interval associated with a register r. 603 * Copy only the basic intervals up to and including stop. 604 */ 605 CompoundInterval copy(Register r, BasicInterval stop) { 606 CompoundInterval result = new CompoundInterval(r); 607 608 for (Iterator<BasicInterval> i = iterator(); i.hasNext();) { 609 BasicInterval b = i.next(); 610 result.add(b); 611 if (b.sameRange(stop)) return result; 612 } 613 return result; 614 } 615 616 /** 617 * Add a new live range to this compound interval. 618 * 619 * @param live the new live range 620 * @param bb the basic block for live 621 * @return the new basic interval if one was created; null otherwise 622 */ 623 BasicInterval addRange(LiveIntervalElement live, BasicBlock bb) { 624 625 if (shouldConcatenate(live, bb)) { 626 // concatenate with the last basic interval 627 BasicInterval last = last(); 628 last.setEnd(getDfnEnd(live, bb)); 629 return null; 630 } else { 631 // create a new basic interval and append it to the list. 632 BasicInterval newInterval = new MappedBasicInterval(getDfnBegin(live, bb), getDfnEnd(live, bb), this); 633 add(newInterval); 634 return newInterval; 635 } 636 } 637 638 /** 639 * Should we simply merge the live interval <code>live</code> into a 640 * previous BasicInterval? 641 * 642 * @param live the live interval being queried 643 * @param bb the basic block in which live resides. 644 */ 645 private boolean shouldConcatenate(LiveIntervalElement live, BasicBlock bb) { 646 647 BasicInterval last = last(); 648 649 // Make sure the new live range starts after the last basic interval 650 if (VM.VerifyAssertions) { 651 VM._assert(last.getEnd() <= getDfnBegin(live, bb)); 652 } 653 654 int dfnBegin = getDfnBegin(live, bb); 655 if (live.getBegin() != null) { 656 if (live.getBegin() == bb.firstRealInstruction()) { 657 // live starts the basic block. Now make sure it is contiguous 658 // with the last interval. 659 return last.getEnd() + 1 >= dfnBegin; 660 } else { 661 // live does not start the basic block. Merge with last iff 662 // last and live share an instruction. This happens when a 663 // register is def'ed and use'd in the same instruction. 664 return last.getEnd() == dfnBegin; 665 } 666 } else { 667 // live.getBegin == null. 668 // Merge if it is contiguous with the last interval. 669 int dBegin = getDFN(bb.firstInstruction()); 670 return last.getEnd() + 1 >= dBegin; 671 } 672 } 673 674 /** 675 * Assign this compound interval to a free spill location. 676 * 677 * @param spillManager governing spill location manager 678 */ 679 void spill(SpillLocationManager spillManager) { 680 spillInterval = spillManager.findOrCreateSpillLocation(this); 681 RegisterAllocatorState.setSpill(reg, spillInterval.getOffset()); 682 RegisterAllocatorState.clearOneToOne(reg); 683 if (VERBOSE_DEBUG) { 684 System.out.println("Assigned " + reg + " to location " + spillInterval.getOffset()); 685 } 686 } 687 688 /** 689 * Has this interval been spilled? 690 */ 691 boolean isSpilled() { 692 return (RegisterAllocatorState.getSpill(getRegister()) != 0); 693 } 694 695 /** 696 * Assign this compound interval to a physical register. 697 */ 698 void assign(Register r) { 699 getRegister().allocateToRegister(r); 700 } 701 702 /** 703 * Has this interval been assigned to a physical register? 704 */ 705 boolean isAssigned() { 706 return (RegisterAllocatorState.getMapping(getRegister()) != null); 707 } 708 709 /** 710 * Get the physical register this interval is assigned to. null if 711 * none assigned. 712 */ 713 Register getAssignment() { 714 return RegisterAllocatorState.getMapping(getRegister()); 715 } 716 717 /** 718 * Merge this interval with another, non-intersecting interval. 719 * Precondition: BasicInterval stop is an interval in i. This version 720 * will only merge basic intervals up to and including stop into this. 721 */ 722 void addNonIntersectingInterval(CompoundInterval i, BasicInterval stop) { 723 SortedSet<BasicInterval> headSet = i.headSetInclusive(stop); 724 addAll(headSet); 725 } 726 727 /** 728 * Compute the headSet() [from java.util.SortedSet] but include all 729 * elements less than upperBound <em>inclusive</em> 730 */ 731 SortedSet<BasicInterval> headSetInclusive(BasicInterval upperBound) { 732 BasicInterval newUpperBound = new BasicInterval(upperBound.getBegin() + 1, upperBound.getEnd()); 733 return headSet(newUpperBound); 734 } 735 736 /** 737 * Compute the headSet() [from java.util.SortedSet] but include all 738 * elements less than upperBound <em>inclusive</em> 739 */ 740 SortedSet<BasicInterval> headSetInclusive(int upperBound) { 741 BasicInterval newUpperBound = new BasicInterval(upperBound + 1, upperBound + 1); 742 return headSet(newUpperBound); 743 } 744 745 /** 746 * Compute the tailSet() [from java.util.SortedSet] but include all 747 * elements greater than lowerBound <em>inclusive</em> 748 */ 749 SortedSet<BasicInterval> tailSetInclusive(int lowerBound) { 750 BasicInterval newLowerBound = new BasicInterval(lowerBound - 1, lowerBound - 1); 751 return tailSet(newLowerBound); 752 } 753 754 /** 755 * Remove some basic intervals from this compound interval, and return 756 * the intervals actually removed. 757 * 758 * PRECONDITION: all basic intervals in i must appear in this compound 759 * interval, unless they end after the end of this interval 760 */ 761 CompoundInterval removeIntervalsAndCache(CompoundInterval i) { 762 CompoundInterval result = new CompoundInterval(i.getRegister()); 763 Iterator<BasicInterval> myIterator = iterator(); 764 Iterator<BasicInterval> otherIterator = i.iterator(); 765 BasicInterval current = myIterator.hasNext() ? myIterator.next() : null; 766 BasicInterval currentI = otherIterator.hasNext() ? otherIterator.next() : null; 767 768 while (currentI != null && current != null) { 769 if (current.startsBefore(currentI)) { 770 current = myIterator.hasNext() ? myIterator.next() : null; 771 } else if (currentI.startsBefore(current)) { 772 currentI = otherIterator.hasNext() ? otherIterator.next() : null; 773 } else { 774 if (VM.VerifyAssertions) VM._assert(current.sameRange(currentI)); 775 776 currentI = otherIterator.hasNext() ? otherIterator.next() : null; 777 BasicInterval next = myIterator.hasNext() ? myIterator.next() : null; 778 // add the interval to the cache 779 result.add(current); 780 current = next; 781 } 782 } 783 784 // SJF: the loop as written is slightly more efficient than calling 785 // removeAll(). However, for some reason, replacing the loop with 786 // the call to removeAll breaks the compiler on OptTestHarness 787 // -oc:O2 -method RVMMethod replaceCharWithString -. This is deeply 788 // disturbing. TODO: fix it. (Hope the problem goes away if/when 789 // we migrate to classpath libraries). 790 // removeAll(result); 791 for (BasicInterval b : result) { 792 remove(b); 793 } 794 795 return result; 796 } 797 798 /** 799 * SJF: Apparently our java.util implementation of removeAll() 800 * doesn't work. Perhaps I've somehow screwed up the comparator with 801 * the "consistent with equals" property? 802 * It breaks javalex on BaseOptMarkSweep on IA32 803 * Hopefully this problem will go away if/when we switch to classpath. 804 * Else, perhaps I'll ditch use of java.util Collections and write my 805 * own collection classes. 806 * In the meantime, here's an ugly hack to get around the problem. 807 */ 808 void removeAll(CompoundInterval c) { 809 for (BasicInterval b : c) { 810 remove(b); 811 } 812 } 813 814 /** 815 * Return the lowest DFN in this compound interval. 816 */ 817 int getLowerBound() { 818 BasicInterval b = first(); 819 return b.getBegin(); 820 } 821 822 /** 823 * Return the highest DFN in this compound interval. 824 */ 825 int getUpperBound() { 826 BasicInterval b = last(); 827 return b.getEnd(); 828 } 829 830 /** 831 * Does this interval intersect with i? 832 */ 833 boolean intersects(CompoundInterval i) { 834 835 if (isEmpty()) return false; 836 if (i.isEmpty()) return false; 837 838 // Walk over the basic intervals of this interval and i. 839 // Restrict the walking to intervals that might intersect. 840 int lower = Math.max(getLowerBound(), i.getLowerBound()); 841 int upper = Math.min(getUpperBound(), i.getUpperBound()); 842 843 // we may have to move one interval lower on each side. 844 BasicInterval b = getBasicInterval(lower); 845 int myLower = (b == null) ? lower : b.getBegin(); 846 if (myLower > upper) return false; 847 b = i.getBasicInterval(lower); 848 int otherLower = (b == null) ? lower : b.getBegin(); 849 if (otherLower > upper) return false; 850 851 SortedSet<BasicInterval> myTailSet = tailSetInclusive(myLower); 852 SortedSet<BasicInterval> otherTailSet = i.tailSetInclusive(otherLower); 853 Iterator<BasicInterval> myIterator = myTailSet.iterator(); 854 Iterator<BasicInterval> otherIterator = otherTailSet.iterator(); 855 856 BasicInterval current = myIterator.hasNext() ? myIterator.next() : null; 857 BasicInterval currentI = otherIterator.hasNext() ? otherIterator.next() : null; 858 859 while (current != null && currentI != null) { 860 if (current.getBegin() > upper) break; 861 if (currentI.getBegin() > upper) break; 862 if (current.intersects(currentI)) return true; 863 864 if (current.startsBefore(currentI)) { 865 current = myIterator.hasNext() ? myIterator.next() : null; 866 } else { 867 currentI = otherIterator.hasNext() ? otherIterator.next() : null; 868 } 869 } 870 return false; 871 } 872 873 /** 874 * Return the first basic interval that contains a given 875 * instruction. 876 * 877 * If there is no such interval, return null; 878 * @param s The instruction in question 879 */ 880 BasicInterval getBasicInterval(Instruction s) { 881 return getBasicInterval(getDFN(s)); 882 } 883 884 /** 885 * Return the first basic interval that contains the given 886 * instruction. 887 * 888 * If there is no such interval, return null; 889 * @param n The DFN of the instruction in question 890 */ 891 BasicInterval getBasicInterval(int n) { 892 SortedSet<BasicInterval> headSet = headSetInclusive(n); 893 if (!headSet.isEmpty()) { 894 BasicInterval last = headSet.last(); 895 return last.contains(n) ? last : null; 896 } else { 897 return null; 898 } 899 } 900 901 /** 902 * Make a String representation 903 */ 904 @Override 905 public String toString() { 906 String str = "[" + getRegister() + "]:"; 907 for (Iterator<BasicInterval> i = iterator(); i.hasNext();) { 908 BasicInterval b = i.next(); 909 str = str + b; 910 } 911 return str; 912 } 913 } 914 915 /** 916 * "Active set" for linear scan register allocation. 917 * This version is maintained sorted in order of increasing 918 * live interval end point. 919 */ 920 static final class ActiveSet extends IncreasingEndMappedIntervalSet { 921 /** Support for Set serialization */ 922 static final long serialVersionUID = 2570397490575294294L; 923 /** 924 * Governing ir 925 */ 926 private final IR ir; 927 928 /** 929 * Manager of spill locations; 930 */ 931 private final SpillLocationManager spillManager; 932 933 /** 934 * An object to help estimate spill costs 935 */ 936 private final transient SpillCostEstimator spillCost; 937 938 /** 939 * Have we spilled anything? 940 */ 941 private boolean spilled; 942 943 /** 944 * Default constructor 945 */ 946 ActiveSet(IR ir, SpillLocationManager sm) { 947 super(); 948 spilled = false; 949 this.ir = ir; 950 this.spillManager = sm; 951 952 switch (ir.options.REGALLOC_SPILL_COST_ESTIMATE) { 953 case OptOptions.REGALLOC_SIMPLE_SPILL_COST: 954 spillCost = new SimpleSpillCost(ir); 955 break; 956 case OptOptions.REGALLOC_BRAINDEAD_SPILL_COST: 957 spillCost = new BrainDeadSpillCost(ir); 958 break; 959 case OptOptions.REGALLOC_BLOCK_COUNT_SPILL_COST: 960 spillCost = new BlockCountSpillCost(ir); 961 break; 962 default: 963 OptimizingCompilerException.UNREACHABLE("unsupported spill cost"); 964 spillCost = null; 965 } 966 } 967 968 /** 969 * Have we spilled anything? 970 */ 971 boolean spilledSomething() { 972 return spilled; 973 } 974 975 /** 976 * For each new basic interval, we scan the list of active basic 977 * intervals in order of increasing end point. We remove any "expired" 978 * intervals - those 979 * intervals that no longer overlap the new interval because their 980 * end point precedes the new interval's start point - and makes the 981 * corresponding register available for allocation 982 * 983 * @param newInterval the new interval 984 */ 985 void expireOldIntervals(BasicInterval newInterval) { 986 987 for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { 988 MappedBasicInterval bi = (MappedBasicInterval) e.next(); 989 990 // break out of the loop when we reach an interval that is still 991 // alive 992 int newStart = newInterval.getBegin(); 993 if (bi.endsAfter(newStart)) break; 994 995 if (VERBOSE_DEBUG) System.out.println("Expire " + bi); 996 997 // note that the bi interval no longer is live 998 freeInterval(bi); 999 1000 // remove bi from the active set 1001 e.remove(); 1002 1003 } 1004 } 1005 1006 /** 1007 * Take action when a basic interval becomes inactive 1008 */ 1009 void freeInterval(MappedBasicInterval bi) { 1010 CompoundInterval container = bi.container; 1011 Register r = container.getRegister(); 1012 1013 if (r.isPhysical()) { 1014 r.deallocateRegister(); 1015 return; 1016 } 1017 1018 if (container.isSpilled()) { 1019 // free the spill location iff this is the last interval in the 1020 // compound interval. 1021 BasicInterval last = container.last(); 1022 if (last.sameRange(bi)) { 1023 spillManager.freeInterval(container.getSpillInterval()); 1024 } 1025 } else { 1026 // free the assigned register 1027 if (VM.VerifyAssertions) VM._assert(container.getAssignment().isAllocated()); 1028 container.getAssignment().deallocateRegister(); 1029 } 1030 1031 } 1032 1033 /** 1034 * Assign a basic interval to either a register or a spill location. 1035 */ 1036 void allocate(BasicInterval newInterval, CompoundInterval container) { 1037 1038 if (DEBUG) { 1039 System.out.println("Allocate " + newInterval + " " + container.getRegister()); 1040 } 1041 1042 Register r = container.getRegister(); 1043 1044 if (container.isSpilled()) { 1045 // We previously decided to spill the compound interval. No further 1046 // action is needed. 1047 if (VERBOSE_DEBUG) System.out.println("Previously spilled " + container); 1048 } else { 1049 if (container.isAssigned()) { 1050 // The compound interval was previously assigned to a physical 1051 // register. 1052 Register phys = container.getAssignment(); 1053 if (!currentlyActive(phys)) { 1054 // The assignment of newInterval to phys is still OK. 1055 // Update the live ranges of phys to include the new basic 1056 // interval 1057 if (VERBOSE_DEBUG) { 1058 System.out.println("Previously assigned to " + 1059 phys + 1060 " " + 1061 container + 1062 " phys interval " + 1063 getInterval(phys)); 1064 } 1065 updatePhysicalInterval(phys, newInterval); 1066 if (VERBOSE_DEBUG) { 1067 System.out.println(" now phys interval " + getInterval(phys)); 1068 } 1069 // Mark the physical register as currently allocated 1070 phys.allocateRegister(); 1071 } else { 1072 // The previous assignment is not OK, since the physical 1073 // register is now in use elsewhere. 1074 if (DEBUG) { 1075 System.out.println("Previously assigned, " + phys + " " + container); 1076 } 1077 // first look and see if there's another free register for 1078 // container. 1079 if (VERBOSE_DEBUG) System.out.println("Looking for free register"); 1080 Register freeR = findAvailableRegister(container); 1081 if (VERBOSE_DEBUG) System.out.println("Free register? " + freeR); 1082 1083 if (freeR == null) { 1084 // Did not find a free register to assign. So, spill one of 1085 // the two intervals concurrently allocated to phys. 1086 1087 CompoundInterval currentAssignment = getCurrentInterval(phys); 1088 // choose which of the two intervals to spill 1089 double costA = spillCost.getCost(container.getRegister()); 1090 double costB = spillCost.getCost(currentAssignment.getRegister()); 1091 if (VERBOSE_DEBUG) { 1092 System.out.println("Current assignment " + currentAssignment + " cost " + costB); 1093 } 1094 if (VERBOSE_DEBUG) { 1095 System.out.println("Cost of spilling" + container + " cost " + costA); 1096 } 1097 CompoundInterval toSpill = (costA < costB) ? container : currentAssignment; 1098 // spill it. 1099 Register p = toSpill.getAssignment(); 1100 toSpill.spill(spillManager); 1101 spilled = true; 1102 if (VERBOSE_DEBUG) { 1103 System.out.println("Spilled " + toSpill + " from " + p); 1104 } 1105 CompoundInterval physInterval = getInterval(p); 1106 physInterval.removeAll(toSpill); 1107 if (VERBOSE_DEBUG) System.out.println(" after spill phys" + getInterval(p)); 1108 if (toSpill != container) updatePhysicalInterval(p, newInterval); 1109 if (VERBOSE_DEBUG) { 1110 System.out.println(" now phys interval " + getInterval(p)); 1111 } 1112 } else { 1113 // found a free register for container! use it! 1114 if (DEBUG) { 1115 System.out.println("Switch container " + container + "from " + phys + " to " + freeR); 1116 } 1117 CompoundInterval physInterval = getInterval(phys); 1118 if (DEBUG) { 1119 System.out.println("Before switch phys interval" + physInterval); 1120 } 1121 physInterval.removeAll(container); 1122 if (DEBUG) { 1123 System.out.println("Intervals of " + phys + " now " + physInterval); 1124 } 1125 1126 container.assign(freeR); 1127 updatePhysicalInterval(freeR, container, newInterval); 1128 if (VERBOSE_DEBUG) { 1129 System.out.println("Intervals of " + freeR + " now " + getInterval(freeR)); 1130 } 1131 // mark the free register found as currently allocated. 1132 freeR.allocateRegister(); 1133 } 1134 } 1135 } else { 1136 // This is the first attempt to allocate the compound interval. 1137 // Attempt to find a free physical register for this interval. 1138 Register phys = findAvailableRegister(r); 1139 if (phys != null) { 1140 // Found a free register. Perform the register assignment. 1141 container.assign(phys); 1142 if (DEBUG) { 1143 System.out.println("First allocation " + phys + " " + container); 1144 } 1145 updatePhysicalInterval(phys, newInterval); 1146 if (VERBOSE_DEBUG) System.out.println(" now phys" + getInterval(phys)); 1147 // Mark the physical register as currently allocated. 1148 phys.allocateRegister(); 1149 } else { 1150 // Could not find a free physical register. Some member of the 1151 // active set must be spilled. Choose a spill candidate. 1152 CompoundInterval spillCandidate = getSpillCandidate(container); 1153 if (VM.VerifyAssertions) { 1154 VM._assert(!spillCandidate.isSpilled()); 1155 VM._assert((spillCandidate.getRegister().getType() == r.getType()) || 1156 (spillCandidate.getRegister().isNatural() && r.isNatural())); 1157 VM._assert(!ir.stackManager.getRestrictions().mustNotSpill(spillCandidate.getRegister())); 1158 if (spillCandidate.getAssignment() != null) { 1159 VM._assert(!ir.stackManager.getRestrictions(). 1160 isForbidden(r, spillCandidate.getAssignment())); 1161 } 1162 } 1163 if (spillCandidate != container) { 1164 // spill a previously allocated interval. 1165 phys = spillCandidate.getAssignment(); 1166 spillCandidate.spill(spillManager); 1167 spilled = true; 1168 if (VERBOSE_DEBUG) { 1169 System.out.println("Spilled " + spillCandidate + " from " + phys); 1170 } 1171 CompoundInterval physInterval = getInterval(phys); 1172 if (VERBOSE_DEBUG) { 1173 System.out.println(" assigned " + phys + " to " + container); 1174 } 1175 physInterval.removeAll(spillCandidate); 1176 if (VERBOSE_DEBUG) System.out.println(" after spill phys" + getInterval(phys)); 1177 updatePhysicalInterval(phys, newInterval); 1178 if (VERBOSE_DEBUG) { 1179 System.out.println(" now phys interval " + getInterval(phys)); 1180 } 1181 container.assign(phys); 1182 } else { 1183 // spill the new interval. 1184 if (VERBOSE_DEBUG) System.out.println("spilled " + container); 1185 container.spill(spillManager); 1186 spilled = true; 1187 } 1188 } 1189 } 1190 } 1191 } 1192 1193 /** 1194 * Update the interval representing the allocations of a physical 1195 * register p to include a new interval i 1196 */ 1197 private void updatePhysicalInterval(Register p, BasicInterval i) { 1198 // Get a representation of the intervals already assigned to p. 1199 CompoundInterval physInterval = getInterval(p); 1200 if (physInterval == null) { 1201 // no interval yet. create one. 1202 setInterval(p, new CompoundInterval(i, p)); 1203 } else { 1204 // incorporate i into the set of intervals assigned to p 1205 CompoundInterval ci = new CompoundInterval(i, p); 1206 if (VM.VerifyAssertions) VM._assert(!ci.intersects(physInterval)); 1207 physInterval.addAll(ci); 1208 } 1209 } 1210 1211 /** 1212 * Update the interval representing the allocations of a physical 1213 * register p to include a new compound interval c. Include only 1214 * those basic intervals in c up to and including basic interval stop. 1215 */ 1216 private void updatePhysicalInterval(Register p, CompoundInterval c, BasicInterval stop) { 1217 // Get a representation of the intervals already assigned to p. 1218 CompoundInterval physInterval = getInterval(p); 1219 if (physInterval == null) { 1220 // no interval yet. create one. 1221 setInterval(p, c.copy(p, stop)); 1222 } else { 1223 // incorporate c into the set of intervals assigned to p 1224 if (VM.VerifyAssertions) VM._assert(!c.intersects(physInterval)); 1225 // copy to a new BasicInterval so "equals" will work as expected, 1226 // since "stop" may be a MappedBasicInterval. 1227 stop = new BasicInterval(stop.getBegin(), stop.getEnd()); 1228 physInterval.addNonIntersectingInterval(c, stop); 1229 } 1230 } 1231 1232 /** 1233 * Is a particular physical register currently allocated to an 1234 * interval in the active set? 1235 */ 1236 boolean currentlyActive(Register r) { 1237 for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { 1238 MappedBasicInterval i = (MappedBasicInterval) e.next(); 1239 CompoundInterval container = i.container; 1240 if (RegisterAllocatorState.getMapping(container.getRegister()) == r) { 1241 return true; 1242 } 1243 } 1244 return false; 1245 } 1246 1247 /** 1248 * Given that a physical register r is currently allocated to an 1249 * interval in the active set, return the interval. 1250 */ 1251 CompoundInterval getCurrentInterval(Register r) { 1252 for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { 1253 MappedBasicInterval i = (MappedBasicInterval) e.next(); 1254 CompoundInterval container = i.container; 1255 if (RegisterAllocatorState.getMapping(container.getRegister()) == r) { 1256 return container; 1257 } 1258 } 1259 OptimizingCompilerException.UNREACHABLE("getCurrentInterval", "Not Currently Active ", r.toString()); 1260 return null; 1261 } 1262 1263 /** 1264 * try to find a free physical register to allocate to the compound 1265 * interval. if no free physical register is found, return null; 1266 */ 1267 Register findAvailableRegister(CompoundInterval ci) { 1268 1269 if (ir.options.FREQ_FOCUS_EFFORT && ci.isInfrequent()) { 1270 // don't bother trying to find an available register 1271 return null; 1272 } 1273 1274 Register r = ci.getRegister(); 1275 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1276 1277 // first attempt to allocate to the preferred register 1278 if (ir.options.REGALLOC_COALESCE_MOVES) { 1279 Register p = getPhysicalPreference(ci); 1280 if (p != null) { 1281 if (DEBUG_COALESCE) { 1282 System.out.println("REGISTER PREFERENCE " + ci + " " + p); 1283 } 1284 return p; 1285 } 1286 } 1287 1288 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 1289 int type = PhysicalRegisterSet.getPhysicalRegisterType(r); 1290 1291 // next attempt to allocate to a volatile 1292 if (!restrict.allVolatilesForbidden(r)) { 1293 for (Enumeration<Register> e = phys.enumerateVolatiles(type); e.hasMoreElements();) { 1294 Register p = e.nextElement(); 1295 if (allocateToPhysical(ci, p)) { 1296 return p; 1297 } 1298 } 1299 } 1300 1301 // next attempt to allocate to a Nonvolatile. we allocate the 1302 // novolatiles backwards. 1303 for (Enumeration<Register> e = phys.enumerateNonvolatilesBackwards(type); e.hasMoreElements();) { 1304 Register p = e.nextElement(); 1305 if (allocateToPhysical(ci, p)) { 1306 return p; 1307 } 1308 } 1309 1310 // no allocation succeeded. 1311 return null; 1312 } 1313 1314 /** 1315 * Try to find a free physical register to allocate to a symbolic 1316 * register. 1317 */ 1318 Register findAvailableRegister(Register symb) { 1319 1320 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1321 1322 // first attempt to allocate to the preferred register 1323 if (ir.options.REGALLOC_COALESCE_MOVES) { 1324 Register p = getPhysicalPreference(symb); 1325 if (p != null) { 1326 if (DEBUG_COALESCE) { 1327 System.out.println("REGISTER PREFERENCE " + symb + " " + p); 1328 } 1329 return p; 1330 } 1331 } 1332 1333 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 1334 int type = PhysicalRegisterSet.getPhysicalRegisterType(symb); 1335 1336 // next attempt to allocate to a volatile 1337 if (!restrict.allVolatilesForbidden(symb)) { 1338 for (Enumeration<Register> e = phys.enumerateVolatiles(type); e.hasMoreElements();) { 1339 Register p = e.nextElement(); 1340 if (allocateNewSymbolicToPhysical(symb, p)) { 1341 return p; 1342 } 1343 } 1344 } 1345 1346 // next attempt to allocate to a Nonvolatile. we allocate the 1347 // novolatiles backwards. 1348 for (Enumeration<Register> e = phys.enumerateNonvolatilesBackwards(type); e.hasMoreElements();) { 1349 Register p = e.nextElement(); 1350 if (allocateNewSymbolicToPhysical(symb, p)) { 1351 return p; 1352 } 1353 } 1354 1355 // no allocation succeeded. 1356 return null; 1357 } 1358 1359 /** 1360 * Given the current state of the register allocator, compute the 1361 * available physical register to which a symbolic register has the 1362 * highest preference. 1363 * 1364 * @param r the symbolic register in question. 1365 * @return the preferred register. null if no preference found. 1366 */ 1367 private Register getPhysicalPreference(Register r) { 1368 // a mapping from Register to Integer 1369 // (physical register to weight); 1370 HashMap<Register, Integer> map = new HashMap<Register, Integer>(); 1371 1372 CoalesceGraph graph = ir.stackManager.getPreferences().getGraph(); 1373 SpaceEffGraphNode node = graph.findNode(r); 1374 1375 // Return null if no affinities. 1376 if (node == null) return null; 1377 1378 // walk through all in edges of the node, searching for affinity 1379 for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { 1380 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 1381 CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from(); 1382 Register neighbor = src.getRegister(); 1383 if (neighbor.isSymbolic()) { 1384 // if r is assigned to a physical register r2, treat the 1385 // affinity as an affinity for r2 1386 Register r2 = RegisterAllocatorState.getMapping(r); 1387 if (r2 != null && r2.isPhysical()) { 1388 neighbor = r2; 1389 } 1390 } 1391 if (neighbor.isPhysical()) { 1392 // if this is a candidate interval, update its weight 1393 if (allocateNewSymbolicToPhysical(r, neighbor)) { 1394 int w = edge.getWeight(); 1395 Integer oldW = map.get(neighbor); 1396 if (oldW == null) { 1397 map.put(neighbor, w); 1398 } else { 1399 map.put(neighbor, oldW + w); 1400 } 1401 break; 1402 } 1403 } 1404 } 1405 // walk through all out edges of the node, searching for affinity 1406 for (Enumeration<GraphEdge> in = node.outEdges(); in.hasMoreElements();) { 1407 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 1408 CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); 1409 Register neighbor = dest.getRegister(); 1410 if (neighbor.isSymbolic()) { 1411 // if r is assigned to a physical register r2, treat the 1412 // affinity as an affinity for r2 1413 Register r2 = RegisterAllocatorState.getMapping(r); 1414 if (r2 != null && r2.isPhysical()) { 1415 neighbor = r2; 1416 } 1417 } 1418 if (neighbor.isPhysical()) { 1419 // if this is a candidate interval, update its weight 1420 if (allocateNewSymbolicToPhysical(r, neighbor)) { 1421 int w = edge.getWeight(); 1422 Integer oldW = map.get(neighbor); 1423 if (oldW == null) { 1424 map.put(neighbor, w); 1425 } else { 1426 map.put(neighbor, oldW + w); 1427 } 1428 break; 1429 } 1430 } 1431 } 1432 // OK, now find the highest preference. 1433 Register result = null; 1434 int weight = -1; 1435 for (Map.Entry<Register, Integer> entry : map.entrySet()) { 1436 int w = entry.getValue(); 1437 if (w > weight) { 1438 weight = w; 1439 result = entry.getKey(); 1440 } 1441 } 1442 return result; 1443 } 1444 1445 /** 1446 * Given the current state of the register allocator, compute the 1447 * available physical register to which an interval has the highest 1448 * preference. 1449 * 1450 * @return the preferred register. null if no preference found. 1451 */ 1452 private Register getPhysicalPreference(CompoundInterval ci) { 1453 // a mapping from Register to Integer 1454 // (physical register to weight); 1455 HashMap<Register, Integer> map = new HashMap<Register, Integer>(); 1456 Register r = ci.getRegister(); 1457 1458 CoalesceGraph graph = ir.stackManager.getPreferences().getGraph(); 1459 SpaceEffGraphNode node = graph.findNode(r); 1460 1461 // Return null if no affinities. 1462 if (node == null) return null; 1463 1464 // walk through all in edges of the node, searching for affinity 1465 for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { 1466 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 1467 CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from(); 1468 Register neighbor = src.getRegister(); 1469 if (neighbor.isSymbolic()) { 1470 // if r is assigned to a physical register r2, treat the 1471 // affinity as an affinity for r2 1472 Register r2 = RegisterAllocatorState.getMapping(r); 1473 if (r2 != null && r2.isPhysical()) { 1474 neighbor = r2; 1475 } 1476 } 1477 if (neighbor.isPhysical()) { 1478 // if this is a candidate interval, update its weight 1479 if (allocateToPhysical(ci, neighbor)) { 1480 int w = edge.getWeight(); 1481 Integer oldW = map.get(neighbor); 1482 if (oldW == null) { 1483 map.put(neighbor, w); 1484 } else { 1485 map.put(neighbor, oldW + w); 1486 } 1487 break; 1488 } 1489 } 1490 } 1491 // walk through all out edges of the node, searching for affinity 1492 for (Enumeration<GraphEdge> in = node.outEdges(); in.hasMoreElements();) { 1493 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 1494 CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); 1495 Register neighbor = dest.getRegister(); 1496 if (neighbor.isSymbolic()) { 1497 // if r is assigned to a physical register r2, treat the 1498 // affinity as an affinity for r2 1499 Register r2 = RegisterAllocatorState.getMapping(r); 1500 if (r2 != null && r2.isPhysical()) { 1501 neighbor = r2; 1502 } 1503 } 1504 if (neighbor.isPhysical()) { 1505 // if this is a candidate interval, update its weight 1506 if (allocateToPhysical(ci, neighbor)) { 1507 int w = edge.getWeight(); 1508 Integer oldW = map.get(neighbor); 1509 if (oldW == null) { 1510 map.put(neighbor, w); 1511 } else { 1512 map.put(neighbor, oldW + w); 1513 } 1514 break; 1515 } 1516 } 1517 } 1518 // OK, now find the highest preference. 1519 Register result = null; 1520 int weight = -1; 1521 for (Map.Entry<Register, Integer> entry : map.entrySet()) { 1522 int w = entry.getValue(); 1523 if (w > weight) { 1524 weight = w; 1525 result = entry.getKey(); 1526 } 1527 } 1528 return result; 1529 } 1530 1531 /** 1532 * Check whether it's ok to allocate an interval i to physical 1533 * register p. If so, return true; If not, return false. 1534 */ 1535 private boolean allocateToPhysical(CompoundInterval i, Register p) { 1536 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1537 Register r = i.getRegister(); 1538 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 1539 if (p != null && !phys.isAllocatable(p)) return false; 1540 1541 if (VERBOSE_DEBUG && p != null) { 1542 if (!p.isAvailable()) System.out.println("unavailable " + i + p); 1543 if (restrict.isForbidden(r, p)) System.out.println("forbidden" + i + p); 1544 } 1545 1546 if ((p != null) && p.isAvailable() && !restrict.isForbidden(r, p)) { 1547 CompoundInterval pInterval = getInterval(p); 1548 if (pInterval == null) { 1549 // no assignment to p yet 1550 return true; 1551 } else { 1552 if (!i.intersects(pInterval)) { 1553 return true; 1554 } 1555 } 1556 } 1557 return false; 1558 } 1559 1560 /** 1561 * Check whether it's ok to allocate symbolic register to a physical 1562 * register p. If so, return true; If not, return false. 1563 * 1564 * NOTE: This routine assumes we're processing the first interval of 1565 * register symb; so p.isAvailable() is the key information needed. 1566 */ 1567 private boolean allocateNewSymbolicToPhysical(Register symb, Register p) { 1568 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1569 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 1570 if (p != null && !phys.isAllocatable(p)) return false; 1571 1572 if (VERBOSE_DEBUG && p != null) { 1573 if (!p.isAvailable()) System.out.println("unavailable " + symb + p); 1574 if (restrict.isForbidden(symb, p)) System.out.println("forbidden" + symb + p); 1575 } 1576 1577 return (p != null) && p.isAvailable() && !restrict.isForbidden(symb, p); 1578 } 1579 1580 /** 1581 * choose one of the active intervals or the newInterval to spill. 1582 */ 1583 private CompoundInterval getSpillCandidate(CompoundInterval newInterval) { 1584 if (VERBOSE_DEBUG) System.out.println("GetSpillCandidate from " + this); 1585 1586 if (ir.options.FREQ_FOCUS_EFFORT && newInterval.isInfrequent()) { 1587 // if it's legal to spill this infrequent interval, then just do so! 1588 // don't spend any more effort. 1589 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1590 if (!restrict.mustNotSpill(newInterval.getRegister())) { 1591 return newInterval; 1592 } 1593 } 1594 1595 return spillMinUnitCost(newInterval); 1596 } 1597 1598 /** 1599 * Choose the interval with the min unit cost (defined as the number 1600 * of defs and uses) 1601 */ 1602 private CompoundInterval spillMinUnitCost(CompoundInterval newInterval) { 1603 if (VERBOSE_DEBUG) { 1604 System.out.println(" interval caused a spill: " + newInterval); 1605 } 1606 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1607 Register r = newInterval.getRegister(); 1608 double minCost = spillCost.getCost(r); 1609 if (VERBOSE_DEBUG) { 1610 System.out.println(" spill cost: " + r + " " + minCost); 1611 } 1612 CompoundInterval result = newInterval; 1613 if (restrict.mustNotSpill(result.getRegister())) { 1614 if (VERBOSE_DEBUG) { 1615 System.out.println(" must not spill: " + result.getRegister()); 1616 } 1617 result = null; 1618 minCost = Double.MAX_VALUE; 1619 } 1620 for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { 1621 MappedBasicInterval b = (MappedBasicInterval) e.next(); 1622 CompoundInterval i = b.container; 1623 Register newR = i.getRegister(); 1624 if (VERBOSE_DEBUG) { 1625 if (i.isSpilled()) { 1626 System.out.println(" not candidate, already spilled: " + newR); 1627 } 1628 if ((r.getType() != newR.getType()) || (r.isNatural() && newR.isNatural())) { 1629 System.out.println(" not candidate, type mismatch : " + r.getType() + " " + newR + " " + newR.getType()); 1630 } 1631 if (restrict.mustNotSpill(newR)) { 1632 System.out.println(" not candidate, must not spill: " + newR); 1633 } 1634 } 1635 if (!newR.isPhysical() && 1636 !i.isSpilled() && 1637 (r.getType() == newR.getType() || (r.isNatural() && newR.isNatural())) && 1638 !restrict.mustNotSpill(newR)) { 1639 // Found a potential spill interval. Check if the assignment 1640 // works if we spill this interval. 1641 if (checkAssignmentIfSpilled(newInterval, i)) { 1642 double iCost = spillCost.getCost(newR); 1643 if (VERBOSE_DEBUG) { 1644 System.out.println(" potential candidate " + i + " cost " + iCost); 1645 } 1646 if (iCost < minCost) { 1647 if (VERBOSE_DEBUG) System.out.println(" best candidate so far" + i); 1648 minCost = iCost; 1649 result = i; 1650 } 1651 } else { 1652 if (VERBOSE_DEBUG) { 1653 System.out.println(" not a candidate, insufficient range: " + i); 1654 } 1655 } 1656 } 1657 } 1658 if (VM.VerifyAssertions) { 1659 VM._assert(result != null); 1660 } 1661 return result; 1662 } 1663 1664 /** 1665 * Check whether, if we spilled interval spill, we could then assign 1666 * interval i to physical register spill.getRegister(). 1667 * 1668 * @return true if the allocation would fit. false otherwise 1669 */ 1670 private boolean checkAssignmentIfSpilled(CompoundInterval i, CompoundInterval spill) { 1671 Register r = spill.getAssignment(); 1672 1673 RegisterRestrictions restrict = ir.stackManager.getRestrictions(); 1674 if (restrict.isForbidden(i.getRegister(), r)) return false; 1675 1676 // 1. Speculatively simulate the spill. 1677 CompoundInterval rI = getInterval(r); 1678 CompoundInterval cache = rI.removeIntervalsAndCache(spill); 1679 1680 // 2. Check the fit. 1681 boolean result = !rI.intersects(i); 1682 1683 // 3. Undo the simulated spill. 1684 rI.addAll(cache); 1685 1686 return result; 1687 } 1688 1689 /** 1690 * Find the basic interval for register r containing instruction s. 1691 * If there are two such intervals, return the 1st one. 1692 * If there is none, return null. 1693 */ 1694 BasicInterval getBasicInterval(Register r, Instruction s) { 1695 CompoundInterval c = getInterval(r); 1696 if (c == null) return null; 1697 return c.getBasicInterval(s); 1698 } 1699 1700 } 1701 1702 /** 1703 * phase to compute linear scan intervals. 1704 */ 1705 public static final class IntervalAnalysis extends CompilerPhase implements Operators { 1706 /** 1707 * the governing ir 1708 */ 1709 IR ir; 1710 1711 /** 1712 * a list of basic blocks in topological order 1713 */ 1714 private BasicBlock listOfBlocks; 1715 1716 /** 1717 * a reverse topological list of basic blocks 1718 */ 1719 private BasicBlock reverseTopFirst; 1720 1721 /** 1722 * Constructor for this compiler phase 1723 */ 1724 private static final Constructor<CompilerPhase> constructor = 1725 getCompilerPhaseConstructor(IntervalAnalysis.class); 1726 1727 /** 1728 * Get a constructor object for this compiler phase 1729 * @return compiler phase constructor 1730 */ 1731 @Override 1732 public Constructor<CompilerPhase> getClassConstructor() { 1733 return constructor; 1734 } 1735 1736 /** 1737 * should we perform this phase? yes. 1738 */ 1739 @Override 1740 public boolean shouldPerform(OptOptions options) { return true; } 1741 1742 /** 1743 * a name for this phase. 1744 */ 1745 @Override 1746 public String getName() { return "Interval Analysis"; } 1747 1748 /** 1749 * should we print the ir? 1750 */ 1751 @Override 1752 public boolean printingEnabled(OptOptions options, boolean before) { 1753 return false; 1754 } 1755 1756 /** 1757 * compute live intervals for this ir 1758 * the result is a sorted (by beginning point) set of compound 1759 * intervals, stored in the private 'intervals' field. 1760 * 1761 * note: this implementation bashes the 'scratchobject' field on all 1762 * registers and the 'scratch' field on instructions. 1763 * 1764 * @param ir the ir 1765 */ 1766 @Override 1767 public void perform(IR ir) { 1768 this.ir = ir; 1769 1770 ControlFlowGraph cfg = ir.cfg; 1771 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 1772 LinearScanState state = new LinearScanState(); 1773 ir.MIRInfo.linearScanState = state; 1774 1775 // create topological list and a reverse topological list 1776 // the results are on listOfBlocks and reverseTopFirst lists 1777 createTopAndReverseList(cfg); 1778 1779 // give dfn values to each instruction 1780 assignDepthFirstNumbers(cfg); 1781 1782 // initialize registers 1783 initializeRegisters(); 1784 1785 int lastBeginSeen = -1; 1786 1787 // visit each basic block in the listOfBlocks list 1788 for (BasicBlock bb = listOfBlocks; bb != null; bb = (BasicBlock) bb.nextSorted) { 1789 1790 // visit each live interval for this basic block 1791 for (LiveIntervalElement live = bb.getFirstLiveIntervalElement(); live != null; live = live.getNext()) { 1792 1793 // check that we process live intervals in order of increasing 1794 // begin. 1795 if (VM.VerifyAssertions) { 1796 int begin = getDfnBegin(live, bb); 1797 VM._assert(begin >= lastBeginSeen); 1798 lastBeginSeen = begin; 1799 } 1800 1801 // skip registers which are not allocated. 1802 if (live.getRegister().isPhysical() && !phys.isAllocatable(live.getRegister())) { 1803 continue; 1804 } 1805 1806 CompoundInterval resultingInterval = processLiveInterval(live, bb); 1807 if (!bb.getInfrequent() && resultingInterval != null) { 1808 resultingInterval.setFrequent(); 1809 } 1810 } 1811 } 1812 1813 // debug support 1814 if (VERBOSE_DEBUG) { 1815 VM.sysWrite("**** start of interval dump " + ir.method + " ****\n"); 1816 VM.sysWrite(ir.MIRInfo.linearScanState.intervals.toString()); 1817 VM.sysWrite("**** end of interval dump ****\n"); 1818 } 1819 } 1820 1821 /** 1822 * create topological list and a reverse topological list 1823 * the results are on listOfBlocks and reverseTopFirst lists 1824 * @param cfg the control flow graph 1825 */ 1826 private void createTopAndReverseList(ControlFlowGraph cfg) { 1827 // dfs: create a list of nodes (basic blocks) in a topological order 1828 cfg.clearDFS(); 1829 listOfBlocks = cfg.entry(); 1830 listOfBlocks.sortDFS(); 1831 1832 // this loop reverses the topological list by using the sortedPrev field 1833 reverseTopFirst = null; 1834 for (BasicBlock bb = listOfBlocks; bb != null; bb = (BasicBlock) bb.nextSorted) { 1835 1836 // put back pointers in the "prev" field 1837 // set reverseTopFirst to be the more recent node we've seen, 1838 // it will be the front of the list when we are done 1839 bb.sortedPrev = reverseTopFirst; 1840 reverseTopFirst = bb; 1841 } 1842 } 1843 1844 /** 1845 * this method processes all basic blocks, do the following to each block 1846 * 1) add it to the begining of the "listOfBlocks" list 1847 * 2) number the instructions 1848 * 3) process the instructions that restrict physical register 1849 * assignment 1850 * @param cfg the control flow graph 1851 */ 1852 void assignDepthFirstNumbers(ControlFlowGraph cfg) { 1853 1854 int curDfn = ir.numberInstructions() - 1; 1855 1856 listOfBlocks = null; 1857 for (BasicBlock bb = reverseTopFirst; bb != null; bb = (BasicBlock) bb.sortedPrev) { 1858 1859 // insert bb at the front of the list 1860 bb.nextSorted = listOfBlocks; 1861 listOfBlocks = bb; 1862 1863 // number the instructions last to first 1864 Enumeration<Instruction> e = bb.reverseInstrEnumerator(); 1865 while (e.hasMoreElements()) { 1866 Instruction inst = e.nextElement(); 1867 setDFN(inst, curDfn); 1868 curDfn--; 1869 } 1870 } 1871 1872 if (DEBUG) { printDfns(ir); } 1873 } 1874 1875 /** 1876 * Initialize the interval for each register to null. 1877 */ 1878 private void initializeRegisters() { 1879 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { 1880 setInterval(reg, null); 1881 RegisterAllocatorState.setSpill(reg, 0); 1882 // clear the 'long' type if it's persisted to here. 1883 if (VM.BuildFor32Addr && reg.isLong()) { 1884 reg.clearType(); 1885 reg.setInteger(); 1886 } 1887 } 1888 } 1889 1890 /** 1891 * for each live interval associated with this block 1892 * we either add a new interval, or extend a previous interval 1893 * if it is contiguous 1894 * 1895 * @param live the liveintervalelement for a basic block/reg pair 1896 * @param bb the basic block 1897 * @return the resulting CompoundInterval. null if the live interval 1898 * is not relevant to register allocation. 1899 */ 1900 private CompoundInterval processLiveInterval(LiveIntervalElement live, BasicBlock bb) { 1901 1902 // get the reg and (adjusted) begin, end pair for this interval 1903 Register reg = live.getRegister(); 1904 int dfnend = getDfnEnd(live, bb); 1905 int dfnbegin = getDfnBegin(live, bb); 1906 1907 if (MUTATE_FMOV && reg.isFloatingPoint()) { 1908 Operators.helper.mutateFMOVs(live, reg, dfnbegin, dfnend); 1909 } 1910 1911 // check for an existing live interval for this register 1912 CompoundInterval existingInterval = getInterval(reg); 1913 if (existingInterval == null) { 1914 // create a new live interval 1915 CompoundInterval newInterval = new CompoundInterval(dfnbegin, dfnend, reg); 1916 if (VERBOSE_DEBUG) System.out.println("created a new interval " + newInterval); 1917 1918 // associate the interval with the register 1919 setInterval(reg, newInterval); 1920 1921 // add the new interval to the sorted set of intervals. 1922 BasicInterval b = newInterval.first(); 1923 ir.MIRInfo.linearScanState.intervals.add(b); 1924 1925 return newInterval; 1926 1927 } else { 1928 // add the new live range to the existing interval 1929 ArrayList<BasicInterval> intervals = ir.MIRInfo.linearScanState.intervals; 1930 BasicInterval added = existingInterval.addRange(live, bb); 1931 if (added != null) { 1932 intervals.add(added); 1933 } 1934 if (VERBOSE_DEBUG) System.out.println("Extended old interval " + reg); 1935 if (VERBOSE_DEBUG) System.out.println(existingInterval); 1936 1937 return existingInterval; 1938 } 1939 } 1940 } 1941 1942 /** 1943 * The following class manages allocation and reuse of spill locations. 1944 */ 1945 static class SpillLocationManager implements PhysicalRegisterConstants { 1946 1947 /** 1948 * The governing IR 1949 */ 1950 private final IR ir; 1951 1952 /** 1953 * Set of spill locations which were previously allocated, but may be 1954 * free since the assigned register is no longer live. 1955 */ 1956 final HashSet<SpillLocationInterval> freeIntervals = new HashSet<SpillLocationInterval>(); 1957 1958 /** 1959 * Return a spill location that is valid to hold the contents of 1960 * compound interval ci. 1961 */ 1962 SpillLocationInterval findOrCreateSpillLocation(CompoundInterval ci) { 1963 SpillLocationInterval result = null; 1964 1965 Register r = ci.getRegister(); 1966 int type = PhysicalRegisterSet.getPhysicalRegisterType(r); 1967 if (type == -1) { 1968 type = DOUBLE_REG; 1969 } 1970 int spillSize = PhysicalRegisterSet.getSpillSize(type); 1971 1972 // Search the free intervals and try to find an interval to 1973 // reuse. First look for the preferred interval. 1974 if (ir.options.REGALLOC_COALESCE_SPILLS) { 1975 result = getSpillPreference(ci, spillSize); 1976 if (result != null) { 1977 if (DEBUG_COALESCE) { 1978 System.out.println("SPILL PREFERENCE " + ci + " " + result); 1979 } 1980 freeIntervals.remove(result); 1981 } 1982 } 1983 1984 // Now search for any free interval. 1985 if (result == null) { 1986 for (SpillLocationInterval s : freeIntervals) { 1987 if (s.getSize() == spillSize && !s.intersects(ci)) { 1988 result = s; 1989 freeIntervals.remove(result); 1990 break; 1991 } 1992 } 1993 } 1994 1995 if (result == null) { 1996 // Could not find an interval to reuse. Create a new interval. 1997 int location = ir.stackManager.allocateNewSpillLocation(type); 1998 result = new SpillLocationInterval(location, spillSize); 1999 } 2000 2001 // Update the spill location interval to hold the new spill 2002 result.addAll(ci); 2003 2004 return result; 2005 } 2006 2007 /** 2008 * Record that a particular interval is potentially available for 2009 * reuse 2010 */ 2011 void freeInterval(SpillLocationInterval i) { 2012 freeIntervals.add(i); 2013 } 2014 2015 /** 2016 * Constructor. 2017 */ 2018 SpillLocationManager(IR ir) { 2019 this.ir = ir; 2020 } 2021 2022 /** 2023 * Given the current state of the register allocator, compute the 2024 * available spill location to which ci has the highest preference. 2025 * 2026 * @param ci the interval to spill 2027 * @param spillSize the size of spill location needed 2028 * @return the interval to spill to. null if no preference found. 2029 */ 2030 SpillLocationInterval getSpillPreference(CompoundInterval ci, int spillSize) { 2031 // a mapping from SpillLocationInterval to Integer 2032 // (spill location to weight); 2033 HashMap<SpillLocationInterval, Integer> map = new HashMap<SpillLocationInterval, Integer>(); 2034 Register r = ci.getRegister(); 2035 2036 CoalesceGraph graph = ir.stackManager.getPreferences().getGraph(); 2037 SpaceEffGraphNode node = graph.findNode(r); 2038 2039 // Return null if no affinities. 2040 if (node == null) return null; 2041 2042 // walk through all in edges of the node, searching for spill 2043 // location affinity 2044 for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { 2045 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 2046 CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from(); 2047 Register neighbor = src.getRegister(); 2048 if (neighbor.isSymbolic() && neighbor.isSpilled()) { 2049 int spillOffset = RegisterAllocatorState.getSpill(neighbor); 2050 // if this is a candidate interval, update its weight 2051 for (SpillLocationInterval s : freeIntervals) { 2052 if (s.getOffset() == spillOffset && s.getSize() == spillSize && !s.intersects(ci)) { 2053 int w = edge.getWeight(); 2054 Integer oldW = map.get(s); 2055 if (oldW == null) { 2056 map.put(s, w); 2057 } else { 2058 map.put(s, oldW + w); 2059 } 2060 break; 2061 } 2062 } 2063 } 2064 } 2065 2066 // walk through all out edges of the node, searching for spill 2067 // location affinity 2068 for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { 2069 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 2070 CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); 2071 Register neighbor = dest.getRegister(); 2072 if (neighbor.isSymbolic() && neighbor.isSpilled()) { 2073 int spillOffset = RegisterAllocatorState.getSpill(neighbor); 2074 // if this is a candidate interval, update its weight 2075 for (SpillLocationInterval s : freeIntervals) { 2076 if (s.getOffset() == spillOffset && s.getSize() == spillSize && !s.intersects(ci)) { 2077 int w = edge.getWeight(); 2078 Integer oldW = map.get(s); 2079 if (oldW == null) { 2080 map.put(s, w); 2081 } else { 2082 map.put(s, oldW + w); 2083 } 2084 break; 2085 } 2086 } 2087 } 2088 } 2089 2090 // OK, now find the highest preference. 2091 SpillLocationInterval result = null; 2092 int weight = -1; 2093 for (Map.Entry<SpillLocationInterval, Integer> entry : map.entrySet()) { 2094 int w = entry.getValue(); 2095 if (w > weight) { 2096 weight = w; 2097 result = entry.getKey(); 2098 } 2099 } 2100 return result; 2101 } 2102 } 2103 2104 /** 2105 * The following represents the intervals assigned to a particular spill 2106 * location 2107 */ 2108 static class SpillLocationInterval extends CompoundInterval { 2109 /** Support for Set serialization */ 2110 static final long serialVersionUID = 2854333172650538517L; 2111 /** 2112 * The spill location, an offset from the frame pointer 2113 */ 2114 private final int frameOffset; 2115 2116 int getOffset() { 2117 return frameOffset; 2118 } 2119 2120 /** 2121 * The size of the spill location, in bytes. 2122 */ 2123 private final int size; 2124 2125 int getSize() { 2126 return size; 2127 } 2128 2129 SpillLocationInterval(int frameOffset, int size) { 2130 super(null); 2131 this.frameOffset = frameOffset; 2132 this.size = size; 2133 } 2134 2135 @Override 2136 public String toString() { 2137 return super.toString() + "<Offset:" + frameOffset + "," + size + ">"; 2138 } 2139 2140 /** 2141 * Redefine hash code for reproducibility. 2142 */ 2143 @Override 2144 public int hashCode() { 2145 BasicInterval first = first(); 2146 BasicInterval last = last(); 2147 return frameOffset + (first.getBegin() << 4) + (last.getEnd() << 12); 2148 } 2149 } 2150 2151 /** 2152 * Implements a set of Basic Intervals, sorted by start number. 2153 * This version does NOT use container-mapping as a function in the comparator. 2154 */ 2155 static class IncreasingStartIntervalSet extends IntervalSet { 2156 /** Support for Set serialization */ 2157 static final long serialVersionUID = -7086728932911844728L; 2158 2159 private static class StartComparator implements Comparator<BasicInterval> { 2160 @Override 2161 public int compare(BasicInterval b1, BasicInterval b2) { 2162 int result = b1.getBegin() - b2.getBegin(); 2163 if (result == 0) { 2164 result = b1.getEnd() - b2.getEnd(); 2165 } 2166 return result; 2167 } 2168 } 2169 2170 static final StartComparator c = new StartComparator(); 2171 2172 IncreasingStartIntervalSet() { 2173 super(c /*,true*/); 2174 } 2175 } 2176 2177 /** 2178 * Implements a set of Basic Intervals, sorted by start number. 2179 * This version uses container-mapping as a function in the comparator. 2180 */ 2181 static class IncreasingStartMappedIntervalSet extends IntervalSet { 2182 /** Support for Set serialization */ 2183 static final long serialVersionUID = -975667667343524421L; 2184 2185 private static class StartComparator implements Comparator<BasicInterval> { 2186 @Override 2187 public int compare(BasicInterval b1, BasicInterval b2) { 2188 int result = b1.getBegin() - b2.getBegin(); 2189 if (result == 0) { 2190 result = b1.getEnd() - b2.getEnd(); 2191 } 2192 if (result == 0) { 2193 if (b1 instanceof MappedBasicInterval) { 2194 if (b2 instanceof MappedBasicInterval) { 2195 MappedBasicInterval mb1 = (MappedBasicInterval) b1; 2196 MappedBasicInterval mb2 = (MappedBasicInterval) b2; 2197 return mb1.container.getRegister().number - mb2.container.getRegister().number; 2198 } 2199 } 2200 } 2201 return result; 2202 } 2203 } 2204 2205 static final StartComparator c = new StartComparator(); 2206 2207 IncreasingStartMappedIntervalSet() { 2208 super(c); 2209 } 2210 } 2211 2212 /** 2213 * Implements a set of Basic Intervals, sorted by end number. 2214 * This version uses container-mapping as a function in the comparator. 2215 */ 2216 static class IncreasingEndMappedIntervalSet extends IntervalSet { 2217 /** Support for Set serialization */ 2218 static final long serialVersionUID = -3121737650157210290L; 2219 2220 private static class EndComparator implements Comparator<BasicInterval> { 2221 @Override 2222 public int compare(BasicInterval b1, BasicInterval b2) { 2223 int result = b1.getEnd() - b2.getEnd(); 2224 if (result == 0) { 2225 result = b1.getBegin() - b2.getBegin(); 2226 } 2227 if (result == 0) { 2228 if (b1 instanceof MappedBasicInterval) { 2229 if (b2 instanceof MappedBasicInterval) { 2230 MappedBasicInterval mb1 = (MappedBasicInterval) b1; 2231 MappedBasicInterval mb2 = (MappedBasicInterval) b2; 2232 return mb1.container.getRegister().number - mb2.container.getRegister().number; 2233 } 2234 } 2235 } 2236 return result; 2237 } 2238 } 2239 2240 static final EndComparator c = new EndComparator(); 2241 2242 IncreasingEndMappedIntervalSet() { 2243 super(c); 2244 } 2245 } 2246 2247 abstract static class IntervalSet extends TreeSet<BasicInterval> { 2248 2249 /** 2250 * Create an interval set sorted by increasing start or end number 2251 */ 2252 IntervalSet(Comparator<BasicInterval> c) { 2253 super(c); 2254 } 2255 2256 /** 2257 * Return a String representation 2258 */ 2259 @Override 2260 public String toString() { 2261 String result = ""; 2262 for (BasicInterval b : this) { 2263 result = result + b + "\n"; 2264 } 2265 return result; 2266 } 2267 } 2268 2269 /** 2270 * Update GC maps after register allocation but before inserting spill 2271 * code. 2272 */ 2273 static final class UpdateGCMaps1 extends CompilerPhase { 2274 2275 @Override 2276 public boolean shouldPerform(OptOptions options) { 2277 return true; 2278 } 2279 2280 /** 2281 * Return this instance of this phase. This phase contains no 2282 * per-compilation instance fields. 2283 * @param ir not used 2284 * @return this 2285 */ 2286 @Override 2287 public CompilerPhase newExecution(IR ir) { 2288 return this; 2289 } 2290 2291 @Override 2292 public String getName() { 2293 return "Update GCMaps 1"; 2294 } 2295 2296 @Override 2297 public boolean printingEnabled(OptOptions options, boolean before) { 2298 return false; 2299 } 2300 2301 /** 2302 * Iterate over the IR-based GC map collection and for each entry 2303 * replace the symbolic reg with the real reg or spill it was allocated 2304 * @param ir the IR 2305 */ 2306 @Override 2307 public void perform(IR ir) { 2308 2309 for (GCIRMapElement GCelement : ir.MIRInfo.gcIRMap) { 2310 if (GC_DEBUG) { 2311 VM.sysWrite("GCelement " + GCelement); 2312 } 2313 2314 for (RegSpillListElement elem : GCelement.regSpillList()) { 2315 Register symbolic = elem.getSymbolicReg(); 2316 2317 if (GC_DEBUG) { 2318 VM.sysWrite("get location for " + symbolic + '\n'); 2319 } 2320 2321 if (symbolic.isAllocated()) { 2322 Register ra = RegisterAllocatorState.getMapping(symbolic); 2323 elem.setRealReg(ra); 2324 if (GC_DEBUG) { VM.sysWrite(ra + "\n"); } 2325 2326 } else if (symbolic.isSpilled()) { 2327 int spill = symbolic.getSpillAllocated(); 2328 elem.setSpill(spill); 2329 if (GC_DEBUG) { VM.sysWrite(spill + "\n"); } 2330 } else { 2331 OptimizingCompilerException.UNREACHABLE("LinearScan", "register not alive:", symbolic.toString()); 2332 } 2333 } 2334 } 2335 } 2336 } 2337 2338 /** 2339 * Update GC Maps again, to account for changes induced by spill code. 2340 */ 2341 static final class UpdateGCMaps2 extends CompilerPhase { 2342 /** 2343 * Return this instance of this phase. This phase contains no 2344 * per-compilation instance fields. 2345 * @param ir not used 2346 * @return this 2347 */ 2348 @Override 2349 public CompilerPhase newExecution(IR ir) { 2350 return this; 2351 } 2352 2353 @Override 2354 public boolean shouldPerform(OptOptions options) { 2355 return true; 2356 } 2357 2358 @Override 2359 public String getName() { 2360 return "Update GCMaps 2"; 2361 } 2362 2363 @Override 2364 public boolean printingEnabled(OptOptions options, boolean before) { 2365 return false; 2366 } 2367 2368 /** 2369 * @param ir the IR 2370 */ 2371 @Override 2372 public void perform(IR ir) { 2373 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 2374 ScratchMap scratchMap = ir.stackManager.getScratchMap(); 2375 2376 if (GC_DEBUG) { 2377 System.out.println("SCRATCH MAP:\n" + scratchMap); 2378 } 2379 if (scratchMap.isEmpty()) return; 2380 2381 // Walk over each instruction that has a GC point. 2382 for (GCIRMapElement GCelement : ir.MIRInfo.gcIRMap) { 2383 // new elements to add to the gc map 2384 HashSet<RegSpillListElement> newElements = new HashSet<RegSpillListElement>(); 2385 2386 Instruction GCinst = GCelement.getInstruction(); 2387 2388 // Get the linear-scan DFN for this instruction. 2389 int dfn = GCinst.scratch; 2390 2391 if (GC_DEBUG) { 2392 VM.sysWrite("GCelement at " + dfn + " , " + GCelement); 2393 } 2394 2395 // a set of elements to delete from the GC Map 2396 HashSet<RegSpillListElement> toDelete = new HashSet<RegSpillListElement>(3); 2397 2398 // For each element in the GC Map ... 2399 for (RegSpillListElement elem : GCelement.regSpillList()) { 2400 if (GC_DEBUG) { 2401 VM.sysWrite("Update " + elem + "\n"); 2402 } 2403 if (elem.isSpill()) { 2404 // check if the spilled value currently is cached in a scratch 2405 // register 2406 Register r = elem.getSymbolicReg(); 2407 Register scratch = scratchMap.getScratch(r, dfn); 2408 if (scratch != null) { 2409 if (GC_DEBUG) { 2410 VM.sysWrite("cached in scratch register " + scratch + "\n"); 2411 } 2412 // we will add a new element noting that the scratch register 2413 // also must be including in the GC map 2414 RegSpillListElement newElem = new RegSpillListElement(r); 2415 newElem.setRealReg(scratch); 2416 newElements.add(newElem); 2417 // if the scratch register is dirty, then delete the spill 2418 // location from the map, since it doesn't currently hold a 2419 // valid value 2420 if (scratchMap.isDirty(GCinst, r)) { 2421 toDelete.add(elem); 2422 } 2423 } 2424 } else { 2425 // check if the physical register is currently spilled. 2426 int n = elem.getRealRegNumber(); 2427 Register r = phys.get(n); 2428 if (scratchMap.isScratch(r, dfn)) { 2429 // The regalloc state knows where the physical register r is 2430 // spilled. 2431 if (GC_DEBUG) { 2432 VM.sysWrite("CHANGE to spill location " + RegisterAllocatorState.getSpill(r) + "\n"); 2433 } 2434 elem.setSpill(RegisterAllocatorState.getSpill(r)); 2435 } 2436 } 2437 2438 } 2439 // delete all obsolete elements 2440 for (RegSpillListElement deadElem : toDelete) { 2441 GCelement.deleteRegSpillElement(deadElem); 2442 } 2443 2444 // add each new Element to the gc map 2445 for (RegSpillListElement newElem : newElements) { 2446 GCelement.addRegSpillElement(newElem); 2447 } 2448 } 2449 } 2450 } 2451 2452 /** 2453 * Insert Spill Code after register assignment. 2454 */ 2455 static final class SpillCode extends CompilerPhase implements Operators { 2456 /** 2457 * Return this instance of this phase. This phase contains no 2458 * per-compilation instance fields. 2459 * @param ir not used 2460 * @return this 2461 */ 2462 @Override 2463 public CompilerPhase newExecution(IR ir) { 2464 return this; 2465 } 2466 2467 @Override 2468 public boolean shouldPerform(OptOptions options) { 2469 return true; 2470 } 2471 2472 @Override 2473 public String getName() { 2474 return "Spill Code"; 2475 } 2476 2477 @Override 2478 public boolean printingEnabled(OptOptions options, boolean before) { 2479 return false; 2480 } 2481 2482 /** 2483 * @param ir the IR 2484 */ 2485 @Override 2486 public void perform(IR ir) { 2487 replaceSymbolicRegisters(ir); 2488 2489 // Generate spill code if necessary 2490 if (ir.hasSysCall() || ir.MIRInfo.linearScanState.spilledSomething) { 2491 StackManager stackMan = (StackManager) ir.stackManager; 2492 stackMan.insertSpillCode(ir.MIRInfo.linearScanState.active); 2493 // stackMan.insertSpillCode(); 2494 } 2495 2496 if (VM.BuildForIA32 && !VM.BuildForSSE2Full) { 2497 Operators.helper.rewriteFPStack(ir); 2498 } 2499 } 2500 2501 /** 2502 * Iterate over the IR and replace each symbolic register with its 2503 * allocated physical register. 2504 * Also used by ClassWriter 2505 */ 2506 public static void replaceSymbolicRegisters(IR ir) { 2507 for (Enumeration<Instruction> inst = ir.forwardInstrEnumerator(); inst.hasMoreElements();) { 2508 Instruction s = inst.nextElement(); 2509 for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements();) { 2510 Operand op = ops.nextElement(); 2511 if (op.isRegister()) { 2512 RegisterOperand rop = op.asRegister(); 2513 Register r = rop.getRegister(); 2514 if (r.isSymbolic() && !r.isSpilled()) { 2515 Register p = RegisterAllocatorState.getMapping(r); 2516 if (VM.VerifyAssertions) VM._assert(p != null); 2517 rop.setRegister(p); 2518 } 2519 } 2520 } 2521 } 2522 } 2523 2524 } 2525 2526 /** 2527 * Update GC maps after register allocation but before inserting spill 2528 * code. 2529 */ 2530 public static final class UpdateOSRMaps extends CompilerPhase { 2531 2532 @Override 2533 public boolean shouldPerform(OptOptions options) { 2534 return true; 2535 } 2536 2537 /** 2538 * Return this instance of this phase. This phase contains no 2539 * per-compilation instance fields. 2540 * @param ir not used 2541 * @return this 2542 */ 2543 @Override 2544 public CompilerPhase newExecution(IR ir) { 2545 return this; 2546 } 2547 2548 @Override 2549 public String getName() { 2550 return "Update OSRMaps"; 2551 } 2552 2553 @Override 2554 public boolean printingEnabled(OptOptions options, boolean before) { 2555 return false; 2556 } 2557 2558 /** 2559 * Iterate over the IR-based OSR map, and update symbolic registers 2560 * with real reg number or spill locations. 2561 * Verify there are only two types of operands: 2562 * ConstantOperand 2563 * RegisterOperand 2564 * for integer constant, we save the value of the integer 2565 * 2566 * The LONG register has another half part. 2567 * 2568 * CodeSpill replaces any allocated symbolic register by 2569 * physical registers. 2570 */ 2571 @Override 2572 public void perform(IR ir) throws OptimizingCompilerException { 2573 // list of OsrVariableMapElement 2574 //LinkedList<VariableMapElement> mapList = ir.MIRInfo.osrVarMap.list; 2575 //for (int numOsrs=0, m=mapList.size(); numOsrs<m; numOsrs++) { 2576 // VariableMapElement elm = mapList.get(numOsrs); 2577 /* for each osr instruction */ 2578 for (VariableMapElement elm : ir.MIRInfo.osrVarMap.list) { 2579 2580 // for each inlined method 2581 //LinkedList<MethodVariables> mvarsList = elm.mvars; XXX Remove once proven correct 2582 //for (int numMvars=0, n=mvarsList.size(); numMvars<n; numMvars++) { 2583 // MethodVariables mvar = mvarsList.get(numMvars); 2584 for (MethodVariables mvar : elm.mvars) { 2585 2586 // for each tuple 2587 //LinkedList<LocalRegPair> tupleList = mvar.tupleList; 2588 //for (int numTuple=0, k=tupleList.size(); numTuple<k; numTuple++) { 2589 //LocalRegPair tuple = tupleList.get(numTuple); 2590 for (LocalRegPair tuple : mvar.tupleList) { 2591 2592 Operand op = tuple.operand; 2593 if (op.isRegister()) { 2594 Register sym_reg = ((RegisterOperand) op).getRegister(); 2595 2596 setRealPosition(ir, tuple, sym_reg); 2597 2598 // get another half part of long register 2599 if (VM.BuildFor32Addr && (tuple.typeCode == OSRConstants.LongTypeCode)) { 2600 2601 LocalRegPair other = tuple._otherHalf; 2602 Operand other_op = other.operand; 2603 2604 if (VM.VerifyAssertions) VM._assert(other_op.isRegister()); 2605 2606 Register other_reg = ((RegisterOperand) other_op).getRegister(); 2607 setRealPosition(ir, other, other_reg); 2608 } 2609 /* According to ConvertToLowLevelIR, StringConstant, LongConstant, 2610 * NullConstant, FloatConstant, and DoubleConstant are all materialized 2611 * The only thing left is the integer constants which could encode 2612 * non-moveable objects. 2613 * POTENTIAL DRAWBACKS: since any long, float, and double are moved 2614 * to register and treated as use, it may consume more registers and 2615 * add unnecessary MOVEs. 2616 * 2617 * Perhaps, ConvertToLowLevelIR can skip OsrPoint instruction. 2618 */ 2619 } else if (op.isIntConstant()) { 2620 setTupleValue(tuple, OSRConstants.ICONST, ((IntConstantOperand) op).value); 2621 if (VM.BuildFor32Addr && (tuple.typeCode == OSRConstants.LongTypeCode)) { 2622 LocalRegPair other = tuple._otherHalf; 2623 Operand other_op = other.operand; 2624 2625 if (VM.VerifyAssertions) VM._assert(other_op.isIntConstant()); 2626 setTupleValue(other, OSRConstants.ICONST, ((IntConstantOperand) other_op).value); 2627 } 2628 } else if (op.isAddressConstant()) { 2629 setTupleValue(tuple, OSRConstants.ACONST, ((AddressConstantOperand) op).value.toWord()); 2630 } else if (VM.BuildFor64Addr && op.isLongConstant()) { 2631 setTupleValue(tuple, OSRConstants.LCONST, Word.fromLong(((LongConstantOperand) op).value)); 2632 } else { 2633 throw new OptimizingCompilerException("LinearScan", "Unexpected operand type at ", op.toString()); 2634 } // for the op type 2635 } // for each tuple 2636 } // for each inlined method 2637 } // for each osr instruction 2638 } // end of method 2639 2640 void setRealPosition(IR ir, LocalRegPair tuple, Register sym_reg) { 2641 if (VM.VerifyAssertions) VM._assert(sym_reg != null); 2642 2643 int REG_MASK = 0x01F; 2644 2645 // now it is not symbolic register anymore. 2646 // is is really confusing that sometimes a sym reg is a phy, 2647 // and sometimes not. 2648 if (sym_reg.isAllocated()) { 2649 setTupleValue(tuple, OSRConstants.PHYREG, sym_reg.number & REG_MASK); 2650 } else if (sym_reg.isPhysical()) { 2651 setTupleValue(tuple, OSRConstants.PHYREG, sym_reg.number & REG_MASK); 2652 } else if (sym_reg.isSpilled()) { 2653 setTupleValue(tuple, OSRConstants.SPILL, sym_reg.getSpillAllocated()); 2654 } else { 2655 dumpIR(ir, "PANIC"); 2656 throw new RuntimeException("LinearScan PANIC in OSRMAP, " + sym_reg + " is not alive"); 2657 } 2658 } // end of setRealPosition 2659 2660 static void setTupleValue(LocalRegPair tuple, byte type, int value) { 2661 tuple.valueType = type; 2662 tuple.value = Word.fromIntSignExtend(value); 2663 } // end of setTupleValue 2664 2665 static void setTupleValue(LocalRegPair tuple, byte type, Word value) { 2666 tuple.valueType = type; 2667 tuple.value = value; 2668 } // end of setTupleValue 2669 } // end of inner class 2670 }