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