Home | History | Annotate | Download | only in code
      1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
      2 // for details. All rights reserved. Use of this source code is governed by a
      3 // BSD-style license that can be found in the LICENSE file.
      4 package com.android.tools.r8.ir.code;
      5 
      6 import com.android.tools.r8.errors.Unreachable;
      7 import com.android.tools.r8.graph.AppInfo;
      8 import com.android.tools.r8.graph.DebugLocalInfo;
      9 import com.android.tools.r8.graph.DexType;
     10 import com.android.tools.r8.ir.code.Value.DebugInfo;
     11 import com.android.tools.r8.ir.conversion.DexBuilder;
     12 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
     13 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
     14 import com.android.tools.r8.utils.CfgPrinter;
     15 import com.android.tools.r8.utils.InternalOptions;
     16 import com.android.tools.r8.utils.StringUtils;
     17 import com.android.tools.r8.utils.StringUtils.BraceType;
     18 import com.google.common.collect.ImmutableList;
     19 import java.util.ArrayList;
     20 import java.util.List;
     21 
     22 public abstract class Instruction {
     23 
     24   protected Value outValue = null;
     25   protected final List<Value> inValues = new ArrayList<>();
     26   private BasicBlock block = null;
     27   private int number = -1;
     28   private List<Value> debugValues = null;
     29 
     30   protected Instruction(Value outValue) {
     31     setOutValue(outValue);
     32   }
     33 
     34   protected Instruction(Value outValue, Value inValue) {
     35     addInValue(inValue);
     36     setOutValue(outValue);
     37   }
     38 
     39   protected Instruction(Value outValue, List<? extends Value> inValues) {
     40     if (inValues != null) {
     41       for (Value v : inValues) {
     42         addInValue(v);
     43       }
     44     }
     45     setOutValue(outValue);
     46   }
     47 
     48   public List<Value> inValues() {
     49     return inValues;
     50   }
     51 
     52   protected void addInValue(Value value) {
     53     if (value != null) {
     54       inValues.add(value);
     55       value.addUser(this);
     56     }
     57   }
     58 
     59   public Value outValue() {
     60     return outValue;
     61   }
     62 
     63   public void setOutValue(Value value) {
     64     assert outValue == null || !outValue.hasUsersInfo() || outValue.numberOfAllUsers() == 0;
     65     outValue = value;
     66     if (outValue != null) {
     67       outValue.definition = this;
     68       Value previousLocalValue = getPreviousLocalValue();
     69       if (previousLocalValue != null) {
     70         previousLocalValue.addDebugUser(this);
     71       }
     72     }
     73   }
     74 
     75   public void addDebugValue(Value value) {
     76     assert value.getLocalInfo() != null;
     77     if (debugValues == null) {
     78       debugValues = new ArrayList<>();
     79     }
     80     debugValues.add(value);
     81     value.addDebugUser(this);
     82   }
     83 
     84   public static void clearUserInfo(Instruction instruction) {
     85     if (instruction.outValue != null) {
     86       instruction.outValue.clearUsersInfo();
     87     }
     88     instruction.inValues.forEach(Value::clearUsersInfo);
     89     if (instruction.debugValues != null) {
     90       instruction.debugValues.forEach(Value::clearUsersInfo);
     91     }
     92   }
     93 
     94   public final MoveType outType() {
     95     return outValue.outType();
     96   }
     97 
     98   public abstract void buildDex(DexBuilder builder);
     99 
    100   public void replaceValue(Value oldValue, Value newValue) {
    101     for (int i = 0; i < inValues.size(); i++) {
    102       if (oldValue == inValues.get(i)) {
    103         inValues.set(i, newValue);
    104         newValue.addUser(this);
    105         oldValue.removeUser(this);
    106       }
    107     }
    108   }
    109 
    110   public void replaceDebugPhi(Phi phi, Value value) {
    111     if (debugValues != null) {
    112       for (int i = 0; i < debugValues.size(); i++) {
    113         if (phi == debugValues.get(i)) {
    114           if (value.getLocalInfo() == null) {
    115             debugValues.remove(i);
    116           } else {
    117             debugValues.set(i, value);
    118             value.addDebugUser(this);
    119           }
    120         }
    121       }
    122     }
    123     if (phi == getPreviousLocalValue()) {
    124       if (value.getDebugInfo() == null) {
    125         replacePreviousLocalValue(null);
    126       } else {
    127         replacePreviousLocalValue(value);
    128         value.addDebugUser(this);
    129       }
    130     }
    131   }
    132 
    133   /**
    134    * Returns the basic block containing this instruction.
    135    */
    136   public BasicBlock getBlock() {
    137     assert block != null;
    138     return block;
    139   }
    140 
    141   /**
    142    * Set the basic block of this instruction. See IRBuilder.
    143    */
    144   public void setBlock(BasicBlock block) {
    145     assert block != null;
    146     this.block = block;
    147   }
    148 
    149   /**
    150    * Clear the basic block of this instruction. Use when removing an instruction from a block.
    151    */
    152   public void clearBlock() {
    153     assert block != null;
    154     block = null;
    155   }
    156 
    157   public String getInstructionName() {
    158     return getClass().getSimpleName();
    159   }
    160 
    161   @Override
    162   public String toString() {
    163     StringBuilder builder = new StringBuilder();
    164     builder.append(getInstructionName());
    165     for (int i = builder.length(); i < 20; i++) {
    166       builder.append(" ");
    167     }
    168     builder.append(" ");
    169     if (outValue != null) {
    170       builder.append(outValue);
    171       builder.append(" <- ");
    172     }
    173     if (!inValues.isEmpty()) {
    174       StringUtils.append(builder, inValues, ", ", BraceType.NONE);
    175     }
    176     return builder.toString();
    177   }
    178 
    179   public void print(CfgPrinter printer) {
    180     int uses = 0;
    181     String value;
    182     if (outValue == null) {
    183       value = printer.makeUnusedValue();
    184     } else {
    185       if (outValue.hasUsersInfo()) {
    186         uses = outValue.uniqueUsers().size() + outValue.uniquePhiUsers().size();
    187       }
    188       value = "v" + outValue.getNumber();
    189     }
    190     printer
    191         .print(0)           // bci
    192         .sp().append(uses)  // use
    193         .sp().append(value) // tid
    194         .sp().append(getClass().getSimpleName());
    195     for (Value in : inValues) {
    196       printer.append(" v").append(in.getNumber());
    197     }
    198   }
    199 
    200   public void printLIR(CfgPrinter printer) {
    201     // TODO(ager): Improve the instruction printing. Use different name for values so that the
    202     // HIR and LIR values are not confused in the c1 visualizer.
    203     printer.print(number).sp().append(toString());
    204   }
    205 
    206   public int getNumber() {
    207     return number;
    208   }
    209 
    210   public void setNumber(int number) {
    211     assert number != -1;
    212     this.number = number;
    213   }
    214 
    215   /**
    216    * Compare equality of two class-equivalent instructions modulo their values.
    217    *
    218    * <p>It is a precondition to this method that this.getClass() == other.getClass().
    219    */
    220   public abstract boolean identicalNonValueParts(Instruction other);
    221 
    222   public abstract int compareNonValueParts(Instruction other);
    223 
    224   private boolean identicalAfterRegisterAllocation(
    225       Value a, int aInstr, Value b, int bInstr, RegisterAllocator allocator) {
    226     if (a.needsRegister() != b.needsRegister()) {
    227       return false;
    228     }
    229     if (a.needsRegister()) {
    230       if (allocator.getRegisterForValue(a, aInstr) != allocator.getRegisterForValue(b, bInstr)) {
    231         return false;
    232       }
    233     } else {
    234       ConstNumber aNum = a.getConstInstruction().asConstNumber();
    235       ConstNumber bNum = b.getConstInstruction().asConstNumber();
    236       if (!aNum.identicalNonValueParts(bNum)) {
    237         return false;
    238       }
    239     }
    240     if (a.outType() != b.outType()) {
    241       return false;
    242     }
    243     return true;
    244   }
    245 
    246   public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
    247     if (other.getClass() != getClass()) {
    248       return false;
    249     }
    250     if (!identicalNonValueParts(other)) {
    251       return false;
    252     }
    253     if (isInvokeDirect() && !asInvokeDirect().sameConstructorReceiverValue(other.asInvoke())) {
    254       return false;
    255     }
    256     if (outValue != null) {
    257       if (other.outValue == null) {
    258         return false;
    259       }
    260       if (!identicalAfterRegisterAllocation(
    261           outValue, getNumber(), other.outValue, other.getNumber(), allocator)) {
    262         return false;
    263       }
    264     } else if (other.outValue != null) {
    265       return false;
    266     }
    267     // Check that all input values have the same type and allocated registers.
    268     if (inValues.size() != other.inValues.size()) {
    269       return false;
    270     }
    271     for (int j = 0; j < inValues.size(); j++) {
    272       Value in0 = inValues.get(j);
    273       Value in1 = other.inValues.get(j);
    274       if (!identicalAfterRegisterAllocation(in0, getNumber(), in1, other.getNumber(), allocator)) {
    275         return false;
    276       }
    277     }
    278     return true;
    279   }
    280 
    281   /**
    282    * Returns true if this instruction may throw an exception.
    283    */
    284   public boolean instructionTypeCanThrow() {
    285     return false;
    286   }
    287 
    288   public boolean instructionInstanceCanThrow() {
    289     return instructionTypeCanThrow();
    290   }
    291 
    292   /** Returns true is this instruction can be treated as dead code if its outputs are not used. */
    293   public boolean canBeDeadCode(IRCode code, InternalOptions options) {
    294     return !instructionInstanceCanThrow();
    295   }
    296 
    297   /**
    298    * Returns true if this instruction need this value in a register.
    299    */
    300   public boolean needsValueInRegister(Value value) {
    301     return true;
    302   }
    303 
    304   /**
    305    * Returns true if the out value of this instruction is a constant.
    306    *
    307    * @return whether the out value of this instruction is a constant.
    308    */
    309   public boolean isOutConstant() {
    310     return false;
    311   }
    312 
    313   /**
    314    * Returns the ConstInstruction defining the constant out value if the out value is constant.
    315    *
    316    * @return ConstInstruction or null.
    317    */
    318   public ConstInstruction getOutConstantConstInstruction() {
    319     return null;
    320   }
    321 
    322   public abstract int maxInValueRegister();
    323 
    324   public abstract int maxOutValueRegister();
    325 
    326   public DebugInfo getDebugInfo() {
    327     return outValue == null ? null : outValue.getDebugInfo();
    328   }
    329 
    330   public DebugLocalInfo getLocalInfo() {
    331     return outValue == null ? null : outValue.getLocalInfo();
    332   }
    333 
    334   public Value getPreviousLocalValue() {
    335     return outValue == null ? null : outValue.getPreviousLocalValue();
    336   }
    337 
    338   public List<Value> getDebugValues() {
    339     return debugValues != null ? debugValues : ImmutableList.of();
    340   }
    341 
    342   public void replacePreviousLocalValue(Value value) {
    343     outValue.replacePreviousLocalValue(value);
    344   }
    345 
    346   public boolean isArrayGet() {
    347     return false;
    348   }
    349 
    350   public ArrayGet asArrayGet() {
    351     return null;
    352   }
    353 
    354   public boolean isArrayLength() {
    355     return false;
    356   }
    357 
    358   public ArrayLength asArrayLength() {
    359     return null;
    360   }
    361 
    362   public boolean isArrayPut() {
    363     return false;
    364   }
    365 
    366   public ArrayPut asArrayPut() {
    367     return null;
    368   }
    369 
    370   public boolean isArgument() {
    371     return false;
    372   }
    373 
    374   public Argument asArgument() {
    375     return null;
    376   }
    377 
    378   public boolean isArithmeticBinop() {
    379     return false;
    380   }
    381 
    382   public ArithmeticBinop asArithmeticBinop() {
    383     return null;
    384   }
    385 
    386   public boolean isBinop() {
    387     return false;
    388   }
    389 
    390   public Binop asBinop() {
    391     return null;
    392   }
    393 
    394   public boolean isUnop() {
    395     return false;
    396   }
    397 
    398   public Unop asUnop() {
    399     return null;
    400   }
    401 
    402   public boolean isCheckCast() {
    403     return false;
    404   }
    405 
    406   public CheckCast asCheckCast() {
    407     return null;
    408   }
    409 
    410   public boolean isConstNumber() {
    411     return false;
    412   }
    413 
    414   public ConstNumber asConstNumber() {
    415     return null;
    416   }
    417 
    418   public boolean isConstInstruction() {
    419     return false;
    420   }
    421 
    422   public ConstInstruction asConstInstruction() {
    423     return null;
    424   }
    425 
    426   public boolean isConstClass() {
    427     return false;
    428   }
    429 
    430   public ConstClass asConstClass() {
    431     return null;
    432   }
    433 
    434   public boolean isConstString() {
    435     return false;
    436   }
    437 
    438   public ConstString asConstString() {
    439     return null;
    440   }
    441 
    442   public boolean isCmp() {
    443     return false;
    444   }
    445 
    446   public Cmp asCmp() {
    447     return null;
    448   }
    449 
    450   public boolean isJumpInstruction() {
    451     return false;
    452   }
    453 
    454   public JumpInstruction asJumpInstruction() {
    455     return null;
    456   }
    457 
    458   public boolean isGoto() {
    459     return false;
    460   }
    461 
    462   public Goto asGoto() {
    463     return null;
    464   }
    465 
    466   public boolean isIf() {
    467     return false;
    468   }
    469 
    470   public If asIf() {
    471     return null;
    472   }
    473 
    474   public boolean isSwitch() {
    475     return false;
    476   }
    477 
    478   public Switch asSwitch() {
    479     return null;
    480   }
    481 
    482   public boolean isInstanceGet() {
    483     return false;
    484   }
    485 
    486   public InstanceGet asInstanceGet() {
    487     return null;
    488   }
    489 
    490   public boolean isInstanceOf() {
    491     return false;
    492   }
    493 
    494   public InstanceOf asInstanceOf() {
    495     return null;
    496   }
    497 
    498   public boolean isInstancePut() {
    499     return false;
    500   }
    501 
    502   public InstancePut asInstancePut() {
    503     return null;
    504   }
    505 
    506   public boolean isInvoke() {
    507     return false;
    508   }
    509 
    510   public Invoke asInvoke() {
    511     return null;
    512   }
    513 
    514   public boolean isMonitor() {
    515     return false;
    516   }
    517 
    518   public Monitor asMonitor() {
    519     return null;
    520   }
    521 
    522   public boolean isMove() {
    523     return false;
    524   }
    525 
    526   public Move asMove() {
    527     return null;
    528   }
    529 
    530   public boolean isNewArrayEmpty() {
    531     return false;
    532   }
    533 
    534   public NewArrayEmpty asNewArrayEmpty() {
    535     return null;
    536   }
    537 
    538   public boolean isNewArrayFilledData() {
    539     return false;
    540   }
    541 
    542   public NewArrayFilledData asNewArrayFilledData() {
    543     return null;
    544   }
    545 
    546   public boolean isNeg() {
    547     return false;
    548   }
    549 
    550   public Neg asNeg() {
    551     return null;
    552   }
    553 
    554   public boolean isNewInstance() {
    555     return false;
    556   }
    557 
    558   public NewInstance asNewInstance() {
    559     return null;
    560   }
    561 
    562   public boolean isNot() {
    563     return false;
    564   }
    565 
    566   public Not asNot() {
    567     return null;
    568   }
    569 
    570   public boolean isNumberConversion() {
    571     return false;
    572   }
    573 
    574   public NumberConversion asNumberConversion() {
    575     return null;
    576   }
    577 
    578   public boolean isReturn() {
    579     return false;
    580   }
    581 
    582   public Return asReturn() {
    583     return null;
    584   }
    585 
    586   public boolean isThrow() {
    587     return false;
    588   }
    589 
    590   public Throw asThrow() {
    591     return null;
    592   }
    593 
    594   public boolean isStaticGet() {
    595     return false;
    596   }
    597 
    598   public StaticGet asStaticGet() {
    599     return null;
    600   }
    601 
    602   public boolean isStaticPut() {
    603     return false;
    604   }
    605 
    606   public StaticPut asStaticPut() {
    607     return null;
    608   }
    609 
    610   public boolean isAdd() {
    611     return false;
    612   }
    613 
    614   public Add asAdd() {
    615     return null;
    616   }
    617 
    618   public boolean isSub() {
    619     return false;
    620   }
    621 
    622   public Sub asSub() {
    623     return null;
    624   }
    625 
    626   public boolean isMul() {
    627     return false;
    628   }
    629 
    630   public Mul asMul() {
    631     return null;
    632   }
    633 
    634   public boolean isDiv() {
    635     return false;
    636   }
    637 
    638   public Div asDiv() {
    639     return null;
    640   }
    641 
    642   public boolean isRem() {
    643     return false;
    644   }
    645 
    646   public Rem asRem() {
    647     return null;
    648   }
    649 
    650   public boolean isLogicalBinop() {
    651     return false;
    652   }
    653 
    654   public LogicalBinop asLogicalBinop() {
    655     return null;
    656   }
    657 
    658   public boolean isShl() {
    659     return false;
    660   }
    661 
    662   public Shl asShl() {
    663     return null;
    664   }
    665 
    666   public boolean isShr() {
    667     return false;
    668   }
    669 
    670   public Shr asShr() {
    671     return null;
    672   }
    673 
    674   public boolean isUshr() {
    675     return false;
    676   }
    677 
    678   public Ushr asUshr() {
    679     return null;
    680   }
    681 
    682   public boolean isAnd() {
    683     return false;
    684   }
    685 
    686   public And asAnd() {
    687     return null;
    688   }
    689 
    690   public boolean isOr() {
    691     return false;
    692   }
    693 
    694   public Or asOr() {
    695     return null;
    696   }
    697 
    698   public boolean isXor() {
    699     return false;
    700   }
    701 
    702   public Xor asXor() {
    703     return null;
    704   }
    705 
    706   public boolean isMoveException() {
    707     return false;
    708   }
    709 
    710   public MoveException asMoveException() {
    711     return null;
    712   }
    713 
    714   public boolean isDebugInstruction() {
    715     return isDebugPosition()
    716         || isDebugLocalsChange()
    717         || isDebugLocalWrite()
    718         || isDebugLocalUninitialized();
    719   }
    720 
    721   public boolean isDebugPosition() {
    722     return false;
    723   }
    724 
    725   public DebugPosition asDebugPosition() {
    726     return null;
    727   }
    728 
    729   public boolean isDebugLocalsChange() {
    730     return false;
    731   }
    732 
    733   public DebugLocalsChange asDebugLocalsChange() {
    734     return null;
    735   }
    736 
    737   public boolean isDebugLocalUninitialized() {
    738     return false;
    739   }
    740 
    741   public DebugLocalUninitialized asDebugLocalUninitialized() {
    742     return null;
    743   }
    744 
    745   public boolean isDebugLocalWrite() {
    746     return false;
    747   }
    748 
    749   public DebugLocalWrite asDebugLocalWrite() {
    750     return null;
    751   }
    752 
    753   public boolean isInvokeMethod() {
    754     return false;
    755   }
    756 
    757   public InvokeMethod asInvokeMethod() {
    758     return null;
    759   }
    760 
    761   public boolean isInvokeMethodWithReceiver() {
    762     return false;
    763   }
    764 
    765   public InvokeMethodWithReceiver asInvokeMethodWithReceiver() {
    766     return null;
    767   }
    768 
    769   public boolean isInvokeNewArray() {
    770     return false;
    771   }
    772 
    773   public InvokeNewArray asInvokeNewArray() {
    774     return null;
    775   }
    776 
    777   public boolean isInvokeCustom() {
    778     return false;
    779   }
    780 
    781   public InvokeCustom asInvokeCustom() {
    782     return null;
    783   }
    784 
    785   public boolean isInvokeDirect() {
    786     return false;
    787   }
    788 
    789   public InvokeDirect asInvokeDirect() {
    790     return null;
    791   }
    792 
    793   public boolean isInvokeInterface() {
    794     return false;
    795   }
    796 
    797   public InvokeInterface asInvokeInterface() {
    798     return null;
    799   }
    800 
    801   public boolean isInvokeStatic() {
    802     return false;
    803   }
    804 
    805   public InvokeStatic asInvokeStatic() {
    806     return null;
    807   }
    808 
    809   public boolean isInvokeSuper() {
    810     return false;
    811   }
    812 
    813   public InvokeSuper asInvokeSuper() {
    814     return null;
    815   }
    816 
    817   public boolean isInvokeVirtual() {
    818     return false;
    819   }
    820 
    821   public InvokeVirtual asInvokeVirtual() {
    822     return null;
    823   }
    824 
    825   public boolean isInvokePolymorphic() {
    826     return false;
    827   }
    828 
    829   public InvokePolymorphic asInvokePolymorphic() {
    830     return null;
    831   }
    832 
    833   public boolean canBeFolded() {
    834     return false;
    835   }
    836 
    837   public ConstInstruction fold(IRCode code) {
    838     throw new Unreachable("Unsupported folding for " + this);
    839   }
    840 
    841   // Returns the inlining constraint for this instruction.
    842   public Constraint inliningConstraint(AppInfo info, DexType holder) {
    843     return Constraint.NEVER;
    844   }
    845 }
    846