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 static com.android.tools.r8.dex.Constants.U4BIT_MAX; 7 import static com.android.tools.r8.dex.Constants.U8BIT_MAX; 8 9 import com.android.tools.r8.errors.Unreachable; 10 import com.android.tools.r8.ir.conversion.DexBuilder; 11 import com.android.tools.r8.utils.CfgPrinter; 12 import java.util.List; 13 14 public class If extends JumpInstruction { 15 16 public enum Type { 17 EQ, GE, GT, LE, LT, NE; 18 19 // Returns the comparison type if the operands are swapped. forSwappedOperands()20 public Type forSwappedOperands() { 21 switch (this) { 22 case EQ: 23 case NE: 24 return this; 25 case GE: 26 return Type.LE; 27 case GT: 28 return Type.LT; 29 case LE: 30 return Type.GE; 31 case LT: 32 return Type.GT; 33 default: 34 throw new Unreachable("Unknown if condition type."); 35 } 36 } 37 inverted()38 public Type inverted() { 39 switch (this) { 40 case EQ: 41 return Type.NE; 42 case GE: 43 return Type.LT; 44 case GT: 45 return Type.LE; 46 case LE: 47 return Type.GT; 48 case LT: 49 return Type.GE; 50 case NE: 51 return Type.EQ; 52 default: 53 throw new Unreachable("Unknown if condition type."); 54 } 55 } 56 } 57 58 private Type type; 59 If(Type type, Value value)60 public If(Type type, Value value) { 61 super(null, value); 62 this.type = type; 63 } 64 If(Type type, List<Value> values)65 public If(Type type, List<Value> values) { 66 super(null, values); 67 this.type = type; 68 } 69 isZeroTest()70 public boolean isZeroTest() { 71 return inValues.size() == 1; 72 } 73 getType()74 public Type getType() { 75 return type; 76 } 77 invert()78 public void invert() { 79 BasicBlock tmp = getTrueTarget(); 80 setTrueTarget(fallthroughBlock()); 81 setFallthroughBlock(tmp); 82 type = type.inverted(); 83 } 84 getTrueTarget()85 public BasicBlock getTrueTarget() { 86 assert getBlock().exit() == this; 87 List<BasicBlock> successors = getBlock().getSuccessors(); 88 assert successors.size() >= 2; 89 return successors.get(successors.size() - 2); 90 } 91 setTrueTarget(BasicBlock block)92 public void setTrueTarget(BasicBlock block) { 93 assert getBlock().exit() == this; 94 List<BasicBlock> successors = getBlock().getSuccessors(); 95 assert successors.size() >= 2; 96 successors.set(successors.size() - 2, block); 97 } 98 99 @Override fallthroughBlock()100 public BasicBlock fallthroughBlock() { 101 assert getBlock().exit() == this; 102 List<BasicBlock> successors = getBlock().getSuccessors(); 103 assert successors.size() >= 2; 104 return successors.get(successors.size() - 1); 105 } 106 107 @Override setFallthroughBlock(BasicBlock block)108 public void setFallthroughBlock(BasicBlock block) { 109 List<BasicBlock> successors = getBlock().getSuccessors(); 110 successors.set(successors.size() - 1, block); 111 } 112 113 @Override buildDex(DexBuilder builder)114 public void buildDex(DexBuilder builder) { 115 builder.addIf(this); 116 } 117 118 @Override toString()119 public String toString() { 120 return super.toString() + " " + type + " block " + getTrueTarget().getNumber() 121 + " (fallthrough " + fallthroughBlock().getNumber() + ")"; 122 } 123 124 @Override maxInValueRegister()125 public int maxInValueRegister() { 126 return isZeroTest() ? U8BIT_MAX : U4BIT_MAX; 127 } 128 129 @Override maxOutValueRegister()130 public int maxOutValueRegister() { 131 assert false : "If instructions define no values."; 132 return 0; 133 } 134 135 @Override print(CfgPrinter printer)136 public void print(CfgPrinter printer) { 137 super.print(printer); 138 printer.append(" B").append(getTrueTarget().getNumber()); 139 } 140 141 @Override identicalNonValueParts(Instruction other)142 public boolean identicalNonValueParts(Instruction other) { 143 If o = other.asIf(); 144 return o.getTrueTarget() == getTrueTarget() 145 && o.fallthroughBlock() == fallthroughBlock() 146 && o.type == type; 147 } 148 149 @Override compareNonValueParts(Instruction other)150 public int compareNonValueParts(Instruction other) { 151 assert other.isIf(); 152 assert false : "Not supported"; 153 return 0; 154 } 155 156 targetFromCondition(int cond)157 public BasicBlock targetFromCondition(int cond) { 158 switch (type) { 159 case EQ: 160 return cond == 0 ? getTrueTarget() : fallthroughBlock(); 161 case NE: 162 return cond != 0 ? getTrueTarget() : fallthroughBlock(); 163 case GE: 164 return cond >= 0 ? getTrueTarget() : fallthroughBlock(); 165 case GT: 166 return cond > 0 ? getTrueTarget() : fallthroughBlock(); 167 case LE: 168 return cond <= 0 ? getTrueTarget() : fallthroughBlock(); 169 case LT: 170 return cond < 0 ? getTrueTarget() : fallthroughBlock(); 171 } 172 throw new Unreachable("Unexpected condition type " + type); 173 } 174 175 @Override isIf()176 public boolean isIf() { 177 return true; 178 } 179 180 @Override asIf()181 public If asIf() { 182 return this; 183 } 184 } 185