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