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.code.Const; 7 import com.android.tools.r8.code.Const16; 8 import com.android.tools.r8.code.Const4; 9 import com.android.tools.r8.code.ConstHigh16; 10 import com.android.tools.r8.code.ConstWide; 11 import com.android.tools.r8.code.ConstWide16; 12 import com.android.tools.r8.code.ConstWide32; 13 import com.android.tools.r8.code.ConstWideHigh16; 14 import com.android.tools.r8.dex.Constants; 15 import com.android.tools.r8.graph.AppInfo; 16 import com.android.tools.r8.graph.DexType; 17 import com.android.tools.r8.ir.conversion.DexBuilder; 18 import com.android.tools.r8.ir.optimize.Inliner.Constraint; 19 import com.android.tools.r8.utils.NumberUtils; 20 21 public class ConstNumber extends ConstInstruction { 22 23 public final ConstType type; 24 private final long value; 25 ConstNumber(ConstType type, Value dest, long value)26 public ConstNumber(ConstType type, Value dest, long value) { 27 super(dest); 28 // We create const numbers after register allocation for rematerialization of values. Those 29 // are all for fixed register values. All other values that are used as the destination for 30 // const number instructions should be marked as constants. 31 assert dest.isFixedRegisterValue() || dest.definition.isConstNumber(); 32 assert type != ConstType.OBJECT; 33 this.type = type; 34 this.value = value; 35 } 36 copyOf(IRCode code, ConstNumber original)37 public static ConstNumber copyOf(IRCode code, ConstNumber original) { 38 Value newValue = 39 new Value( 40 code.valueNumberGenerator.next(), 41 original.outType(), 42 original.getDebugInfo()); 43 return new ConstNumber(original.type, newValue, original.getRawValue()); 44 } 45 preciseTypeUnknown()46 private boolean preciseTypeUnknown() { 47 return type == ConstType.INT_OR_FLOAT || type == ConstType.LONG_OR_DOUBLE; 48 } 49 dest()50 public Value dest() { 51 return outValue; 52 } 53 getIntValue()54 public int getIntValue() { 55 assert type == ConstType.INT || type == ConstType.INT_OR_FLOAT; 56 return (int) value; 57 } 58 getLongValue()59 public long getLongValue() { 60 assert type == ConstType.LONG || type == ConstType.LONG_OR_DOUBLE; 61 return value; 62 } 63 getFloatValue()64 public float getFloatValue() { 65 assert type == ConstType.FLOAT || type == ConstType.INT_OR_FLOAT; 66 return Float.intBitsToFloat((int) value); 67 } 68 getDoubleValue()69 public double getDoubleValue() { 70 assert type == ConstType.DOUBLE || type == ConstType.LONG_OR_DOUBLE; 71 return Double.longBitsToDouble(value); 72 } 73 getRawValue()74 public long getRawValue() { 75 return value; 76 } 77 isZero()78 public boolean isZero() { 79 return value == 0; 80 } 81 isIntegerNegativeOne(NumericType type)82 public boolean isIntegerNegativeOne(NumericType type) { 83 assert type == NumericType.INT || type == NumericType.LONG; 84 if (type == NumericType.INT) { 85 return getIntValue() == -1; 86 } 87 return getLongValue() == -1; 88 } 89 90 @Override buildDex(DexBuilder builder)91 public void buildDex(DexBuilder builder) { 92 if (!dest().needsRegister()) { 93 builder.addNop(this); 94 return; 95 } 96 97 int register = builder.allocatedRegister(dest(), getNumber()); 98 if (MoveType.fromConstType(type) == MoveType.SINGLE) { 99 assert NumberUtils.is32Bit(value); 100 if ((register & 0xf) == register && NumberUtils.is4Bit(value)) { 101 builder.add(this, new Const4(register, (int) value)); 102 } else if (NumberUtils.is16Bit(value)) { 103 builder.add(this, new Const16(register, (int) value)); 104 } else if ((value & 0x0000ffffL) == 0) { 105 builder.add(this, new ConstHigh16(register, ((int) value) >>> 16)); 106 } else { 107 builder.add(this, new Const(register, (int) value)); 108 } 109 } else { 110 assert MoveType.fromConstType(type) == MoveType.WIDE; 111 if (NumberUtils.is16Bit(value)) { 112 builder.add(this, new ConstWide16(register, (int) value)); 113 } else if ((value & 0x0000ffffffffffffL) == 0) { 114 builder.add(this, new ConstWideHigh16(register, (int) (value >>> 48))); 115 } else if (NumberUtils.is32Bit(value)) { 116 builder.add(this, new ConstWide32(register, (int) value)); 117 } else { 118 builder.add(this, new ConstWide(register, value)); 119 } 120 } 121 } 122 123 @Override maxInValueRegister()124 public int maxInValueRegister() { 125 assert false : "Const has no register arguments."; 126 return 0; 127 } 128 129 @Override maxOutValueRegister()130 public int maxOutValueRegister() { 131 return Constants.U8BIT_MAX; 132 } 133 134 @Override toString()135 public String toString() { 136 return super.toString() + " " + value + " (" + type + ")"; 137 } 138 139 @Override identicalNonValueParts(Instruction other)140 public boolean identicalNonValueParts(Instruction other) { 141 if (preciseTypeUnknown()) { 142 return false; 143 } 144 ConstNumber o = other.asConstNumber(); 145 return o.type == type && o.value == value; 146 } 147 148 @Override compareNonValueParts(Instruction other)149 public int compareNonValueParts(Instruction other) { 150 ConstNumber o = other.asConstNumber(); 151 int result; 152 result = type.ordinal() - o.type.ordinal(); 153 if (result != 0) { 154 return result; 155 } 156 return Long.signum(value - o.value); 157 } 158 is8Bit()159 public boolean is8Bit() { 160 return NumberUtils.is8Bit(value); 161 } 162 negativeIs8Bit()163 public boolean negativeIs8Bit() { 164 return NumberUtils.negativeIs8Bit(value); 165 } 166 is16Bit()167 public boolean is16Bit() { 168 return NumberUtils.is16Bit(value); 169 } 170 negativeIs16Bit()171 public boolean negativeIs16Bit() { 172 return NumberUtils.negativeIs16Bit(value); 173 } 174 175 @Override isOutConstant()176 public boolean isOutConstant() { 177 return true; 178 } 179 180 @Override isConstNumber()181 public boolean isConstNumber() { 182 return true; 183 } 184 185 @Override asConstNumber()186 public ConstNumber asConstNumber() { 187 return this; 188 } 189 190 @Override inliningConstraint(AppInfo info, DexType holder)191 public Constraint inliningConstraint(AppInfo info, DexType holder) { 192 return Constraint.ALWAYS; 193 } 194 } 195