Home | History | Annotate | Download | only in ssa
      1 /*
      2  * Copyright (C) 2008 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.CstInsn;
     20 import com.android.dx.rop.code.LocalItem;
     21 import com.android.dx.rop.code.RegOps;
     22 import com.android.dx.rop.code.RegisterSpec;
     23 import com.android.dx.rop.cst.CstInteger;
     24 import java.util.HashSet;
     25 import java.util.List;
     26 
     27 /**
     28  * Combine identical move-param insns, which may result from Ropper's
     29  * handling of synchronized methods.
     30  */
     31 public class MoveParamCombiner {
     32 
     33     /** method to process */
     34     private final SsaMethod ssaMeth;
     35 
     36     /**
     37      * Processes a method with this optimization step.
     38      *
     39      * @param ssaMethod method to process
     40      */
     41     public static void process(SsaMethod ssaMethod) {
     42         new MoveParamCombiner(ssaMethod).run();
     43     }
     44 
     45     private MoveParamCombiner(SsaMethod ssaMeth) {
     46         this.ssaMeth = ssaMeth;
     47     }
     48 
     49     /**
     50      * Runs this optimization step.
     51      */
     52     private void run() {
     53         // This will contain the definition specs for each parameter
     54         final RegisterSpec[] paramSpecs
     55                 = new RegisterSpec[ssaMeth.getParamWidth()];
     56 
     57         // Insns to delete when all done
     58         final HashSet<SsaInsn> deletedInsns = new HashSet();
     59 
     60         ssaMeth.forEachInsn(new SsaInsn.Visitor() {
     61             @Override
     62             public void visitMoveInsn (NormalSsaInsn insn) {
     63             }
     64             @Override
     65             public void visitPhiInsn (PhiInsn phi) {
     66             }
     67             @Override
     68             public void visitNonMoveInsn (NormalSsaInsn insn) {
     69                 if (insn.getOpcode().getOpcode() != RegOps.MOVE_PARAM) {
     70                     return;
     71                 }
     72 
     73                 int param = getParamIndex(insn);
     74 
     75                 if (paramSpecs[param] == null) {
     76                     paramSpecs[param] = insn.getResult();
     77                 } else {
     78                     final RegisterSpec specA = paramSpecs[param];
     79                     final RegisterSpec specB = insn.getResult();
     80                     LocalItem localA = specA.getLocalItem();
     81                     LocalItem localB = specB.getLocalItem();
     82                     LocalItem newLocal;
     83 
     84                     /*
     85                      * Is there local information to preserve?
     86                      */
     87 
     88                     if (localA == null) {
     89                         newLocal = localB;
     90                     } else if (localB == null) {
     91                         newLocal = localA;
     92                     } else if (localA.equals(localB)) {
     93                         newLocal = localA;
     94                     } else {
     95                         /*
     96                          * Oddly, these two identical move-params have distinct
     97                          * debug info. We'll just keep them distinct.
     98                          */
     99                         return;
    100                     }
    101 
    102                     ssaMeth.getDefinitionForRegister(specA.getReg())
    103                             .setResultLocal(newLocal);
    104 
    105                     /*
    106                      * Map all uses of specB to specA
    107                      */
    108 
    109                     RegisterMapper mapper = new RegisterMapper() {
    110                         /** {@inheritDoc} */
    111                         @Override
    112                         public int getNewRegisterCount() {
    113                             return ssaMeth.getRegCount();
    114                         }
    115 
    116                         /** {@inheritDoc} */
    117                         @Override
    118                         public RegisterSpec map(RegisterSpec registerSpec) {
    119                             if (registerSpec.getReg() == specB.getReg()) {
    120                                 return specA;
    121                             }
    122 
    123                             return registerSpec;
    124                         }
    125                     };
    126 
    127                     List<SsaInsn> uses
    128                             = ssaMeth.getUseListForRegister(specB.getReg());
    129 
    130                     // Use list is modified by mapSourceRegisters
    131                     for (int i = uses.size() - 1; i >= 0; i--) {
    132                         SsaInsn use = uses.get(i);
    133                         use.mapSourceRegisters(mapper);
    134                     }
    135 
    136                     deletedInsns.add(insn);
    137                 }
    138 
    139             }
    140         });
    141 
    142         ssaMeth.deleteInsns(deletedInsns);
    143     }
    144 
    145     /**
    146      * Returns the parameter index associated with a move-param insn. Does
    147      * not verify that the insn is a move-param insn.
    148      *
    149      * @param insn {@code non-null;} a move-param insn
    150      * @return {@code >=0;} parameter index
    151      */
    152     private int getParamIndex(NormalSsaInsn insn) {
    153         CstInsn cstInsn = (CstInsn)(insn.getOriginalRopInsn());
    154 
    155         int param = ((CstInteger)cstInsn.getConstant()).getValue();
    156         return param;
    157     }
    158 
    159 }
    160