1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.ssa; 18 19 import com.android.dx.rop.code.BasicBlock; 20 import com.android.dx.rop.code.BasicBlockList; 21 import com.android.dx.rop.code.Insn; 22 import com.android.dx.rop.code.InsnList; 23 import com.android.dx.rop.code.PlainInsn; 24 import com.android.dx.rop.code.RegisterSpec; 25 import com.android.dx.rop.code.RegisterSpecList; 26 import com.android.dx.rop.code.Rop; 27 import com.android.dx.rop.code.RopMethod; 28 import com.android.dx.rop.code.Rops; 29 import com.android.dx.rop.code.SourcePosition; 30 import com.android.dx.util.Hex; 31 import com.android.dx.util.IntList; 32 import com.android.dx.util.IntSet; 33 import java.util.ArrayList; 34 import java.util.BitSet; 35 import java.util.Collections; 36 import java.util.Comparator; 37 import java.util.List; 38 39 /** 40 * An SSA representation of a basic block. 41 */ 42 public final class SsaBasicBlock { 43 /** 44 * {@code non-null;} comparator for instances of this class that 45 * just compares block labels 46 */ 47 public static final Comparator<SsaBasicBlock> LABEL_COMPARATOR = 48 new LabelComparator(); 49 50 /** {@code non-null;} insn list associated with this instance */ 51 private final ArrayList<SsaInsn> insns; 52 53 /** {@code non-null;} predecessor set (by block list index) */ 54 private BitSet predecessors; 55 56 /** {@code non-null;} successor set (by block list index) */ 57 private BitSet successors; 58 59 /** 60 * {@code non-null;} ordered successor list 61 * (same block may be listed more than once) 62 */ 63 private IntList successorList; 64 65 /** 66 * block list index of primary successor, or {@code -1} for no primary 67 * successor 68 */ 69 private int primarySuccessor = -1; 70 71 /** label of block in rop form */ 72 private final int ropLabel; 73 74 /** {@code non-null;} method we belong to */ 75 private final SsaMethod parent; 76 77 /** our index into parent.getBlock() */ 78 private final int index; 79 80 /** list of dom children */ 81 private final ArrayList<SsaBasicBlock> domChildren; 82 83 /** 84 * the number of moves added to the end of the block during the 85 * phi-removal process. Retained for subsequent move scheduling. 86 */ 87 private int movesFromPhisAtEnd = 0; 88 89 /** 90 * the number of moves added to the beginning of the block during the 91 * phi-removal process. Retained for subsequent move scheduling. 92 */ 93 private int movesFromPhisAtBeginning = 0; 94 95 /** 96 * {@code null-ok;} indexed by reg: the regs that are live-in at 97 * this block 98 */ 99 private IntSet liveIn; 100 101 /** 102 * {@code null-ok;} indexed by reg: the regs that are live-out at 103 * this block 104 */ 105 private IntSet liveOut; 106 107 /** 108 * Creates a new empty basic block. 109 * 110 * @param basicBlockIndex index this block will have 111 * @param ropLabel original rop-form label 112 * @param parent method of this block 113 */ SsaBasicBlock(final int basicBlockIndex, final int ropLabel, final SsaMethod parent)114 public SsaBasicBlock(final int basicBlockIndex, final int ropLabel, 115 final SsaMethod parent) { 116 this.parent = parent; 117 this.index = basicBlockIndex; 118 this.insns = new ArrayList<SsaInsn>(); 119 this.ropLabel = ropLabel; 120 121 this.predecessors = new BitSet(parent.getBlocks().size()); 122 this.successors = new BitSet(parent.getBlocks().size()); 123 this.successorList = new IntList(); 124 125 domChildren = new ArrayList<SsaBasicBlock>(); 126 } 127 128 /** 129 * Creates a new SSA basic block from a ROP form basic block. 130 * 131 * @param rmeth original method 132 * @param basicBlockIndex index this block will have 133 * @param parent method of this block predecessor set will be 134 * updated 135 * @return new instance 136 */ newFromRop(RopMethod rmeth, int basicBlockIndex, final SsaMethod parent)137 public static SsaBasicBlock newFromRop(RopMethod rmeth, 138 int basicBlockIndex, final SsaMethod parent) { 139 BasicBlockList ropBlocks = rmeth.getBlocks(); 140 BasicBlock bb = ropBlocks.get(basicBlockIndex); 141 SsaBasicBlock result = 142 new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent); 143 InsnList ropInsns = bb.getInsns(); 144 145 result.insns.ensureCapacity(ropInsns.size()); 146 147 for (int i = 0, sz = ropInsns.size() ; i < sz ; i++) { 148 result.insns.add(new NormalSsaInsn (ropInsns.get(i), result)); 149 } 150 151 result.predecessors = SsaMethod.bitSetFromLabelList( 152 ropBlocks, 153 rmeth.labelToPredecessors(bb.getLabel())); 154 155 result.successors 156 = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors()); 157 158 result.successorList 159 = SsaMethod.indexListFromLabelList(ropBlocks, 160 bb.getSuccessors()); 161 162 if (result.successorList.size() != 0) { 163 int primarySuccessor = bb.getPrimarySuccessor(); 164 165 result.primarySuccessor = (primarySuccessor < 0) 166 ? -1 : ropBlocks.indexOfLabel(primarySuccessor); 167 } 168 169 return result; 170 } 171 172 /** 173 * Adds a basic block as a dom child for this block. Used when constructing 174 * the dom tree. 175 * 176 * @param child {@code non-null;} new dom child 177 */ addDomChild(SsaBasicBlock child)178 public void addDomChild(SsaBasicBlock child) { 179 domChildren.add(child); 180 } 181 182 /** 183 * Gets the dom children for this node. Don't modify this list. 184 * 185 * @return {@code non-null;} list of dom children 186 */ getDomChildren()187 public ArrayList<SsaBasicBlock> getDomChildren() { 188 return domChildren; 189 } 190 191 /** 192 * Adds a phi insn to the beginning of this block. The result type of 193 * the phi will be set to void, to indicate that it's currently unknown. 194 * 195 * @param reg {@code >=0;} result reg 196 */ addPhiInsnForReg(int reg)197 public void addPhiInsnForReg(int reg) { 198 insns.add(0, new PhiInsn(reg, this)); 199 } 200 201 /** 202 * Adds a phi insn to the beginning of this block. This is to be used 203 * when the result type or local-association can be determined at phi 204 * insert time. 205 * 206 * @param resultSpec {@code non-null;} reg 207 */ addPhiInsnForReg(RegisterSpec resultSpec)208 public void addPhiInsnForReg(RegisterSpec resultSpec) { 209 insns.add(0, new PhiInsn(resultSpec, this)); 210 } 211 212 /** 213 * Adds an insn to the head of this basic block, just after any phi 214 * insns. 215 * 216 * @param insn {@code non-null;} rop-form insn to add 217 */ addInsnToHead(Insn insn)218 public void addInsnToHead(Insn insn) { 219 SsaInsn newInsn = SsaInsn.makeFromRop(insn, this); 220 insns.add(getCountPhiInsns(), newInsn); 221 parent.onInsnAdded(newInsn); 222 } 223 224 /** 225 * Replaces the last insn in this block. The provided insn must have 226 * some branchingness. 227 * 228 * @param insn {@code non-null;} rop-form insn to add, which must branch. 229 */ replaceLastInsn(Insn insn)230 public void replaceLastInsn(Insn insn) { 231 if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) { 232 throw new IllegalArgumentException("last insn must branch"); 233 } 234 235 SsaInsn oldInsn = insns.get(insns.size() - 1); 236 SsaInsn newInsn = SsaInsn.makeFromRop(insn, this); 237 238 insns.set(insns.size() - 1, newInsn); 239 240 parent.onInsnRemoved(oldInsn); 241 parent.onInsnAdded(newInsn); 242 } 243 244 /** 245 * Visits each phi insn. 246 * 247 * @param v {@code non-null;} the callback 248 */ forEachPhiInsn(PhiInsn.Visitor v)249 public void forEachPhiInsn(PhiInsn.Visitor v) { 250 int sz = insns.size(); 251 252 for (int i = 0; i < sz; i++) { 253 SsaInsn insn = insns.get(i); 254 if (insn instanceof PhiInsn) { 255 v.visitPhiInsn((PhiInsn) insn); 256 } else { 257 /* 258 * Presently we assume PhiInsn's are in a continuous 259 * block at the top of the list 260 */ 261 break; 262 } 263 } 264 } 265 266 /** 267 * Deletes all phi insns. Do this after adding appropriate move insns. 268 */ removeAllPhiInsns()269 public void removeAllPhiInsns() { 270 /* 271 * Presently we assume PhiInsn's are in a continuous 272 * block at the top of the list. 273 */ 274 275 insns.subList(0, getCountPhiInsns()).clear(); 276 } 277 278 /** 279 * Gets the number of phi insns at the top of this basic block. 280 * 281 * @return count of phi insns 282 */ getCountPhiInsns()283 private int getCountPhiInsns() { 284 int countPhiInsns; 285 286 int sz = insns.size(); 287 for (countPhiInsns = 0; countPhiInsns < sz; countPhiInsns++) { 288 SsaInsn insn = insns.get(countPhiInsns); 289 if (!(insn instanceof PhiInsn)) { 290 break; 291 } 292 } 293 294 return countPhiInsns; 295 } 296 297 /** 298 * @return {@code non-null;} the (mutable) instruction list for this block, 299 * with phi insns at the beginning 300 */ getInsns()301 public ArrayList<SsaInsn> getInsns() { 302 return insns; 303 } 304 305 /** 306 * @return {@code non-null;} the (mutable) list of phi insns for this block 307 */ getPhiInsns()308 public List<SsaInsn> getPhiInsns() { 309 return insns.subList(0, getCountPhiInsns()); 310 } 311 312 /** 313 * @return the block index of this block 314 */ getIndex()315 public int getIndex() { 316 return index; 317 } 318 319 /** 320 * @return the label of this block in rop form 321 */ getRopLabel()322 public int getRopLabel() { 323 return ropLabel; 324 } 325 326 /** 327 * @return the label of this block in rop form as a hex string 328 */ getRopLabelString()329 public String getRopLabelString() { 330 return Hex.u2(ropLabel); 331 } 332 333 /** 334 * @return {@code non-null;} predecessors set, indexed by block index 335 */ getPredecessors()336 public BitSet getPredecessors() { 337 return predecessors; 338 } 339 340 /** 341 * @return {@code non-null;} successors set, indexed by block index 342 */ getSuccessors()343 public BitSet getSuccessors() { 344 return successors; 345 } 346 347 /** 348 * @return {@code non-null;} ordered successor list, containing block 349 * indicies 350 */ getSuccessorList()351 public IntList getSuccessorList() { 352 return successorList; 353 } 354 355 /** 356 * @return {@code >= -1;} block index of primary successor or 357 * {@code -1} if no primary successor 358 */ getPrimarySuccessorIndex()359 public int getPrimarySuccessorIndex() { 360 return primarySuccessor; 361 } 362 363 /** 364 * @return rop label of primary successor 365 */ getPrimarySuccessorRopLabel()366 public int getPrimarySuccessorRopLabel() { 367 return parent.blockIndexToRopLabel(primarySuccessor); 368 } 369 370 /** 371 * @return {@code null-ok;} the primary successor block or {@code null} 372 * if there is none 373 */ getPrimarySuccessor()374 public SsaBasicBlock getPrimarySuccessor() { 375 if (primarySuccessor < 0) { 376 return null; 377 } else { 378 return parent.getBlocks().get(primarySuccessor); 379 } 380 } 381 382 /** 383 * @return successor list of rop labels 384 */ getRopLabelSuccessorList()385 public IntList getRopLabelSuccessorList() { 386 IntList result = new IntList(successorList.size()); 387 388 int sz = successorList.size(); 389 390 for (int i = 0; i < sz; i++) { 391 result.add(parent.blockIndexToRopLabel(successorList.get(i))); 392 } 393 return result; 394 } 395 396 /** 397 * @return {@code non-null;} method that contains this block 398 */ getParent()399 public SsaMethod getParent() { 400 return parent; 401 } 402 403 /** 404 * Inserts a new empty GOTO block as a predecessor to this block. 405 * All previous predecessors will be predecessors to the new block. 406 * 407 * @return {@code non-null;} an appropriately-constructed instance 408 */ insertNewPredecessor()409 public SsaBasicBlock insertNewPredecessor() { 410 SsaBasicBlock newPred = parent.makeNewGotoBlock(); 411 412 // Update the new block. 413 newPred.predecessors = predecessors; 414 newPred.successors.set(index) ; 415 newPred.successorList.add(index); 416 newPred.primarySuccessor = index; 417 418 419 // Update us. 420 predecessors = new BitSet(parent.getBlocks().size()); 421 predecessors.set(newPred.index); 422 423 // Update our (soon-to-be) old predecessors. 424 for (int i = newPred.predecessors.nextSetBit(0); i >= 0; 425 i = newPred.predecessors.nextSetBit(i + 1)) { 426 427 SsaBasicBlock predBlock = parent.getBlocks().get(i); 428 429 predBlock.replaceSuccessor(index, newPred.index); 430 } 431 432 return newPred; 433 } 434 435 /** 436 * Constructs and inserts a new empty GOTO block {@code Z} between 437 * this block ({@code A}) and a current successor block 438 * ({@code B}). The new block will replace B as A's successor and 439 * A as B's predecessor. A and B will no longer be directly connected. 440 * If B is listed as a successor multiple times, all references 441 * are replaced. 442 * 443 * @param other current successor (B) 444 * @return {@code non-null;} an appropriately-constructed instance 445 */ insertNewSuccessor(SsaBasicBlock other)446 public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) { 447 SsaBasicBlock newSucc = parent.makeNewGotoBlock(); 448 449 if (!successors.get(other.index)) { 450 throw new RuntimeException("Block " + other.getRopLabelString() 451 + " not successor of " + getRopLabelString()); 452 } 453 454 // Update the new block. 455 newSucc.predecessors.set(this.index); 456 newSucc.successors.set(other.index) ; 457 newSucc.successorList.add(other.index); 458 newSucc.primarySuccessor = other.index; 459 460 // Update us. 461 for (int i = successorList.size() - 1 ; i >= 0; i--) { 462 if (successorList.get(i) == other.index) { 463 successorList.set(i, newSucc.index); 464 } 465 } 466 467 if (primarySuccessor == other.index) { 468 primarySuccessor = newSucc.index; 469 } 470 successors.clear(other.index); 471 successors.set(newSucc.index); 472 473 // Update "other". 474 other.predecessors.set(newSucc.index); 475 other.predecessors.set(index, successors.get(other.index)); 476 477 return newSucc; 478 } 479 480 /** 481 * Replaces an old successor with a new successor. This will throw 482 * RuntimeException if {@code oldIndex} was not a successor. 483 * 484 * @param oldIndex index of old successor block 485 * @param newIndex index of new successor block 486 */ replaceSuccessor(int oldIndex, int newIndex)487 public void replaceSuccessor(int oldIndex, int newIndex) { 488 if (oldIndex == newIndex) { 489 return; 490 } 491 492 // Update us. 493 successors.set(newIndex); 494 495 if (primarySuccessor == oldIndex) { 496 primarySuccessor = newIndex; 497 } 498 499 for (int i = successorList.size() - 1 ; i >= 0; i--) { 500 if (successorList.get(i) == oldIndex) { 501 successorList.set(i, newIndex); 502 } 503 } 504 505 successors.clear(oldIndex); 506 507 // Update new successor. 508 parent.getBlocks().get(newIndex).predecessors.set(index); 509 510 // Update old successor. 511 parent.getBlocks().get(oldIndex).predecessors.clear(index); 512 } 513 514 /** 515 * Removes a successor from this block's successor list. 516 * 517 * @param oldIndex index of successor block to remove 518 */ removeSuccessor(int oldIndex)519 public void removeSuccessor(int oldIndex) { 520 int removeIndex = 0; 521 522 for (int i = successorList.size() - 1; i >= 0; i--) { 523 if (successorList.get(i) == oldIndex) { 524 removeIndex = i; 525 } else { 526 primarySuccessor = successorList.get(i); 527 } 528 } 529 530 successorList.removeIndex(removeIndex); 531 successors.clear(oldIndex); 532 parent.getBlocks().get(oldIndex).predecessors.clear(index); 533 } 534 535 /** 536 * Attaches block to an exit block if necessary. If this block 537 * is not an exit predecessor or is the exit block, this block does 538 * nothing. For use by {@link com.android.dx.ssa.SsaMethod#makeExitBlock} 539 * 540 * @param exitBlock {@code non-null;} exit block 541 */ exitBlockFixup(SsaBasicBlock exitBlock)542 public void exitBlockFixup(SsaBasicBlock exitBlock) { 543 if (this == exitBlock) { 544 return; 545 } 546 547 if (successorList.size() == 0) { 548 /* 549 * This is an exit predecessor. 550 * Set the successor to the exit block 551 */ 552 successors.set(exitBlock.index); 553 successorList.add(exitBlock.index); 554 primarySuccessor = exitBlock.index; 555 exitBlock.predecessors.set(this.index); 556 } 557 } 558 559 /** 560 * Adds a move instruction to the end of this basic block, just 561 * before the last instruction. If the result of the final instruction 562 * is the source in question, then the move is placed at the beginning of 563 * the primary successor block. This is for unversioned registers. 564 * 565 * @param result move destination 566 * @param source move source 567 */ addMoveToEnd(RegisterSpec result, RegisterSpec source)568 public void addMoveToEnd(RegisterSpec result, RegisterSpec source) { 569 /* 570 * Check that there are no other successors otherwise we may 571 * insert a move that affects those (b/69128828). 572 */ 573 if (successors.cardinality() > 1) { 574 throw new IllegalStateException("Inserting a move to a block with multiple successors"); 575 } 576 577 if (result.getReg() == source.getReg()) { 578 // Sometimes we end up with no-op moves. Ignore them here. 579 return; 580 } 581 582 /* 583 * The last Insn has to be a normal SSA insn: a phi can't branch 584 * or return or cause an exception, etc. 585 */ 586 NormalSsaInsn lastInsn; 587 lastInsn = (NormalSsaInsn)insns.get(insns.size()-1); 588 589 if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) { 590 /* 591 * The final insn in this block has a source or result 592 * register, and the moves we may need to place and 593 * schedule may interfere. We need to insert this 594 * instruction at the beginning of the primary successor 595 * block instead. We know this is safe, because when we 596 * edge-split earlier, we ensured that each successor has 597 * only us as a predecessor. 598 */ 599 600 for (int i = successors.nextSetBit(0) 601 ; i >= 0 602 ; i = successors.nextSetBit(i + 1)) { 603 604 SsaBasicBlock succ; 605 606 succ = parent.getBlocks().get(i); 607 succ.addMoveToBeginning(result, source); 608 } 609 } else { 610 /* 611 * We can safely add a move to the end of the block just 612 * before the last instruction, because the final insn does 613 * not assign to anything. 614 */ 615 RegisterSpecList sources = RegisterSpecList.make(source); 616 NormalSsaInsn toAdd = new NormalSsaInsn( 617 new PlainInsn(Rops.opMove(result.getType()), 618 SourcePosition.NO_INFO, result, sources), this); 619 620 insns.add(insns.size() - 1, toAdd); 621 622 movesFromPhisAtEnd++; 623 } 624 } 625 626 /** 627 * Adds a move instruction after the phi insn block. 628 * 629 * @param result move destination 630 * @param source move source 631 */ addMoveToBeginning(RegisterSpec result, RegisterSpec source)632 public void addMoveToBeginning (RegisterSpec result, RegisterSpec source) { 633 if (result.getReg() == source.getReg()) { 634 // Sometimes we end up with no-op moves. Ignore them here. 635 return; 636 } 637 638 RegisterSpecList sources = RegisterSpecList.make(source); 639 NormalSsaInsn toAdd = new NormalSsaInsn( 640 new PlainInsn(Rops.opMove(result.getType()), 641 SourcePosition.NO_INFO, result, sources), this); 642 643 insns.add(getCountPhiInsns(), toAdd); 644 movesFromPhisAtBeginning++; 645 } 646 647 /** 648 * Sets the register as used in a bitset, taking into account its 649 * category/width. 650 * 651 * @param regsUsed set, indexed by register number 652 * @param rs register to mark as used 653 */ setRegsUsed(BitSet regsUsed, RegisterSpec rs)654 private static void setRegsUsed (BitSet regsUsed, RegisterSpec rs) { 655 regsUsed.set(rs.getReg()); 656 if (rs.getCategory() > 1) { 657 regsUsed.set(rs.getReg() + 1); 658 } 659 } 660 661 /** 662 * Checks to see if the register is used in a bitset, taking 663 * into account its category/width. 664 * 665 * @param regsUsed set, indexed by register number 666 * @param rs register to mark as used 667 * @return true if register is fully or partially (for the case of wide 668 * registers) used. 669 */ checkRegUsed(BitSet regsUsed, RegisterSpec rs)670 private static boolean checkRegUsed (BitSet regsUsed, RegisterSpec rs) { 671 int reg = rs.getReg(); 672 int category = rs.getCategory(); 673 674 return regsUsed.get(reg) 675 || (category == 2 ? regsUsed.get(reg + 1) : false); 676 } 677 678 /** 679 * Ensures that all move operations in this block occur such that 680 * reads of any register happen before writes to that register. 681 * NOTE: caller is expected to returnSpareRegisters()! 682 * 683 * TODO: See Briggs, et al "Practical Improvements to the Construction and 684 * Destruction of Static Single Assignment Form" section 5. a) This can 685 * be done in three passes. 686 * 687 * @param toSchedule List of instructions. Must consist only of moves. 688 */ scheduleUseBeforeAssigned(List<SsaInsn> toSchedule)689 private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) { 690 BitSet regsUsedAsSources = new BitSet(parent.getRegCount()); 691 692 // TODO: Get rid of this. 693 BitSet regsUsedAsResults = new BitSet(parent.getRegCount()); 694 695 int sz = toSchedule.size(); 696 697 int insertPlace = 0; 698 699 while (insertPlace < sz) { 700 int oldInsertPlace = insertPlace; 701 702 // Record all registers used as sources in this block. 703 for (int i = insertPlace; i < sz; i++) { 704 setRegsUsed(regsUsedAsSources, 705 toSchedule.get(i).getSources().get(0)); 706 707 setRegsUsed(regsUsedAsResults, 708 toSchedule.get(i).getResult()); 709 } 710 711 /* 712 * If there are no circular dependencies, then there exists 713 * n instructions where n > 1 whose result is not used as a source. 714 */ 715 for (int i = insertPlace; i <sz; i++) { 716 SsaInsn insn = toSchedule.get(i); 717 718 /* 719 * Move these n registers to the front, since they overwrite 720 * nothing. 721 */ 722 if (!checkRegUsed(regsUsedAsSources, insn.getResult())) { 723 Collections.swap(toSchedule, i, insertPlace++); 724 } 725 } 726 727 /* 728 * If we've made no progress in this iteration, there's a 729 * circular dependency. Split it using the temp reg. 730 */ 731 if (oldInsertPlace == insertPlace) { 732 733 SsaInsn insnToSplit = null; 734 735 // Find an insn whose result is used as a source. 736 for (int i = insertPlace; i < sz; i++) { 737 SsaInsn insn = toSchedule.get(i); 738 if (checkRegUsed(regsUsedAsSources, insn.getResult()) 739 && checkRegUsed(regsUsedAsResults, 740 insn.getSources().get(0))) { 741 742 insnToSplit = insn; 743 /* 744 * We're going to split this insn; move it to the 745 * front. 746 */ 747 Collections.swap(toSchedule, insertPlace, i); 748 break; 749 } 750 } 751 752 // At least one insn will be set above. 753 754 RegisterSpec result = insnToSplit.getResult(); 755 RegisterSpec tempSpec = result.withReg( 756 parent.borrowSpareRegister(result.getCategory())); 757 758 NormalSsaInsn toAdd = new NormalSsaInsn( 759 new PlainInsn(Rops.opMove(result.getType()), 760 SourcePosition.NO_INFO, 761 tempSpec, 762 insnToSplit.getSources()), this); 763 764 toSchedule.add(insertPlace++, toAdd); 765 766 RegisterSpecList newSources = RegisterSpecList.make(tempSpec); 767 768 NormalSsaInsn toReplace = new NormalSsaInsn( 769 new PlainInsn(Rops.opMove(result.getType()), 770 SourcePosition.NO_INFO, 771 result, 772 newSources), this); 773 774 toSchedule.set(insertPlace, toReplace); 775 776 // The size changed. 777 sz = toSchedule.size(); 778 } 779 780 regsUsedAsSources.clear(); 781 regsUsedAsResults.clear(); 782 } 783 } 784 785 /** 786 * Adds {@code regV} to the live-out list for this block. This is called 787 * by the liveness analyzer. 788 * 789 * @param regV register that is live-out for this block. 790 */ addLiveOut(int regV)791 public void addLiveOut (int regV) { 792 if (liveOut == null) { 793 liveOut = SetFactory.makeLivenessSet(parent.getRegCount()); 794 } 795 796 liveOut.add(regV); 797 } 798 799 /** 800 * Adds {@code regV} to the live-in list for this block. This is 801 * called by the liveness analyzer. 802 * 803 * @param regV register that is live-in for this block. 804 */ addLiveIn(int regV)805 public void addLiveIn (int regV) { 806 if (liveIn == null) { 807 liveIn = SetFactory.makeLivenessSet(parent.getRegCount()); 808 } 809 810 liveIn.add(regV); 811 } 812 813 /** 814 * Returns the set of live-in registers. Valid after register 815 * interference graph has been generated, otherwise empty. 816 * 817 * @return {@code non-null;} live-in register set. 818 */ getLiveInRegs()819 public IntSet getLiveInRegs() { 820 if (liveIn == null) { 821 liveIn = SetFactory.makeLivenessSet(parent.getRegCount()); 822 } 823 return liveIn; 824 } 825 826 /** 827 * Returns the set of live-out registers. Valid after register 828 * interference graph has been generated, otherwise empty. 829 * 830 * @return {@code non-null;} live-out register set 831 */ getLiveOutRegs()832 public IntSet getLiveOutRegs() { 833 if (liveOut == null) { 834 liveOut = SetFactory.makeLivenessSet(parent.getRegCount()); 835 } 836 return liveOut; 837 } 838 839 /** 840 * @return true if this is the one-and-only exit block for this method 841 */ isExitBlock()842 public boolean isExitBlock() { 843 return index == parent.getExitBlockIndex(); 844 } 845 846 /** 847 * Sorts move instructions added via {@code addMoveToEnd} during 848 * phi removal so that results don't overwrite sources that are used. 849 * For use after all phis have been removed and all calls to 850 * addMoveToEnd() have been made.<p> 851 * 852 * This is necessary because copy-propogation may have left us in a state 853 * where the same basic block has the same register as a phi operand 854 * and a result. In this case, the register in the phi operand always 855 * refers value before any other phis have executed. 856 */ scheduleMovesFromPhis()857 public void scheduleMovesFromPhis() { 858 if (movesFromPhisAtBeginning > 1) { 859 List<SsaInsn> toSchedule; 860 861 toSchedule = insns.subList(0, movesFromPhisAtBeginning); 862 863 scheduleUseBeforeAssigned(toSchedule); 864 865 SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning); 866 867 /* 868 * TODO: It's actually possible that this case never happens, 869 * because a move-exception block, having only one predecessor 870 * in SSA form, perhaps is never on a dominance frontier. 871 */ 872 if (firstNonPhiMoveInsn.isMoveException()) { 873 if (true) { 874 /* 875 * We've yet to observe this case, and if it can 876 * occur the code written to handle it probably 877 * does not work. 878 */ 879 throw new RuntimeException( 880 "Unexpected: moves from " 881 +"phis before move-exception"); 882 } else { 883 /* 884 * A move-exception insn must be placed first in this block 885 * We need to move it there, and deal with possible 886 * interference. 887 */ 888 boolean moveExceptionInterferes = false; 889 890 int moveExceptionResult 891 = firstNonPhiMoveInsn.getResult().getReg(); 892 893 /* 894 * Does the move-exception result reg interfere with the 895 * phi moves? 896 */ 897 for (SsaInsn insn : toSchedule) { 898 if (insn.isResultReg(moveExceptionResult) 899 || insn.isRegASource(moveExceptionResult)) { 900 moveExceptionInterferes = true; 901 break; 902 } 903 } 904 905 if (!moveExceptionInterferes) { 906 // This is the easy case. 907 insns.remove(movesFromPhisAtBeginning); 908 insns.add(0, firstNonPhiMoveInsn); 909 } else { 910 /* 911 * We need to move the result to a spare reg 912 * and move it back. 913 */ 914 RegisterSpec originalResultSpec 915 = firstNonPhiMoveInsn.getResult(); 916 int spareRegister = parent.borrowSpareRegister( 917 originalResultSpec.getCategory()); 918 919 // We now move it to a spare register. 920 firstNonPhiMoveInsn.changeResultReg(spareRegister); 921 RegisterSpec tempSpec = 922 firstNonPhiMoveInsn.getResult(); 923 924 insns.add(0, firstNonPhiMoveInsn); 925 926 // And here we move it back. 927 928 NormalSsaInsn toAdd = new NormalSsaInsn( 929 new PlainInsn( 930 Rops.opMove(tempSpec.getType()), 931 SourcePosition.NO_INFO, 932 originalResultSpec, 933 RegisterSpecList.make(tempSpec)), 934 this); 935 936 937 /* 938 * Place it immediately after the phi-moves, 939 * overwriting the move-exception that was there. 940 */ 941 insns.set(movesFromPhisAtBeginning + 1, toAdd); 942 } 943 } 944 } 945 } 946 947 if (movesFromPhisAtEnd > 1) { 948 scheduleUseBeforeAssigned( 949 insns.subList(insns.size() - movesFromPhisAtEnd - 1, 950 insns.size() - 1)); 951 } 952 953 // Return registers borrowed here and in scheduleUseBeforeAssigned(). 954 parent.returnSpareRegisters(); 955 956 } 957 958 /** 959 * Visits all insns in this block. 960 * 961 * @param visitor {@code non-null;} callback interface 962 */ forEachInsn(SsaInsn.Visitor visitor)963 public void forEachInsn(SsaInsn.Visitor visitor) { 964 // This gets called a LOT, and not using an iterator 965 // saves a lot of allocations and reduces memory usage 966 int len = insns.size(); 967 for (int i = 0; i < len; i++) { 968 insns.get(i).accept(visitor); 969 } 970 } 971 972 /** {@inheritDoc} */ 973 @Override toString()974 public String toString() { 975 return "{" + index + ":" + Hex.u2(ropLabel) + '}'; 976 } 977 978 /** 979 * Visitor interface for basic blocks. 980 */ 981 public interface Visitor { 982 /** 983 * Indicates a block has been visited by an iterator method. 984 * 985 * @param v {@code non-null;} block visited 986 * @param parent {@code null-ok;} parent node if applicable 987 */ visitBlock(SsaBasicBlock v, SsaBasicBlock parent)988 void visitBlock (SsaBasicBlock v, SsaBasicBlock parent); 989 } 990 991 /** 992 * Label comparator. 993 */ 994 public static final class LabelComparator 995 implements Comparator<SsaBasicBlock> { 996 /** {@inheritDoc} */ 997 @Override compare(SsaBasicBlock b1, SsaBasicBlock b2)998 public int compare(SsaBasicBlock b1, SsaBasicBlock b2) { 999 int label1 = b1.ropLabel; 1000 int label2 = b2.ropLabel; 1001 1002 if (label1 < label2) { 1003 return -1; 1004 } else if (label1 > label2) { 1005 return 1; 1006 } else { 1007 return 0; 1008 } 1009 } 1010 } 1011 } 1012