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 34 import java.util.ArrayList; 35 import java.util.BitSet; 36 import java.util.Collections; 37 import java.util.Comparator; 38 import java.util.List; 39 40 /** 41 * An SSA representation of a basic block. 42 */ 43 public final class SsaBasicBlock { 44 /** 45 * {@code non-null;} comparator for instances of this class that 46 * just compares block labels 47 */ 48 public static final Comparator<SsaBasicBlock> LABEL_COMPARATOR = 49 new LabelComparator(); 50 51 /** {@code non-null;} insn list associated with this instance */ 52 private ArrayList<SsaInsn> insns; 53 54 /** {@code non-null;} predecessor set (by block list index) */ 55 private BitSet predecessors; 56 57 /** {@code non-null;} successor set (by block list index) */ 58 private BitSet successors; 59 60 /** 61 * {@code non-null;} ordered successor list 62 * (same block may be listed more than once) 63 */ 64 private IntList successorList; 65 66 /** 67 * block list index of primary successor, or {@code -1} for no primary 68 * successor 69 */ 70 private int primarySuccessor = -1; 71 72 /** label of block in rop form */ 73 private int ropLabel; 74 75 /** {@code non-null;} method we belong to */ 76 private SsaMethod parent; 77 78 /** our index into parent.getBlock() */ 79 private int index; 80 81 /** list of dom children */ 82 private final ArrayList<SsaBasicBlock> domChildren; 83 84 /** 85 * the number of moves added to the end of the block during the 86 * phi-removal process. Retained for subsequent move scheduling. 87 */ 88 private int movesFromPhisAtEnd = 0; 89 90 /** 91 * the number of moves added to the beginning of the block during the 92 * phi-removal process. Retained for subsequent move scheduling. 93 */ 94 private int movesFromPhisAtBeginning = 0; 95 96 /** 97 * contains last computed value of reachability of this block, or -1 98 * if reachability hasn't been calculated yet 99 */ 100 private int reachable = -1; 101 102 /** 103 * {@code null-ok;} indexed by reg: the regs that are live-in at 104 * this block 105 */ 106 private IntSet liveIn; 107 108 /** 109 * {@code null-ok;} indexed by reg: the regs that are live-out at 110 * this block 111 */ 112 private IntSet liveOut; 113 114 /** 115 * Creates a new empty basic block. 116 * 117 * @param basicBlockIndex index this block will have 118 * @param ropLabel original rop-form label 119 * @param parent method of this block 120 */ SsaBasicBlock(final int basicBlockIndex, final int ropLabel, final SsaMethod parent)121 public SsaBasicBlock(final int basicBlockIndex, final int ropLabel, 122 final SsaMethod parent) { 123 this.parent = parent; 124 this.index = basicBlockIndex; 125 this.insns = new ArrayList<SsaInsn>(); 126 this.ropLabel = ropLabel; 127 128 this.predecessors = new BitSet(parent.getBlocks().size()); 129 this.successors = new BitSet(parent.getBlocks().size()); 130 this.successorList = new IntList(); 131 132 domChildren = new ArrayList<SsaBasicBlock>(); 133 } 134 135 /** 136 * Creates a new SSA basic block from a ROP form basic block. 137 * 138 * @param rmeth original method 139 * @param basicBlockIndex index this block will have 140 * @param parent method of this block predecessor set will be 141 * updated 142 * @return new instance 143 */ newFromRop(RopMethod rmeth, int basicBlockIndex, final SsaMethod parent)144 public static SsaBasicBlock newFromRop(RopMethod rmeth, 145 int basicBlockIndex, final SsaMethod parent) { 146 BasicBlockList ropBlocks = rmeth.getBlocks(); 147 BasicBlock bb = ropBlocks.get(basicBlockIndex); 148 SsaBasicBlock result = 149 new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent); 150 InsnList ropInsns = bb.getInsns(); 151 152 result.insns.ensureCapacity(ropInsns.size()); 153 154 for (int i = 0, sz = ropInsns.size() ; i < sz ; i++) { 155 result.insns.add(new NormalSsaInsn (ropInsns.get(i), result)); 156 } 157 158 result.predecessors = SsaMethod.bitSetFromLabelList( 159 ropBlocks, 160 rmeth.labelToPredecessors(bb.getLabel())); 161 162 result.successors 163 = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors()); 164 165 result.successorList 166 = SsaMethod.indexListFromLabelList(ropBlocks, 167 bb.getSuccessors()); 168 169 if (result.successorList.size() != 0) { 170 int primarySuccessor = bb.getPrimarySuccessor(); 171 172 result.primarySuccessor = (primarySuccessor < 0) 173 ? -1 : ropBlocks.indexOfLabel(primarySuccessor); 174 } 175 176 return result; 177 } 178 179 /** 180 * Adds a basic block as a dom child for this block. Used when constructing 181 * the dom tree. 182 * 183 * @param child {@code non-null;} new dom child 184 */ addDomChild(SsaBasicBlock child)185 public void addDomChild(SsaBasicBlock child) { 186 domChildren.add(child); 187 } 188 189 /** 190 * Gets the dom children for this node. Don't modify this list. 191 * 192 * @return {@code non-null;} list of dom children 193 */ getDomChildren()194 public ArrayList<SsaBasicBlock> getDomChildren() { 195 return domChildren; 196 } 197 198 /** 199 * Adds a phi insn to the beginning of this block. The result type of 200 * the phi will be set to void, to indicate that it's currently unknown. 201 * 202 * @param reg {@code >=0;} result reg 203 */ addPhiInsnForReg(int reg)204 public void addPhiInsnForReg(int reg) { 205 insns.add(0, new PhiInsn(reg, this)); 206 } 207 208 /** 209 * Adds a phi insn to the beginning of this block. This is to be used 210 * when the result type or local-association can be determined at phi 211 * insert time. 212 * 213 * @param resultSpec {@code non-null;} reg 214 */ addPhiInsnForReg(RegisterSpec resultSpec)215 public void addPhiInsnForReg(RegisterSpec resultSpec) { 216 insns.add(0, new PhiInsn(resultSpec, this)); 217 } 218 219 /** 220 * Adds an insn to the head of this basic block, just after any phi 221 * insns. 222 * 223 * @param insn {@code non-null;} rop-form insn to add 224 */ addInsnToHead(Insn insn)225 public void addInsnToHead(Insn insn) { 226 SsaInsn newInsn = SsaInsn.makeFromRop(insn, this); 227 insns.add(getCountPhiInsns(), newInsn); 228 parent.onInsnAdded(newInsn); 229 } 230 231 /** 232 * Replaces the last insn in this block. The provided insn must have 233 * some branchingness. 234 * 235 * @param insn {@code non-null;} rop-form insn to add, which must branch. 236 */ replaceLastInsn(Insn insn)237 public void replaceLastInsn(Insn insn) { 238 if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) { 239 throw new IllegalArgumentException("last insn must branch"); 240 } 241 242 SsaInsn oldInsn = insns.get(insns.size() - 1); 243 SsaInsn newInsn = SsaInsn.makeFromRop(insn, this); 244 245 insns.set(insns.size() - 1, newInsn); 246 247 parent.onInsnRemoved(oldInsn); 248 parent.onInsnAdded(newInsn); 249 } 250 251 /** 252 * Visits each phi insn. 253 * 254 * @param v {@code non-null;} the callback 255 */ forEachPhiInsn(PhiInsn.Visitor v)256 public void forEachPhiInsn(PhiInsn.Visitor v) { 257 int sz = insns.size(); 258 259 for (int i = 0; i < sz; i++) { 260 SsaInsn insn = insns.get(i); 261 if (insn instanceof PhiInsn) { 262 v.visitPhiInsn((PhiInsn) insn); 263 } else { 264 /* 265 * Presently we assume PhiInsn's are in a continuous 266 * block at the top of the list 267 */ 268 break; 269 } 270 } 271 } 272 273 /** 274 * Deletes all phi insns. Do this after adding appropriate move insns. 275 */ removeAllPhiInsns()276 public void removeAllPhiInsns() { 277 /* 278 * Presently we assume PhiInsn's are in a continuous 279 * block at the top of the list. 280 */ 281 282 insns.subList(0, getCountPhiInsns()).clear(); 283 } 284 285 /** 286 * Gets the number of phi insns at the top of this basic block. 287 * 288 * @return count of phi insns 289 */ getCountPhiInsns()290 private int getCountPhiInsns() { 291 int countPhiInsns; 292 293 int sz = insns.size(); 294 for (countPhiInsns = 0; countPhiInsns < sz; countPhiInsns++) { 295 SsaInsn insn = insns.get(countPhiInsns); 296 if (!(insn instanceof PhiInsn)) { 297 break; 298 } 299 } 300 301 return countPhiInsns; 302 } 303 304 /** 305 * @return {@code non-null;} the (mutable) instruction list for this block, 306 * with phi insns at the beginning 307 */ getInsns()308 public ArrayList<SsaInsn> getInsns() { 309 return insns; 310 } 311 312 /** 313 * @return {@code non-null;} the (mutable) list of phi insns for this block 314 */ getPhiInsns()315 public List<SsaInsn> getPhiInsns() { 316 return insns.subList(0, getCountPhiInsns()); 317 } 318 319 /** 320 * @return the block index of this block 321 */ getIndex()322 public int getIndex() { 323 return index; 324 } 325 326 /** 327 * @return the label of this block in rop form 328 */ getRopLabel()329 public int getRopLabel() { 330 return ropLabel; 331 } 332 333 /** 334 * @return the label of this block in rop form as a hex string 335 */ getRopLabelString()336 public String getRopLabelString() { 337 return Hex.u2(ropLabel); 338 } 339 340 /** 341 * @return {@code non-null;} predecessors set, indexed by block index 342 */ getPredecessors()343 public BitSet getPredecessors() { 344 return predecessors; 345 } 346 347 /** 348 * @return {@code non-null;} successors set, indexed by block index 349 */ getSuccessors()350 public BitSet getSuccessors() { 351 return successors; 352 } 353 354 /** 355 * @return {@code non-null;} ordered successor list, containing block 356 * indicies 357 */ getSuccessorList()358 public IntList getSuccessorList() { 359 return successorList; 360 } 361 362 /** 363 * @return {@code >= -1;} block index of primary successor or 364 * {@code -1} if no primary successor 365 */ getPrimarySuccessorIndex()366 public int getPrimarySuccessorIndex() { 367 return primarySuccessor; 368 } 369 370 /** 371 * @return rop label of primary successor 372 */ getPrimarySuccessorRopLabel()373 public int getPrimarySuccessorRopLabel() { 374 return parent.blockIndexToRopLabel(primarySuccessor); 375 } 376 377 /** 378 * @return {@code null-ok;} the primary successor block or {@code null} 379 * if there is none 380 */ getPrimarySuccessor()381 public SsaBasicBlock getPrimarySuccessor() { 382 if (primarySuccessor < 0) { 383 return null; 384 } else { 385 return parent.getBlocks().get(primarySuccessor); 386 } 387 } 388 389 /** 390 * @return successor list of rop labels 391 */ getRopLabelSuccessorList()392 public IntList getRopLabelSuccessorList() { 393 IntList result = new IntList(successorList.size()); 394 395 int sz = successorList.size(); 396 397 for (int i = 0; i < sz; i++) { 398 result.add(parent.blockIndexToRopLabel(successorList.get(i))); 399 } 400 return result; 401 } 402 403 /** 404 * @return {@code non-null;} method that contains this block 405 */ getParent()406 public SsaMethod getParent() { 407 return parent; 408 } 409 410 /** 411 * Inserts a new empty GOTO block as a predecessor to this block. 412 * All previous predecessors will be predecessors to the new block. 413 * 414 * @return {@code non-null;} an appropriately-constructed instance 415 */ insertNewPredecessor()416 public SsaBasicBlock insertNewPredecessor() { 417 SsaBasicBlock newPred = parent.makeNewGotoBlock(); 418 419 // Update the new block. 420 newPred.predecessors = predecessors; 421 newPred.successors.set(index) ; 422 newPred.successorList.add(index); 423 newPred.primarySuccessor = index; 424 425 426 // Update us. 427 predecessors = new BitSet(parent.getBlocks().size()); 428 predecessors.set(newPred.index); 429 430 // Update our (soon-to-be) old predecessors. 431 for (int i = newPred.predecessors.nextSetBit(0); i >= 0; 432 i = newPred.predecessors.nextSetBit(i + 1)) { 433 434 SsaBasicBlock predBlock = parent.getBlocks().get(i); 435 436 predBlock.replaceSuccessor(index, newPred.index); 437 } 438 439 return newPred; 440 } 441 442 /** 443 * Constructs and inserts a new empty GOTO block {@code Z} between 444 * this block ({@code A}) and a current successor block 445 * ({@code B}). The new block will replace B as A's successor and 446 * A as B's predecessor. A and B will no longer be directly connected. 447 * If B is listed as a successor multiple times, all references 448 * are replaced. 449 * 450 * @param other current successor (B) 451 * @return {@code non-null;} an appropriately-constructed instance 452 */ insertNewSuccessor(SsaBasicBlock other)453 public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) { 454 SsaBasicBlock newSucc = parent.makeNewGotoBlock(); 455 456 if (!successors.get(other.index)) { 457 throw new RuntimeException("Block " + other.getRopLabelString() 458 + " not successor of " + getRopLabelString()); 459 } 460 461 // Update the new block. 462 newSucc.predecessors.set(this.index); 463 newSucc.successors.set(other.index) ; 464 newSucc.successorList.add(other.index); 465 newSucc.primarySuccessor = other.index; 466 467 // Update us. 468 for (int i = successorList.size() - 1 ; i >= 0; i--) { 469 if (successorList.get(i) == other.index) { 470 successorList.set(i, newSucc.index); 471 } 472 } 473 474 if (primarySuccessor == other.index) { 475 primarySuccessor = newSucc.index; 476 } 477 successors.clear(other.index); 478 successors.set(newSucc.index); 479 480 // Update "other". 481 other.predecessors.set(newSucc.index); 482 other.predecessors.set(index, successors.get(other.index)); 483 484 return newSucc; 485 } 486 487 /** 488 * Replaces an old successor with a new successor. This will throw 489 * RuntimeException if {@code oldIndex} was not a successor. 490 * 491 * @param oldIndex index of old successor block 492 * @param newIndex index of new successor block 493 */ replaceSuccessor(int oldIndex, int newIndex)494 public void replaceSuccessor(int oldIndex, int newIndex) { 495 if (oldIndex == newIndex) { 496 return; 497 } 498 499 // Update us. 500 successors.set(newIndex); 501 502 if (primarySuccessor == oldIndex) { 503 primarySuccessor = newIndex; 504 } 505 506 for (int i = successorList.size() - 1 ; i >= 0; i--) { 507 if (successorList.get(i) == oldIndex) { 508 successorList.set(i, newIndex); 509 } 510 } 511 512 successors.clear(oldIndex); 513 514 // Update new successor. 515 parent.getBlocks().get(newIndex).predecessors.set(index); 516 517 // Update old successor. 518 parent.getBlocks().get(oldIndex).predecessors.clear(index); 519 } 520 521 /** 522 * Removes a successor from this block's successor list. 523 * 524 * @param oldIndex index of successor block to remove 525 */ removeSuccessor(int oldIndex)526 public void removeSuccessor(int oldIndex) { 527 int removeIndex = 0; 528 529 for (int i = successorList.size() - 1; i >= 0; i--) { 530 if (successorList.get(i) == oldIndex) { 531 removeIndex = i; 532 } else { 533 primarySuccessor = successorList.get(i); 534 } 535 } 536 537 successorList.removeIndex(removeIndex); 538 successors.clear(oldIndex); 539 parent.getBlocks().get(oldIndex).predecessors.clear(index); 540 } 541 542 /** 543 * Attaches block to an exit block if necessary. If this block 544 * is not an exit predecessor or is the exit block, this block does 545 * nothing. For use by {@link com.android.dx.ssa.SsaMethod#makeExitBlock} 546 * 547 * @param exitBlock {@code non-null;} exit block 548 */ exitBlockFixup(SsaBasicBlock exitBlock)549 public void exitBlockFixup(SsaBasicBlock exitBlock) { 550 if (this == exitBlock) { 551 return; 552 } 553 554 if (successorList.size() == 0) { 555 /* 556 * This is an exit predecessor. 557 * Set the successor to the exit block 558 */ 559 successors.set(exitBlock.index); 560 successorList.add(exitBlock.index); 561 primarySuccessor = exitBlock.index; 562 exitBlock.predecessors.set(this.index); 563 } 564 } 565 566 /** 567 * Adds a move instruction to the end of this basic block, just 568 * before the last instruction. If the result of the final instruction 569 * is the source in question, then the move is placed at the beginning of 570 * the primary successor block. This is for unversioned registers. 571 * 572 * @param result move destination 573 * @param source move source 574 */ addMoveToEnd(RegisterSpec result, RegisterSpec source)575 public void addMoveToEnd(RegisterSpec result, RegisterSpec source) { 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 * Returns true if this block was last calculated to be reachable. 848 * Recalculates reachability if value has never been computed. 849 * 850 * @return {@code true} if reachable 851 */ isReachable()852 public boolean isReachable() { 853 if (reachable == -1) { 854 parent.computeReachability(); 855 } 856 return (reachable == 1); 857 } 858 859 /** 860 * Sets reachability of block to specified value 861 * 862 * @param reach new value of reachability for block 863 */ setReachable(int reach)864 public void setReachable(int reach) { 865 reachable = reach; 866 } 867 868 /** 869 * Sorts move instructions added via {@code addMoveToEnd} during 870 * phi removal so that results don't overwrite sources that are used. 871 * For use after all phis have been removed and all calls to 872 * addMoveToEnd() have been made.<p> 873 * 874 * This is necessary because copy-propogation may have left us in a state 875 * where the same basic block has the same register as a phi operand 876 * and a result. In this case, the register in the phi operand always 877 * refers value before any other phis have executed. 878 */ scheduleMovesFromPhis()879 public void scheduleMovesFromPhis() { 880 if (movesFromPhisAtBeginning > 1) { 881 List<SsaInsn> toSchedule; 882 883 toSchedule = insns.subList(0, movesFromPhisAtBeginning); 884 885 scheduleUseBeforeAssigned(toSchedule); 886 887 SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning); 888 889 /* 890 * TODO: It's actually possible that this case never happens, 891 * because a move-exception block, having only one predecessor 892 * in SSA form, perhaps is never on a dominance frontier. 893 */ 894 if (firstNonPhiMoveInsn.isMoveException()) { 895 if (true) { 896 /* 897 * We've yet to observe this case, and if it can 898 * occur the code written to handle it probably 899 * does not work. 900 */ 901 throw new RuntimeException( 902 "Unexpected: moves from " 903 +"phis before move-exception"); 904 } else { 905 /* 906 * A move-exception insn must be placed first in this block 907 * We need to move it there, and deal with possible 908 * interference. 909 */ 910 boolean moveExceptionInterferes = false; 911 912 int moveExceptionResult 913 = firstNonPhiMoveInsn.getResult().getReg(); 914 915 /* 916 * Does the move-exception result reg interfere with the 917 * phi moves? 918 */ 919 for (SsaInsn insn : toSchedule) { 920 if (insn.isResultReg(moveExceptionResult) 921 || insn.isRegASource(moveExceptionResult)) { 922 moveExceptionInterferes = true; 923 break; 924 } 925 } 926 927 if (!moveExceptionInterferes) { 928 // This is the easy case. 929 insns.remove(movesFromPhisAtBeginning); 930 insns.add(0, firstNonPhiMoveInsn); 931 } else { 932 /* 933 * We need to move the result to a spare reg 934 * and move it back. 935 */ 936 RegisterSpec originalResultSpec 937 = firstNonPhiMoveInsn.getResult(); 938 int spareRegister = parent.borrowSpareRegister( 939 originalResultSpec.getCategory()); 940 941 // We now move it to a spare register. 942 firstNonPhiMoveInsn.changeResultReg(spareRegister); 943 RegisterSpec tempSpec = 944 firstNonPhiMoveInsn.getResult(); 945 946 insns.add(0, firstNonPhiMoveInsn); 947 948 // And here we move it back. 949 950 NormalSsaInsn toAdd = new NormalSsaInsn( 951 new PlainInsn( 952 Rops.opMove(tempSpec.getType()), 953 SourcePosition.NO_INFO, 954 originalResultSpec, 955 RegisterSpecList.make(tempSpec)), 956 this); 957 958 959 /* 960 * Place it immediately after the phi-moves, 961 * overwriting the move-exception that was there. 962 */ 963 insns.set(movesFromPhisAtBeginning + 1, toAdd); 964 } 965 } 966 } 967 } 968 969 if (movesFromPhisAtEnd > 1) { 970 scheduleUseBeforeAssigned( 971 insns.subList(insns.size() - movesFromPhisAtEnd - 1, 972 insns.size() - 1)); 973 } 974 975 // Return registers borrowed here and in scheduleUseBeforeAssigned(). 976 parent.returnSpareRegisters(); 977 978 } 979 980 /** 981 * Visits all insns in this block. 982 * 983 * @param visitor {@code non-null;} callback interface 984 */ forEachInsn(SsaInsn.Visitor visitor)985 public void forEachInsn(SsaInsn.Visitor visitor) { 986 // This gets called a LOT, and not using an iterator 987 // saves a lot of allocations and reduces memory usage 988 int len = insns.size(); 989 for (int i = 0; i < len; i++) { 990 insns.get(i).accept(visitor); 991 } 992 } 993 994 /** {@inheritDoc} */ 995 @Override toString()996 public String toString() { 997 return "{" + index + ":" + Hex.u2(ropLabel) + '}'; 998 } 999 1000 /** 1001 * Visitor interface for basic blocks. 1002 */ 1003 public interface Visitor { 1004 /** 1005 * Indicates a block has been visited by an iterator method. 1006 * 1007 * @param v {@code non-null;} block visited 1008 * @param parent {@code null-ok;} parent node if applicable 1009 */ visitBlock(SsaBasicBlock v, SsaBasicBlock parent)1010 void visitBlock (SsaBasicBlock v, SsaBasicBlock parent); 1011 } 1012 1013 /** 1014 * Label comparator. 1015 */ 1016 public static final class LabelComparator 1017 implements Comparator<SsaBasicBlock> { 1018 /** {@inheritDoc} */ compare(SsaBasicBlock b1, SsaBasicBlock b2)1019 public int compare(SsaBasicBlock b1, SsaBasicBlock b2) { 1020 int label1 = b1.ropLabel; 1021 int label2 = b2.ropLabel; 1022 1023 if (label1 < label2) { 1024 return -1; 1025 } else if (label1 > label2) { 1026 return 1; 1027 } else { 1028 return 0; 1029 } 1030 } 1031 } 1032 } 1033