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.Insn;
     20 import com.android.dx.rop.code.LocalItem;
     21 import com.android.dx.rop.code.RegisterSpec;
     22 import com.android.dx.rop.code.RegisterSpecList;
     23 import com.android.dx.rop.code.Rop;
     24 import com.android.dx.util.ToHuman;
     25 
     26 /**
     27  * An instruction in SSA form
     28  */
     29 public abstract class SsaInsn implements ToHuman, Cloneable {
     30     /** {@code non-null;} the block that contains this instance */
     31     private final SsaBasicBlock block;
     32 
     33     /** {@code null-ok;} result register */
     34     private RegisterSpec result;
     35 
     36     /**
     37      * Constructs an instance.
     38      *
     39      * @param result {@code null-ok;} initial result register. May be changed.
     40      * @param block {@code non-null;} block containing this insn. Can
     41      * never change.
     42      */
     43     protected SsaInsn(RegisterSpec result, SsaBasicBlock block) {
     44         if (block == null) {
     45             throw new NullPointerException("block == null");
     46         }
     47 
     48         this.block = block;
     49         this.result = result;
     50     }
     51 
     52     /**
     53      * Makes a new SSA insn form a rop insn.
     54      *
     55      * @param insn {@code non-null;} rop insn
     56      * @param block {@code non-null;} owning block
     57      * @return {@code non-null;} an appropriately constructed instance
     58      */
     59     public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
     60         return new NormalSsaInsn(insn, block);
     61     }
     62 
     63     /** {@inheritDoc} */
     64     @Override
     65     public SsaInsn clone() {
     66         try {
     67             return (SsaInsn)super.clone();
     68         } catch (CloneNotSupportedException ex) {
     69             throw new RuntimeException ("unexpected", ex);
     70         }
     71     }
     72 
     73     /**
     74      * Like {@link com.android.dx.rop.code.Insn getResult()}.
     75      *
     76      * @return result register
     77      */
     78     public RegisterSpec getResult() {
     79         return result;
     80     }
     81 
     82     /**
     83      * Set the result register.
     84      *
     85      * @param result {@code non-null;} the new result register
     86      */
     87     protected void setResult(RegisterSpec result) {
     88         if (result == null) {
     89             throw new NullPointerException("result == null");
     90         }
     91 
     92         this.result = result;
     93     }
     94 
     95     /**
     96      * Like {@link com.android.dx.rop.code.Insn getSources()}.
     97      *
     98      * @return {@code non-null;} sources list
     99      */
    100     abstract public RegisterSpecList getSources();
    101 
    102     /**
    103      * Gets the block to which this insn instance belongs.
    104      *
    105      * @return owning block
    106      */
    107     public SsaBasicBlock getBlock() {
    108         return block;
    109     }
    110 
    111     /**
    112      * Returns whether or not the specified reg is the result reg.
    113      *
    114      * @param reg register to test
    115      * @return true if there is a result and it is stored in the specified
    116      * register
    117      */
    118     public boolean isResultReg(int reg) {
    119         return result != null && result.getReg() == reg;
    120     }
    121 
    122 
    123     /**
    124      * Changes the result register if this insn has a result. This is used
    125      * during renaming.
    126      *
    127      * @param reg new result register
    128      */
    129     public void changeResultReg(int reg) {
    130         if (result != null) {
    131             result = result.withReg(reg);
    132         }
    133     }
    134 
    135     /**
    136      * Sets the local association for the result of this insn. This is
    137      * sometimes updated during the SsaRenamer process.
    138      *
    139      * @param local {@code null-ok;} new debug/local variable info
    140      */
    141     public final void setResultLocal(LocalItem local) {
    142         LocalItem oldItem = result.getLocalItem();
    143 
    144         if (local != oldItem && (local == null
    145                 || !local.equals(result.getLocalItem()))) {
    146             result = RegisterSpec.makeLocalOptional(
    147                     result.getReg(), result.getType(), local);
    148         }
    149     }
    150 
    151     /**
    152      * Map registers after register allocation.
    153      *
    154      * @param mapper {@code non-null;} mapping from old to new registers
    155      */
    156     public final void mapRegisters(RegisterMapper mapper) {
    157         RegisterSpec oldResult = result;
    158 
    159         result = mapper.map(result);
    160         block.getParent().updateOneDefinition(this, oldResult);
    161         mapSourceRegisters(mapper);
    162     }
    163 
    164     /**
    165      * Maps only source registers.
    166      *
    167      * @param mapper new mapping
    168      */
    169     abstract public void mapSourceRegisters(RegisterMapper mapper);
    170 
    171     /**
    172      * Returns the Rop opcode for this insn, or null if this is a phi insn.
    173      *
    174      * TODO: Move this up into NormalSsaInsn.
    175      *
    176      * @return {@code null-ok;} Rop opcode if there is one.
    177      */
    178     abstract public Rop getOpcode();
    179 
    180     /**
    181      * Returns the original Rop insn for this insn, or null if this is
    182      * a phi insn.
    183      *
    184      * TODO: Move this up into NormalSsaInsn.
    185      *
    186      * @return {@code null-ok;} Rop insn if there is one.
    187      */
    188     abstract public Insn getOriginalRopInsn();
    189 
    190     /**
    191      * Gets the spec of a local variable assignment that occurs at this
    192      * instruction, or null if no local variable assignment occurs. This
    193      * may be the result register, or for {@code mark-local} insns
    194      * it may be the source.
    195      *
    196      * @see com.android.dx.rop.code.Insn#getLocalAssignment()
    197      *
    198      * @return {@code null-ok;} a local-associated register spec or null
    199      */
    200     public RegisterSpec getLocalAssignment() {
    201         if (result != null && result.getLocalItem() != null) {
    202             return result;
    203         }
    204 
    205         return null;
    206     }
    207 
    208     /**
    209      * Indicates whether the specified register is amongst the registers
    210      * used as sources for this instruction.
    211      *
    212      * @param reg the register in question
    213      * @return true if the reg is a source
    214      */
    215     public boolean isRegASource(int reg) {
    216         return null != getSources().specForRegister(reg);
    217     }
    218 
    219     /**
    220      * Transform back to ROP form.
    221      *
    222      * TODO: Move this up into NormalSsaInsn.
    223      *
    224      * @return {@code non-null;} a ROP representation of this instruction, with
    225      * updated registers.
    226      */
    227     public abstract Insn toRopInsn();
    228 
    229     /**
    230      * @return true if this is a PhiInsn or a normal move insn
    231      */
    232     public abstract boolean isPhiOrMove();
    233 
    234     /**
    235      * Returns true if this insn is considered to have a side effect beyond
    236      * that of assigning to the result reg.
    237      *
    238      * @return true if this insn is considered to have a side effect beyond
    239      * that of assigning to the result reg.
    240      */
    241     public abstract boolean hasSideEffect();
    242 
    243     /**
    244      * @return true if this is a move (but not a move-operand or
    245      * move-exception) instruction
    246      */
    247     public boolean isNormalMoveInsn() {
    248         return false;
    249     }
    250 
    251     /**
    252      * @return true if this is a move-exception instruction.
    253      * These instructions must immediately follow a preceeding invoke*
    254      */
    255     public boolean isMoveException() {
    256         return false;
    257     }
    258 
    259     /**
    260      * @return true if this instruction can throw.
    261      */
    262     abstract public boolean canThrow();
    263 
    264     /**
    265      * Accepts a visitor.
    266      *
    267      * @param v {@code non-null} the visitor
    268      */
    269     public abstract void accept(Visitor v);
    270 
    271     /**
    272      * Visitor interface for this class.
    273      */
    274     public static interface Visitor {
    275         /**
    276          * Any non-phi move instruction
    277          * @param insn {@code non-null;} the instruction to visit
    278          */
    279         public void visitMoveInsn(NormalSsaInsn insn);
    280 
    281         /**
    282          * Any phi insn
    283          * @param insn {@code non-null;} the instruction to visit
    284          */
    285         public void visitPhiInsn(PhiInsn insn);
    286 
    287         /**
    288          * Any insn that isn't a move or a phi (which is also a move).
    289          * @param insn {@code non-null;} the instruction to visit
    290          */
    291         public void visitNonMoveInsn(NormalSsaInsn insn);
    292     }
    293 }
    294