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