Home | History | Annotate | Download | only in ssa
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    308     public List<SsaInsn> getPhiInsns() {
    309         return insns.subList(0, getCountPhiInsns());
    310     }
    311 
    312     /**
    313      * @return the block index of this block
    314      */
    315     public int getIndex() {
    316         return index;
    317     }
    318 
    319     /**
    320      * @return the label of this block in rop form
    321      */
    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      */
    329     public String getRopLabelString() {
    330         return Hex.u2(ropLabel);
    331     }
    332 
    333     /**
    334      * @return {@code non-null;} predecessors set, indexed by block index
    335      */
    336     public BitSet getPredecessors() {
    337         return predecessors;
    338     }
    339 
    340     /**
    341      * @return {@code non-null;} successors set, indexed by block index
    342      */
    343     public BitSet getSuccessors() {
    344         return successors;
    345     }
    346 
    347     /**
    348      * @return {@code non-null;} ordered successor list, containing block
    349      * indicies
    350      */
    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      */
    359     public int getPrimarySuccessorIndex() {
    360         return primarySuccessor;
    361     }
    362 
    363     /**
    364      * @return rop label of primary successor
    365      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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          */
    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
    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