• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Instruction(Value outValue)30   protected Instruction(Value outValue) {
31     setOutValue(outValue);
32   }
33 
Instruction(Value outValue, Value inValue)34   protected Instruction(Value outValue, Value inValue) {
35     addInValue(inValue);
36     setOutValue(outValue);
37   }
38 
Instruction(Value outValue, List<? extends Value> inValues)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 
inValues()48   public List<Value> inValues() {
49     return inValues;
50   }
51 
addInValue(Value value)52   protected void addInValue(Value value) {
53     if (value != null) {
54       inValues.add(value);
55       value.addUser(this);
56     }
57   }
58 
outValue()59   public Value outValue() {
60     return outValue;
61   }
62 
setOutValue(Value value)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 
addDebugValue(Value value)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 
clearUserInfo(Instruction instruction)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 
outType()94   public final MoveType outType() {
95     return outValue.outType();
96   }
97 
buildDex(DexBuilder builder)98   public abstract void buildDex(DexBuilder builder);
99 
replaceValue(Value oldValue, Value newValue)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 
replaceDebugPhi(Phi phi, Value value)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    */
getBlock()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    */
setBlock(BasicBlock block)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    */
clearBlock()152   public void clearBlock() {
153     assert block != null;
154     block = null;
155   }
156 
getInstructionName()157   public String getInstructionName() {
158     return getClass().getSimpleName();
159   }
160 
161   @Override
toString()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 
print(CfgPrinter printer)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 
printLIR(CfgPrinter printer)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 
getNumber()206   public int getNumber() {
207     return number;
208   }
209 
setNumber(int number)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    */
identicalNonValueParts(Instruction other)220   public abstract boolean identicalNonValueParts(Instruction other);
221 
compareNonValueParts(Instruction other)222   public abstract int compareNonValueParts(Instruction other);
223 
identicalAfterRegisterAllocation( Value a, int aInstr, Value b, int bInstr, RegisterAllocator allocator)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 
identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator)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    */
instructionTypeCanThrow()284   public boolean instructionTypeCanThrow() {
285     return false;
286   }
287 
instructionInstanceCanThrow()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. */
canBeDeadCode(IRCode code, InternalOptions options)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    */
needsValueInRegister(Value value)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    */
isOutConstant()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    */
getOutConstantConstInstruction()318   public ConstInstruction getOutConstantConstInstruction() {
319     return null;
320   }
321 
maxInValueRegister()322   public abstract int maxInValueRegister();
323 
maxOutValueRegister()324   public abstract int maxOutValueRegister();
325 
getDebugInfo()326   public DebugInfo getDebugInfo() {
327     return outValue == null ? null : outValue.getDebugInfo();
328   }
329 
getLocalInfo()330   public DebugLocalInfo getLocalInfo() {
331     return outValue == null ? null : outValue.getLocalInfo();
332   }
333 
getPreviousLocalValue()334   public Value getPreviousLocalValue() {
335     return outValue == null ? null : outValue.getPreviousLocalValue();
336   }
337 
getDebugValues()338   public List<Value> getDebugValues() {
339     return debugValues != null ? debugValues : ImmutableList.of();
340   }
341 
replacePreviousLocalValue(Value value)342   public void replacePreviousLocalValue(Value value) {
343     outValue.replacePreviousLocalValue(value);
344   }
345 
isArrayGet()346   public boolean isArrayGet() {
347     return false;
348   }
349 
asArrayGet()350   public ArrayGet asArrayGet() {
351     return null;
352   }
353 
isArrayLength()354   public boolean isArrayLength() {
355     return false;
356   }
357 
asArrayLength()358   public ArrayLength asArrayLength() {
359     return null;
360   }
361 
isArrayPut()362   public boolean isArrayPut() {
363     return false;
364   }
365 
asArrayPut()366   public ArrayPut asArrayPut() {
367     return null;
368   }
369 
isArgument()370   public boolean isArgument() {
371     return false;
372   }
373 
asArgument()374   public Argument asArgument() {
375     return null;
376   }
377 
isArithmeticBinop()378   public boolean isArithmeticBinop() {
379     return false;
380   }
381 
asArithmeticBinop()382   public ArithmeticBinop asArithmeticBinop() {
383     return null;
384   }
385 
isBinop()386   public boolean isBinop() {
387     return false;
388   }
389 
asBinop()390   public Binop asBinop() {
391     return null;
392   }
393 
isUnop()394   public boolean isUnop() {
395     return false;
396   }
397 
asUnop()398   public Unop asUnop() {
399     return null;
400   }
401 
isCheckCast()402   public boolean isCheckCast() {
403     return false;
404   }
405 
asCheckCast()406   public CheckCast asCheckCast() {
407     return null;
408   }
409 
isConstNumber()410   public boolean isConstNumber() {
411     return false;
412   }
413 
asConstNumber()414   public ConstNumber asConstNumber() {
415     return null;
416   }
417 
isConstInstruction()418   public boolean isConstInstruction() {
419     return false;
420   }
421 
asConstInstruction()422   public ConstInstruction asConstInstruction() {
423     return null;
424   }
425 
isConstClass()426   public boolean isConstClass() {
427     return false;
428   }
429 
asConstClass()430   public ConstClass asConstClass() {
431     return null;
432   }
433 
isConstString()434   public boolean isConstString() {
435     return false;
436   }
437 
asConstString()438   public ConstString asConstString() {
439     return null;
440   }
441 
isCmp()442   public boolean isCmp() {
443     return false;
444   }
445 
asCmp()446   public Cmp asCmp() {
447     return null;
448   }
449 
isJumpInstruction()450   public boolean isJumpInstruction() {
451     return false;
452   }
453 
asJumpInstruction()454   public JumpInstruction asJumpInstruction() {
455     return null;
456   }
457 
isGoto()458   public boolean isGoto() {
459     return false;
460   }
461 
asGoto()462   public Goto asGoto() {
463     return null;
464   }
465 
isIf()466   public boolean isIf() {
467     return false;
468   }
469 
asIf()470   public If asIf() {
471     return null;
472   }
473 
isSwitch()474   public boolean isSwitch() {
475     return false;
476   }
477 
asSwitch()478   public Switch asSwitch() {
479     return null;
480   }
481 
isInstanceGet()482   public boolean isInstanceGet() {
483     return false;
484   }
485 
asInstanceGet()486   public InstanceGet asInstanceGet() {
487     return null;
488   }
489 
isInstanceOf()490   public boolean isInstanceOf() {
491     return false;
492   }
493 
asInstanceOf()494   public InstanceOf asInstanceOf() {
495     return null;
496   }
497 
isInstancePut()498   public boolean isInstancePut() {
499     return false;
500   }
501 
asInstancePut()502   public InstancePut asInstancePut() {
503     return null;
504   }
505 
isInvoke()506   public boolean isInvoke() {
507     return false;
508   }
509 
asInvoke()510   public Invoke asInvoke() {
511     return null;
512   }
513 
isMonitor()514   public boolean isMonitor() {
515     return false;
516   }
517 
asMonitor()518   public Monitor asMonitor() {
519     return null;
520   }
521 
isMove()522   public boolean isMove() {
523     return false;
524   }
525 
asMove()526   public Move asMove() {
527     return null;
528   }
529 
isNewArrayEmpty()530   public boolean isNewArrayEmpty() {
531     return false;
532   }
533 
asNewArrayEmpty()534   public NewArrayEmpty asNewArrayEmpty() {
535     return null;
536   }
537 
isNewArrayFilledData()538   public boolean isNewArrayFilledData() {
539     return false;
540   }
541 
asNewArrayFilledData()542   public NewArrayFilledData asNewArrayFilledData() {
543     return null;
544   }
545 
isNeg()546   public boolean isNeg() {
547     return false;
548   }
549 
asNeg()550   public Neg asNeg() {
551     return null;
552   }
553 
isNewInstance()554   public boolean isNewInstance() {
555     return false;
556   }
557 
asNewInstance()558   public NewInstance asNewInstance() {
559     return null;
560   }
561 
isNot()562   public boolean isNot() {
563     return false;
564   }
565 
asNot()566   public Not asNot() {
567     return null;
568   }
569 
isNumberConversion()570   public boolean isNumberConversion() {
571     return false;
572   }
573 
asNumberConversion()574   public NumberConversion asNumberConversion() {
575     return null;
576   }
577 
isReturn()578   public boolean isReturn() {
579     return false;
580   }
581 
asReturn()582   public Return asReturn() {
583     return null;
584   }
585 
isThrow()586   public boolean isThrow() {
587     return false;
588   }
589 
asThrow()590   public Throw asThrow() {
591     return null;
592   }
593 
isStaticGet()594   public boolean isStaticGet() {
595     return false;
596   }
597 
asStaticGet()598   public StaticGet asStaticGet() {
599     return null;
600   }
601 
isStaticPut()602   public boolean isStaticPut() {
603     return false;
604   }
605 
asStaticPut()606   public StaticPut asStaticPut() {
607     return null;
608   }
609 
isAdd()610   public boolean isAdd() {
611     return false;
612   }
613 
asAdd()614   public Add asAdd() {
615     return null;
616   }
617 
isSub()618   public boolean isSub() {
619     return false;
620   }
621 
asSub()622   public Sub asSub() {
623     return null;
624   }
625 
isMul()626   public boolean isMul() {
627     return false;
628   }
629 
asMul()630   public Mul asMul() {
631     return null;
632   }
633 
isDiv()634   public boolean isDiv() {
635     return false;
636   }
637 
asDiv()638   public Div asDiv() {
639     return null;
640   }
641 
isRem()642   public boolean isRem() {
643     return false;
644   }
645 
asRem()646   public Rem asRem() {
647     return null;
648   }
649 
isLogicalBinop()650   public boolean isLogicalBinop() {
651     return false;
652   }
653 
asLogicalBinop()654   public LogicalBinop asLogicalBinop() {
655     return null;
656   }
657 
isShl()658   public boolean isShl() {
659     return false;
660   }
661 
asShl()662   public Shl asShl() {
663     return null;
664   }
665 
isShr()666   public boolean isShr() {
667     return false;
668   }
669 
asShr()670   public Shr asShr() {
671     return null;
672   }
673 
isUshr()674   public boolean isUshr() {
675     return false;
676   }
677 
asUshr()678   public Ushr asUshr() {
679     return null;
680   }
681 
isAnd()682   public boolean isAnd() {
683     return false;
684   }
685 
asAnd()686   public And asAnd() {
687     return null;
688   }
689 
isOr()690   public boolean isOr() {
691     return false;
692   }
693 
asOr()694   public Or asOr() {
695     return null;
696   }
697 
isXor()698   public boolean isXor() {
699     return false;
700   }
701 
asXor()702   public Xor asXor() {
703     return null;
704   }
705 
isMoveException()706   public boolean isMoveException() {
707     return false;
708   }
709 
asMoveException()710   public MoveException asMoveException() {
711     return null;
712   }
713 
isDebugInstruction()714   public boolean isDebugInstruction() {
715     return isDebugPosition()
716         || isDebugLocalsChange()
717         || isDebugLocalWrite()
718         || isDebugLocalUninitialized();
719   }
720 
isDebugPosition()721   public boolean isDebugPosition() {
722     return false;
723   }
724 
asDebugPosition()725   public DebugPosition asDebugPosition() {
726     return null;
727   }
728 
isDebugLocalsChange()729   public boolean isDebugLocalsChange() {
730     return false;
731   }
732 
asDebugLocalsChange()733   public DebugLocalsChange asDebugLocalsChange() {
734     return null;
735   }
736 
isDebugLocalUninitialized()737   public boolean isDebugLocalUninitialized() {
738     return false;
739   }
740 
asDebugLocalUninitialized()741   public DebugLocalUninitialized asDebugLocalUninitialized() {
742     return null;
743   }
744 
isDebugLocalWrite()745   public boolean isDebugLocalWrite() {
746     return false;
747   }
748 
asDebugLocalWrite()749   public DebugLocalWrite asDebugLocalWrite() {
750     return null;
751   }
752 
isInvokeMethod()753   public boolean isInvokeMethod() {
754     return false;
755   }
756 
asInvokeMethod()757   public InvokeMethod asInvokeMethod() {
758     return null;
759   }
760 
isInvokeMethodWithReceiver()761   public boolean isInvokeMethodWithReceiver() {
762     return false;
763   }
764 
asInvokeMethodWithReceiver()765   public InvokeMethodWithReceiver asInvokeMethodWithReceiver() {
766     return null;
767   }
768 
isInvokeNewArray()769   public boolean isInvokeNewArray() {
770     return false;
771   }
772 
asInvokeNewArray()773   public InvokeNewArray asInvokeNewArray() {
774     return null;
775   }
776 
isInvokeCustom()777   public boolean isInvokeCustom() {
778     return false;
779   }
780 
asInvokeCustom()781   public InvokeCustom asInvokeCustom() {
782     return null;
783   }
784 
isInvokeDirect()785   public boolean isInvokeDirect() {
786     return false;
787   }
788 
asInvokeDirect()789   public InvokeDirect asInvokeDirect() {
790     return null;
791   }
792 
isInvokeInterface()793   public boolean isInvokeInterface() {
794     return false;
795   }
796 
asInvokeInterface()797   public InvokeInterface asInvokeInterface() {
798     return null;
799   }
800 
isInvokeStatic()801   public boolean isInvokeStatic() {
802     return false;
803   }
804 
asInvokeStatic()805   public InvokeStatic asInvokeStatic() {
806     return null;
807   }
808 
isInvokeSuper()809   public boolean isInvokeSuper() {
810     return false;
811   }
812 
asInvokeSuper()813   public InvokeSuper asInvokeSuper() {
814     return null;
815   }
816 
isInvokeVirtual()817   public boolean isInvokeVirtual() {
818     return false;
819   }
820 
asInvokeVirtual()821   public InvokeVirtual asInvokeVirtual() {
822     return null;
823   }
824 
isInvokePolymorphic()825   public boolean isInvokePolymorphic() {
826     return false;
827   }
828 
asInvokePolymorphic()829   public InvokePolymorphic asInvokePolymorphic() {
830     return null;
831   }
832 
canBeFolded()833   public boolean canBeFolded() {
834     return false;
835   }
836 
fold(IRCode code)837   public ConstInstruction fold(IRCode code) {
838     throw new Unreachable("Unsupported folding for " + this);
839   }
840 
841   // Returns the inlining constraint for this instruction.
inliningConstraint(AppInfo info, DexType holder)842   public Constraint inliningConstraint(AppInfo info, DexType holder) {
843     return Constraint.NEVER;
844   }
845 }
846