• 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 
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