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 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      */
SsaBasicBlock(final int basicBlockIndex, final int ropLabel, final SsaMethod parent)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      */
newFromRop(RopMethod rmeth, int basicBlockIndex, final SsaMethod parent)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      */
addDomChild(SsaBasicBlock child)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      */
getDomChildren()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      */
addPhiInsnForReg(int reg)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      */
addPhiInsnForReg(RegisterSpec resultSpec)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      */
addInsnToHead(Insn insn)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      */
replaceLastInsn(Insn insn)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      */
forEachPhiInsn(PhiInsn.Visitor v)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      */
removeAllPhiInsns()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      */
getCountPhiInsns()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      */
getInsns()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      */
getPhiInsns()314     public List<SsaInsn> getPhiInsns() {
315         return insns.subList(0, getCountPhiInsns());
316     }
317 
318     /**
319      * @return the block index of this block
320      */
getIndex()321     public int getIndex() {
322         return index;
323     }
324 
325     /**
326      * @return the label of this block in rop form
327      */
getRopLabel()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      */
getRopLabelString()335     public String getRopLabelString() {
336         return Hex.u2(ropLabel);
337     }
338 
339     /**
340      * @return {@code non-null;} predecessors set, indexed by block index
341      */
getPredecessors()342     public BitSet getPredecessors() {
343         return predecessors;
344     }
345 
346     /**
347      * @return {@code non-null;} successors set, indexed by block index
348      */
getSuccessors()349     public BitSet getSuccessors() {
350         return successors;
351     }
352 
353     /**
354      * @return {@code non-null;} ordered successor list, containing block
355      * indicies
356      */
getSuccessorList()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      */
getPrimarySuccessorIndex()365     public int getPrimarySuccessorIndex() {
366         return primarySuccessor;
367     }
368 
369     /**
370      * @return rop label of primary successor
371      */
getPrimarySuccessorRopLabel()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      */
getPrimarySuccessor()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      */
getRopLabelSuccessorList()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      */
getParent()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      */
insertNewPredecessor()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      */
insertNewSuccessor(SsaBasicBlock other)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      */
replaceSuccessor(int oldIndex, int newIndex)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      */
removeSuccessor(int oldIndex)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      */
exitBlockFixup(SsaBasicBlock exitBlock)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      */
addMoveToEnd(RegisterSpec result, RegisterSpec source)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      */
addMoveToBeginning(RegisterSpec result, RegisterSpec source)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      */
setRegsUsed(BitSet regsUsed, RegisterSpec rs)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      */
checkRegUsed(BitSet regsUsed, RegisterSpec rs)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      */
scheduleUseBeforeAssigned(List<SsaInsn> toSchedule)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      */
addLiveOut(int regV)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      */
addLiveIn(int regV)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      */
getLiveInRegs()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      */
getLiveOutRegs()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      */
isExitBlock()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      */
isReachable()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      */
setReachable(int reach)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      */
scheduleMovesFromPhis()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      */
forEachInsn(SsaInsn.Visitor visitor)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
toString()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          */
visitBlock(SsaBasicBlock v, SsaBasicBlock parent)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} */
compare(SsaBasicBlock b1, SsaBasicBlock b2)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