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 5 package com.android.tools.r8.ir.code; 6 7 import com.android.tools.r8.code.CmpLong; 8 import com.android.tools.r8.code.CmpgDouble; 9 import com.android.tools.r8.code.CmpgFloat; 10 import com.android.tools.r8.code.CmplDouble; 11 import com.android.tools.r8.code.CmplFloat; 12 import com.android.tools.r8.dex.Constants; 13 import com.android.tools.r8.errors.Unreachable; 14 import com.android.tools.r8.ir.conversion.DexBuilder; 15 import com.android.tools.r8.utils.LongInterval; 16 import com.android.tools.r8.utils.StringUtils; 17 import com.android.tools.r8.utils.StringUtils.BraceType; 18 19 public class Cmp extends Binop { 20 21 public enum Bias { 22 NONE, GT, LT 23 } 24 25 private final Bias bias; 26 Cmp(NumericType type, Bias bias, Value dest, Value left, Value right)27 public Cmp(NumericType type, Bias bias, Value dest, Value left, Value right) { 28 super(type, dest, left, right); 29 this.bias = bias; 30 } 31 32 @Override isCommutative()33 public boolean isCommutative() { 34 return false; 35 } 36 37 @Override buildDex(DexBuilder builder)38 public void buildDex(DexBuilder builder) { 39 com.android.tools.r8.code.Instruction instruction; 40 int dest = builder.allocatedRegister(outValue, getNumber()); 41 int left = builder.allocatedRegister(leftValue(), getNumber()); 42 int right = builder.allocatedRegister(rightValue(), getNumber()); 43 switch (type) { 44 case DOUBLE: 45 assert bias != Bias.NONE; 46 if (bias == Bias.GT) { 47 instruction = new CmpgDouble(dest, left, right); 48 } else { 49 assert bias == Bias.LT; 50 instruction = new CmplDouble(dest, left, right); 51 } 52 break; 53 case FLOAT: 54 assert bias != Bias.NONE; 55 if (bias == Bias.GT) { 56 instruction = new CmpgFloat(dest, left, right); 57 } else { 58 assert bias == Bias.LT; 59 instruction = new CmplFloat(dest, left, right); 60 } 61 break; 62 case LONG: 63 assert bias == Bias.NONE; 64 instruction = new CmpLong(dest, left, right); 65 break; 66 default: 67 throw new Unreachable("Unexpected type " + type); 68 } 69 builder.add(this, instruction); 70 } 71 biasToString(Bias bias)72 private String biasToString(Bias bias) { 73 switch (bias) { 74 case NONE: 75 return "none"; 76 case GT: 77 return "gt"; 78 case LT: 79 return "lt"; 80 default: 81 throw new Unreachable("Unexpected bias " + bias); 82 } 83 } 84 85 @Override toString()86 public String toString() { 87 StringBuilder builder = new StringBuilder(); 88 builder.append(getClass().getSimpleName()); 89 builder.append(" ("); 90 switch (type) { 91 case DOUBLE: 92 builder.append("double, "); 93 builder.append(biasToString(bias)); 94 break; 95 case FLOAT: 96 builder.append("float, "); 97 builder.append(biasToString(bias)); 98 break; 99 case LONG: 100 builder.append("long"); 101 break; 102 default: 103 throw new Unreachable("Unexpected type " + type); 104 } 105 builder.append(")"); 106 for (int i = builder.length(); i < 20; i++) { 107 builder.append(" "); 108 } 109 if (outValue != null) { 110 builder.append(outValue); 111 builder.append(" <- "); 112 } 113 StringUtils.append(builder, inValues, ", ", BraceType.NONE); 114 return builder.toString(); 115 } 116 117 @Override identicalNonValueParts(Instruction other)118 public boolean identicalNonValueParts(Instruction other) { 119 return other.asCmp().bias == bias; 120 } 121 122 @Override compareNonValueParts(Instruction other)123 public int compareNonValueParts(Instruction other) { 124 return bias.ordinal() - other.asCmp().bias.ordinal(); 125 } 126 127 @Override maxInValueRegister()128 public int maxInValueRegister() { 129 return Constants.U8BIT_MAX; 130 } 131 132 @Override maxOutValueRegister()133 public int maxOutValueRegister() { 134 return Constants.U8BIT_MAX; 135 } 136 nonOverlapingRanges()137 private boolean nonOverlapingRanges() { 138 return type == NumericType.LONG 139 && leftValue().hasValueRange() 140 && rightValue().hasValueRange() 141 && leftValue().getValueRange().doesntOverlapWith(rightValue().getValueRange()); 142 } 143 144 @Override canBeFolded()145 public boolean canBeFolded() { 146 return (leftValue().isConstant() && rightValue().isConstant()) || nonOverlapingRanges(); 147 } 148 149 @Override fold(IRCode code)150 public ConstInstruction fold(IRCode code) { 151 assert canBeFolded(); 152 int result; 153 if (type == NumericType.LONG) { 154 if (leftValue().isConstant() && rightValue().isConstant()) { 155 long left = leftValue().getConstInstruction().asConstNumber().getLongValue(); 156 long right = rightValue().getConstInstruction().asConstNumber().getLongValue(); 157 result = Integer.signum(Long.compare(left, right)); 158 } else { 159 assert nonOverlapingRanges(); 160 LongInterval leftRange = leftValue().getValueRange(); 161 LongInterval rightRange = rightValue().getValueRange(); 162 result = Integer.signum(Long.compare(leftRange.getMin(), rightRange.getMin())); 163 } 164 } else if (type == NumericType.FLOAT) { 165 float left = leftValue().getConstInstruction().asConstNumber().getFloatValue(); 166 float right = rightValue().getConstInstruction().asConstNumber().getFloatValue(); 167 if (Float.isNaN(left) || Float.isNaN(right)) { 168 result = bias == Bias.GT ? 1 : -1; 169 } else { 170 result = (int) Math.signum(left - right); 171 } 172 } else { 173 assert type == NumericType.DOUBLE; 174 double left = leftValue().getConstInstruction().asConstNumber().getDoubleValue(); 175 double right = rightValue().getConstInstruction().asConstNumber().getDoubleValue(); 176 if (Double.isNaN(left) || Double.isNaN(right)) { 177 result = bias == Bias.GT ? 1 : -1; 178 } else { 179 result = (int) Math.signum(left - right); 180 } 181 } 182 assert result == -1 || result == 0 || result == 1; 183 Value value = code.createValue(MoveType.SINGLE, getDebugInfo()); 184 return new ConstNumber(ConstType.INT, value, result); 185 } 186 187 @Override isCmp()188 public boolean isCmp() { 189 return true; 190 } 191 192 @Override asCmp()193 public Cmp asCmp() { 194 return this; 195 } 196 } 197