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      */
SsaBasicBlock(final int basicBlockIndex, final int ropLabel, final SsaMethod parent)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      */
newFromRop(RopMethod rmeth, int basicBlockIndex, final SsaMethod parent)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      */
addDomChild(SsaBasicBlock child)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      */
getDomChildren()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      */
addPhiInsnForReg(int reg)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      */
addPhiInsnForReg(RegisterSpec resultSpec)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      */
addInsnToHead(Insn insn)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      */
replaceLastInsn(Insn insn)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      */
forEachPhiInsn(PhiInsn.Visitor v)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      */
removeAllPhiInsns()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      */
getCountPhiInsns()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      */
getInsns()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      */
getPhiInsns()308     public List<SsaInsn> getPhiInsns() {
309         return insns.subList(0, getCountPhiInsns());
310     }
311 
312     /**
313      * @return the block index of this block
314      */
getIndex()315     public int getIndex() {
316         return index;
317     }
318 
319     /**
320      * @return the label of this block in rop form
321      */
getRopLabel()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      */
getRopLabelString()329     public String getRopLabelString() {
330         return Hex.u2(ropLabel);
331     }
332 
333     /**
334      * @return {@code non-null;} predecessors set, indexed by block index
335      */
getPredecessors()336     public BitSet getPredecessors() {
337         return predecessors;
338     }
339 
340     /**
341      * @return {@code non-null;} successors set, indexed by block index
342      */
getSuccessors()343     public BitSet getSuccessors() {
344         return successors;
345     }
346 
347     /**
348      * @return {@code non-null;} ordered successor list, containing block
349      * indicies
350      */
getSuccessorList()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      */
getPrimarySuccessorIndex()359     public int getPrimarySuccessorIndex() {
360         return primarySuccessor;
361     }
362 
363     /**
364      * @return rop label of primary successor
365      */
getPrimarySuccessorRopLabel()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      */
getPrimarySuccessor()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      */
getRopLabelSuccessorList()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      */
getParent()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      */
insertNewPredecessor()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      */
insertNewSuccessor(SsaBasicBlock other)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      */
replaceSuccessor(int oldIndex, int newIndex)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      */
removeSuccessor(int oldIndex)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      */
exitBlockFixup(SsaBasicBlock exitBlock)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      */
addMoveToEnd(RegisterSpec result, RegisterSpec source)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      */
addMoveToBeginning(RegisterSpec result, RegisterSpec source)632     public void addMoveToBeginning (RegisterSpec result, RegisterSpec source) {
633         if (result.getReg() == source.getReg()) {
634             // Sometimes we end up with no-op moves. Ignore them here.
635             return;
636         }
637 
638         RegisterSpecList sources = RegisterSpecList.make(source);
639         NormalSsaInsn toAdd = new NormalSsaInsn(
640                 new PlainInsn(Rops.opMove(result.getType()),
641                         SourcePosition.NO_INFO, result, sources), this);
642 
643         insns.add(getCountPhiInsns(), toAdd);
644         movesFromPhisAtBeginning++;
645     }
646 
647     /**
648      * Sets the register as used in a bitset, taking into account its
649      * category/width.
650      *
651      * @param regsUsed set, indexed by register number
652      * @param rs register to mark as used
653      */
setRegsUsed(BitSet regsUsed, RegisterSpec rs)654     private static void setRegsUsed (BitSet regsUsed, RegisterSpec rs) {
655         regsUsed.set(rs.getReg());
656         if (rs.getCategory() > 1) {
657             regsUsed.set(rs.getReg() + 1);
658         }
659     }
660 
661     /**
662      * Checks to see if the register is used in a bitset, taking
663      * into account its category/width.
664      *
665      * @param regsUsed set, indexed by register number
666      * @param rs register to mark as used
667      * @return true if register is fully or partially (for the case of wide
668      * registers) used.
669      */
checkRegUsed(BitSet regsUsed, RegisterSpec rs)670     private static boolean checkRegUsed (BitSet regsUsed, RegisterSpec rs) {
671         int reg = rs.getReg();
672         int category = rs.getCategory();
673 
674         return regsUsed.get(reg)
675                 || (category == 2 ? regsUsed.get(reg + 1) : false);
676     }
677 
678     /**
679      * Ensures that all move operations in this block occur such that
680      * reads of any register happen before writes to that register.
681      * NOTE: caller is expected to returnSpareRegisters()!
682      *
683      * TODO: See Briggs, et al "Practical Improvements to the Construction and
684      * Destruction of Static Single Assignment Form" section 5. a) This can
685      * be done in three passes.
686      *
687      * @param toSchedule List of instructions. Must consist only of moves.
688      */
scheduleUseBeforeAssigned(List<SsaInsn> toSchedule)689     private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) {
690         BitSet regsUsedAsSources = new BitSet(parent.getRegCount());
691 
692         // TODO: Get rid of this.
693         BitSet regsUsedAsResults = new BitSet(parent.getRegCount());
694 
695         int sz = toSchedule.size();
696 
697         int insertPlace = 0;
698 
699         while (insertPlace < sz) {
700             int oldInsertPlace = insertPlace;
701 
702             // Record all registers used as sources in this block.
703             for (int i = insertPlace; i < sz; i++) {
704                 setRegsUsed(regsUsedAsSources,
705                         toSchedule.get(i).getSources().get(0));
706 
707                 setRegsUsed(regsUsedAsResults,
708                         toSchedule.get(i).getResult());
709             }
710 
711             /*
712              * If there are no circular dependencies, then there exists
713              * n instructions where n > 1 whose result is not used as a source.
714              */
715             for (int i = insertPlace; i <sz; i++) {
716                 SsaInsn insn = toSchedule.get(i);
717 
718                 /*
719                  * Move these n registers to the front, since they overwrite
720                  * nothing.
721                  */
722                 if (!checkRegUsed(regsUsedAsSources, insn.getResult())) {
723                     Collections.swap(toSchedule, i, insertPlace++);
724                 }
725             }
726 
727             /*
728              * If we've made no progress in this iteration, there's a
729              * circular dependency. Split it using the temp reg.
730              */
731             if (oldInsertPlace == insertPlace) {
732 
733                 SsaInsn insnToSplit = null;
734 
735                 // Find an insn whose result is used as a source.
736                 for (int i = insertPlace; i < sz; i++) {
737                     SsaInsn insn = toSchedule.get(i);
738                     if (checkRegUsed(regsUsedAsSources, insn.getResult())
739                             && checkRegUsed(regsUsedAsResults,
740                                 insn.getSources().get(0))) {
741 
742                         insnToSplit = insn;
743                         /*
744                          * We're going to split this insn; move it to the
745                          * front.
746                          */
747                         Collections.swap(toSchedule, insertPlace, i);
748                         break;
749                     }
750                 }
751 
752                 // At least one insn will be set above.
753 
754                 RegisterSpec result = insnToSplit.getResult();
755                 RegisterSpec tempSpec = result.withReg(
756                         parent.borrowSpareRegister(result.getCategory()));
757 
758                 NormalSsaInsn toAdd = new NormalSsaInsn(
759                         new PlainInsn(Rops.opMove(result.getType()),
760                                 SourcePosition.NO_INFO,
761                                 tempSpec,
762                                 insnToSplit.getSources()), this);
763 
764                 toSchedule.add(insertPlace++, toAdd);
765 
766                 RegisterSpecList newSources = RegisterSpecList.make(tempSpec);
767 
768                 NormalSsaInsn toReplace = new NormalSsaInsn(
769                         new PlainInsn(Rops.opMove(result.getType()),
770                                 SourcePosition.NO_INFO,
771                                 result,
772                                 newSources), this);
773 
774                 toSchedule.set(insertPlace, toReplace);
775 
776                 // The size changed.
777                 sz = toSchedule.size();
778             }
779 
780             regsUsedAsSources.clear();
781             regsUsedAsResults.clear();
782         }
783     }
784 
785     /**
786      * Adds {@code regV} to the live-out list for this block. This is called
787      * by the liveness analyzer.
788      *
789      * @param regV register that is live-out for this block.
790      */
addLiveOut(int regV)791     public void addLiveOut (int regV) {
792         if (liveOut == null) {
793             liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
794         }
795 
796         liveOut.add(regV);
797     }
798 
799     /**
800      * Adds {@code regV} to the live-in list for this block. This is
801      * called by the liveness analyzer.
802      *
803      * @param regV register that is live-in for this block.
804      */
addLiveIn(int regV)805     public void addLiveIn (int regV) {
806         if (liveIn == null) {
807             liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
808         }
809 
810         liveIn.add(regV);
811     }
812 
813     /**
814      * Returns the set of live-in registers. Valid after register
815      * interference graph has been generated, otherwise empty.
816      *
817      * @return {@code non-null;} live-in register set.
818      */
getLiveInRegs()819     public IntSet getLiveInRegs() {
820         if (liveIn == null) {
821             liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
822         }
823         return liveIn;
824     }
825 
826     /**
827      * Returns the set of live-out registers. Valid after register
828      * interference graph has been generated, otherwise empty.
829      *
830      * @return {@code non-null;} live-out register set
831      */
getLiveOutRegs()832     public IntSet getLiveOutRegs() {
833         if (liveOut == null) {
834             liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
835         }
836         return liveOut;
837     }
838 
839     /**
840      * @return true if this is the one-and-only exit block for this method
841      */
isExitBlock()842     public boolean isExitBlock() {
843         return index == parent.getExitBlockIndex();
844     }
845 
846     /**
847      * 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      */
scheduleMovesFromPhis()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      */
forEachInsn(SsaInsn.Visitor visitor)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
toString()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          */
visitBlock(SsaBasicBlock v, SsaBasicBlock parent)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
compare(SsaBasicBlock b1, SsaBasicBlock b2)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