Home | History | Annotate | Download | only in ssa
      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.RegisterSpec;
     20 import com.android.dx.rop.code.RopMethod;
     21 import com.android.dx.util.IntIterator;
     22 
     23 import java.util.ArrayList;
     24 import java.util.BitSet;
     25 
     26 /**
     27  * Converts ROP methods to SSA Methods
     28  */
     29 public class SsaConverter {
     30     public static final boolean DEBUG = false;
     31 
     32     /**
     33      * Returns an SSA representation, edge-split and with phi
     34      * functions placed.
     35      *
     36      * @param rmeth input
     37      * @param paramWidth the total width, in register-units, of the method's
     38      * parameters
     39      * @param isStatic {@code true} if this method has no {@code this}
     40      * pointer argument
     41      * @return output in SSA form
     42      */
     43     public static SsaMethod convertToSsaMethod(RopMethod rmeth,
     44             int paramWidth, boolean isStatic) {
     45         SsaMethod result
     46             = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
     47 
     48         edgeSplit(result);
     49 
     50         LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
     51 
     52         placePhiFunctions(result, localInfo, 0);
     53         new SsaRenamer(result).run();
     54 
     55         /*
     56          * The exit block, added here, is not considered for edge splitting
     57          * or phi placement since no actual control flows to it.
     58          */
     59         result.makeExitBlock();
     60 
     61         return result;
     62     }
     63 
     64     /**
     65      * Updates an SSA representation, placing phi functions and renaming all
     66      * registers above a certain threshold number.
     67      *
     68      * @param ssaMeth input
     69      * @param threshold registers below this number are unchanged
     70      */
     71     public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
     72         LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
     73         placePhiFunctions(ssaMeth, localInfo, threshold);
     74         new SsaRenamer(ssaMeth, threshold).run();
     75     }
     76 
     77     /**
     78      * Returns an SSA represention with only the edge-splitter run.
     79      *
     80      * @param rmeth method to process
     81      * @param paramWidth width of all arguments in the method
     82      * @param isStatic {@code true} if this method has no {@code this}
     83      * pointer argument
     84      * @return an SSA represention with only the edge-splitter run
     85      */
     86     public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth,
     87             boolean isStatic) {
     88         SsaMethod result;
     89 
     90         result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
     91 
     92         edgeSplit(result);
     93         return result;
     94     }
     95 
     96     /**
     97      * Returns an SSA represention with only the steps through the
     98      * phi placement run.
     99      *
    100      * @param rmeth method to process
    101      * @param paramWidth width of all arguments in the method
    102      * @param isStatic {@code true} if this method has no {@code this}
    103      * pointer argument
    104      * @return an SSA represention with only the edge-splitter run
    105      */
    106     public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth,
    107             boolean isStatic) {
    108         SsaMethod result;
    109 
    110         result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
    111 
    112         edgeSplit(result);
    113 
    114         LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
    115 
    116         placePhiFunctions(result, localInfo, 0);
    117         return result;
    118     }
    119 
    120     /**
    121      * See Appel section 19.1:
    122      *
    123      * Converts CFG into "edge-split" form, such that each node either a
    124      * unique successor or unique predecessor.<p>
    125      *
    126      * In addition, the SSA form we use enforces a further constraint,
    127      * requiring each block with a final instruction that returns a
    128      * value to have a primary successor that has no other
    129      * predecessor. This ensures move statements can always be
    130      * inserted correctly when phi statements are removed.
    131      *
    132      * @param result method to process
    133      */
    134     private static void edgeSplit(SsaMethod result) {
    135         edgeSplitPredecessors(result);
    136         edgeSplitMoveExceptionsAndResults(result);
    137         edgeSplitSuccessors(result);
    138     }
    139 
    140     /**
    141      * Inserts Z nodes as new predecessors for every node that has multiple
    142      * successors and multiple predecessors.
    143      *
    144      * @param result {@code non-null;} method to process
    145      */
    146     private static void edgeSplitPredecessors(SsaMethod result) {
    147         ArrayList<SsaBasicBlock> blocks = result.getBlocks();
    148 
    149         /*
    150          * New blocks are added to the end of the block list during
    151          * this iteration.
    152          */
    153         for (int i = blocks.size() - 1; i >= 0; i-- ) {
    154             SsaBasicBlock block = blocks.get(i);
    155             if (nodeNeedsUniquePredecessor(block)) {
    156                 block.insertNewPredecessor();
    157             }
    158         }
    159     }
    160 
    161     /**
    162      * @param block {@code non-null;} block in question
    163      * @return {@code true} if this node needs to have a unique
    164      * predecessor created for it
    165      */
    166     private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) {
    167         /*
    168          * Any block with that has both multiple successors and multiple
    169          * predecessors needs a new predecessor node.
    170          */
    171 
    172         int countPredecessors = block.getPredecessors().cardinality();
    173         int countSuccessors = block.getSuccessors().cardinality();
    174 
    175         return  (countPredecessors > 1 && countSuccessors > 1);
    176     }
    177 
    178     /**
    179      * In ROP form, move-exception must occur as the first insn in a block
    180      * immediately succeeding the insn that could thrown an exception.
    181      * We may need room to insert move insns later, so make sure to split
    182      * any block that starts with a move-exception such that there is a
    183      * unique move-exception block for each predecessor.
    184      *
    185      * @param ssaMeth method to process
    186      */
    187     private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) {
    188         ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
    189 
    190         /*
    191          * New blocks are added to the end of the block list during
    192          * this iteration.
    193          */
    194         for (int i = blocks.size() - 1; i >= 0; i-- ) {
    195             SsaBasicBlock block = blocks.get(i);
    196 
    197             /*
    198              * Any block that starts with a move-exception and has more than
    199              * one predecessor...
    200              */
    201             if (!block.isExitBlock()
    202                     && block.getPredecessors().cardinality() > 1
    203                     && block.getInsns().get(0).isMoveException()) {
    204 
    205                 // block.getPredecessors() is changed in the loop below.
    206                 BitSet preds = (BitSet)block.getPredecessors().clone();
    207                 for (int j = preds.nextSetBit(0); j >= 0;
    208                      j = preds.nextSetBit(j + 1)) {
    209                     SsaBasicBlock predecessor = blocks.get(j);
    210                     SsaBasicBlock zNode
    211                         = predecessor.insertNewSuccessor(block);
    212 
    213                     /*
    214                      * Make sure to place the move-exception as the
    215                      * first insn.
    216                      */
    217                     zNode.getInsns().add(0, block.getInsns().get(0).clone());
    218                 }
    219 
    220                 // Remove the move-exception from the original block.
    221                 block.getInsns().remove(0);
    222             }
    223         }
    224     }
    225 
    226     /**
    227      * Inserts Z nodes for every node that needs a new
    228      * successor.
    229      *
    230      * @param result {@code non-null;} method to process
    231      */
    232     private static void edgeSplitSuccessors(SsaMethod result) {
    233         ArrayList<SsaBasicBlock> blocks = result.getBlocks();
    234 
    235         /*
    236          * New blocks are added to the end of the block list during
    237          * this iteration.
    238          */
    239         for (int i = blocks.size() - 1; i >= 0; i-- ) {
    240             SsaBasicBlock block = blocks.get(i);
    241 
    242             // Successors list is modified in loop below.
    243             BitSet successors = (BitSet)block.getSuccessors().clone();
    244             for (int j = successors.nextSetBit(0);
    245                  j >= 0; j = successors.nextSetBit(j+1)) {
    246 
    247                 SsaBasicBlock succ = blocks.get(j);
    248 
    249                 if (needsNewSuccessor(block, succ)) {
    250                     block.insertNewSuccessor(succ);
    251                 }
    252             }
    253         }
    254     }
    255 
    256     /**
    257      * Returns {@code true} if block and successor need a Z-node
    258      * between them. Presently, this is {@code true} if the final
    259      * instruction has any sources or results and the current
    260      * successor block has more than one predecessor.
    261      *
    262      * @param block predecessor node
    263      * @param succ successor node
    264      * @return {@code true} if a Z node is needed
    265      */
    266     private static boolean needsNewSuccessor(SsaBasicBlock block,
    267             SsaBasicBlock succ) {
    268         ArrayList<SsaInsn> insns = block.getInsns();
    269         SsaInsn lastInsn = insns.get(insns.size() - 1);
    270 
    271         return ((lastInsn.getResult() != null)
    272                     || (lastInsn.getSources().size() > 0))
    273                 && succ.getPredecessors().cardinality() > 1;
    274     }
    275 
    276     /**
    277      * See Appel algorithm 19.6:
    278      *
    279      * Place Phi functions in appropriate locations.
    280      *
    281      * @param ssaMeth {@code non-null;} method to process.
    282      * Modifications are made in-place.
    283      * @param localInfo {@code non-null;} local variable info, used
    284      * when placing phis
    285      * @param threshold registers below this number are ignored
    286      */
    287     private static void placePhiFunctions (SsaMethod ssaMeth,
    288             LocalVariableInfo localInfo, int threshold) {
    289         ArrayList<SsaBasicBlock> ssaBlocks;
    290         int regCount;
    291         int blockCount;
    292 
    293         ssaBlocks = ssaMeth.getBlocks();
    294         blockCount = ssaBlocks.size();
    295         regCount = ssaMeth.getRegCount() - threshold;
    296 
    297         DomFront df = new DomFront(ssaMeth);
    298         DomFront.DomInfo[] domInfos = df.run();
    299 
    300         // Bit set of registers vs block index "definition sites"
    301         BitSet[] defsites = new BitSet[regCount];
    302 
    303         // Bit set of registers vs block index "phi placement sites"
    304         BitSet[] phisites = new BitSet[regCount];
    305 
    306         for (int i = 0; i < regCount; i++) {
    307             defsites[i] = new BitSet(blockCount);
    308             phisites[i] = new BitSet(blockCount);
    309         }
    310 
    311         /*
    312          * For each register, build a set of all basic blocks where
    313          * containing an assignment to that register.
    314          */
    315         for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
    316             SsaBasicBlock b = ssaBlocks.get(bi);
    317 
    318             for (SsaInsn insn : b.getInsns()) {
    319                 RegisterSpec rs = insn.getResult();
    320 
    321                 if (rs != null && rs.getReg() - threshold >= 0) {
    322                     defsites[rs.getReg() - threshold].set(bi);
    323                 }
    324             }
    325         }
    326 
    327         if (DEBUG) {
    328             System.out.println("defsites");
    329 
    330             for (int i = 0; i < regCount; i++) {
    331                 StringBuilder sb = new StringBuilder();
    332                 sb.append('v').append(i).append(": ");
    333                 sb.append(defsites[i].toString());
    334                 System.out.println(sb);
    335             }
    336         }
    337 
    338         BitSet worklist;
    339 
    340         /*
    341          * For each register, compute all locations for phi placement
    342          * based on dominance-frontier algorithm.
    343          */
    344         for (int reg = 0, s = regCount; reg < s; reg++) {
    345             int workBlockIndex;
    346 
    347             /* Worklist set starts out with each node where reg is assigned. */
    348 
    349             worklist = (BitSet) (defsites[reg].clone());
    350 
    351             while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
    352                 worklist.clear(workBlockIndex);
    353                 IntIterator dfIterator
    354                     = domInfos[workBlockIndex].dominanceFrontiers.iterator();
    355 
    356                 while (dfIterator.hasNext()) {
    357                     int dfBlockIndex = dfIterator.next();
    358 
    359                     if (!phisites[reg].get(dfBlockIndex)) {
    360                         phisites[reg].set(dfBlockIndex);
    361 
    362                         int tReg = reg + threshold;
    363                         RegisterSpec rs
    364                             = localInfo.getStarts(dfBlockIndex).get(tReg);
    365 
    366                         if (rs == null) {
    367                             ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
    368                         } else {
    369                             ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
    370                         }
    371 
    372                         if (!defsites[reg].get(dfBlockIndex)) {
    373                             worklist.set(dfBlockIndex);
    374                         }
    375                     }
    376                 }
    377             }
    378         }
    379 
    380         if (DEBUG) {
    381             System.out.println("phisites");
    382 
    383             for (int i = 0; i < regCount; i++) {
    384                 StringBuilder sb = new StringBuilder();
    385                 sb.append('v').append(i).append(": ");
    386                 sb.append(phisites[i].toString());
    387                 System.out.println(sb);
    388             }
    389         }
    390     }
    391 }
    392