SsaBasicBlock.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
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
17package com.android.dx.ssa;
18
19import com.android.dx.rop.code.BasicBlock;
20import com.android.dx.rop.code.BasicBlockList;
21import com.android.dx.rop.code.Insn;
22import com.android.dx.rop.code.InsnList;
23import com.android.dx.rop.code.PlainInsn;
24import com.android.dx.rop.code.RegisterSpec;
25import com.android.dx.rop.code.RegisterSpecList;
26import com.android.dx.rop.code.Rop;
27import com.android.dx.rop.code.RopMethod;
28import com.android.dx.rop.code.Rops;
29import com.android.dx.rop.code.SourcePosition;
30import com.android.dx.util.Hex;
31import com.android.dx.util.IntList;
32import com.android.dx.util.IntSet;
33
34import java.util.ArrayList;
35import java.util.BitSet;
36import java.util.Collections;
37import java.util.Comparator;
38import java.util.List;
39
40/**
41 * An SSA representation of a basic block.
42 */
43public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
315    public List<SsaInsn> getPhiInsns() {
316        return insns.subList(0, getCountPhiInsns());
317    }
318
319    /**
320     * @return the block index of this block
321     */
322    public int getIndex() {
323        return index;
324    }
325
326    /**
327     * @return the label of this block in rop form
328     */
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     */
336    public String getRopLabelString() {
337        return Hex.u2(ropLabel);
338    }
339
340    /**
341     * @return {@code non-null;} predecessors set, indexed by block index
342     */
343    public BitSet getPredecessors() {
344        return predecessors;
345    }
346
347    /**
348     * @return {@code non-null;} successors set, indexed by block index
349     */
350    public BitSet getSuccessors() {
351        return successors;
352    }
353
354    /**
355     * @return {@code non-null;} ordered successor list, containing block
356     * indicies
357     */
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     */
366    public int getPrimarySuccessorIndex() {
367        return primarySuccessor;
368    }
369
370    /**
371     * @return rop label of primary successor
372     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     * 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     */
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     */
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     */
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     */
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
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         */
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} */
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