// Binary encoding of 2^31 for type double.
static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
+// Minimum value for a primitive integer.
+static int32_t constexpr kPrimIntMin = 0x80000000;
+// Minimum value for a primitive long.
+static int64_t constexpr kPrimLongMin = INT64_C(0x8000000000000000);
+
// Maximum value for a primitive integer.
static int32_t constexpr kPrimIntMax = 0x7fffffff;
// Maximum value for a primitive long.
-static int64_t constexpr kPrimLongMax = 0x7fffffffffffffff;
+static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff);
class Assembler;
class CodeGenerator;
inst->ReplaceWith(constant);
inst->GetBlock()->RemoveInstruction(inst);
}
+ } else if (inst->IsTypeConversion()) {
+ // Constant folding: replace `TypeConversion(a)' with a constant at
+ // compile time if `a' is a constant.
+ HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
+ if (constant != nullptr) {
+ inst->ReplaceWith(constant);
+ inst->GetBlock()->RemoveInstruction(inst);
+ }
} else if (inst->IsDivZeroCheck()) {
// We can safely remove the check if the input is a non-null constant.
HDivZeroCheck* check = inst->AsDivZeroCheck();
#include "nodes.h"
+#include "code_generator.h"
#include "ssa_builder.h"
#include "base/bit_vector-inl.h"
#include "utils/growable_array.h"
}
}
+HConstant* HTypeConversion::TryStaticEvaluation() const {
+ HGraph* graph = GetBlock()->GetGraph();
+ if (GetInput()->IsIntConstant()) {
+ int32_t value = GetInput()->AsIntConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimLong:
+ return graph->GetLongConstant(static_cast<int64_t>(value));
+ case Primitive::kPrimFloat:
+ return graph->GetFloatConstant(static_cast<float>(value));
+ case Primitive::kPrimDouble:
+ return graph->GetDoubleConstant(static_cast<double>(value));
+ default:
+ return nullptr;
+ }
+ } else if (GetInput()->IsLongConstant()) {
+ int64_t value = GetInput()->AsLongConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimInt:
+ return graph->GetIntConstant(static_cast<int32_t>(value));
+ case Primitive::kPrimFloat:
+ return graph->GetFloatConstant(static_cast<float>(value));
+ case Primitive::kPrimDouble:
+ return graph->GetDoubleConstant(static_cast<double>(value));
+ default:
+ return nullptr;
+ }
+ } else if (GetInput()->IsFloatConstant()) {
+ float value = GetInput()->AsFloatConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimInt:
+ if (std::isnan(value))
+ return graph->GetIntConstant(0);
+ if (value >= kPrimIntMax)
+ return graph->GetIntConstant(kPrimIntMax);
+ if (value <= kPrimIntMin)
+ return graph->GetIntConstant(kPrimIntMin);
+ return graph->GetIntConstant(static_cast<int32_t>(value));
+ case Primitive::kPrimLong:
+ if (std::isnan(value))
+ return graph->GetLongConstant(0);
+ if (value >= kPrimLongMax)
+ return graph->GetLongConstant(kPrimLongMax);
+ if (value <= kPrimLongMin)
+ return graph->GetLongConstant(kPrimLongMin);
+ return graph->GetLongConstant(static_cast<int64_t>(value));
+ case Primitive::kPrimDouble:
+ return graph->GetDoubleConstant(static_cast<double>(value));
+ default:
+ return nullptr;
+ }
+ } else if (GetInput()->IsDoubleConstant()) {
+ double value = GetInput()->AsDoubleConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimInt:
+ if (std::isnan(value))
+ return graph->GetIntConstant(0);
+ if (value >= kPrimIntMax)
+ return graph->GetIntConstant(kPrimIntMax);
+ if (value <= kPrimLongMin)
+ return graph->GetIntConstant(kPrimIntMin);
+ return graph->GetIntConstant(static_cast<int32_t>(value));
+ case Primitive::kPrimLong:
+ if (std::isnan(value))
+ return graph->GetLongConstant(0);
+ if (value >= kPrimLongMax)
+ return graph->GetLongConstant(kPrimLongMax);
+ if (value <= kPrimLongMin)
+ return graph->GetLongConstant(kPrimLongMin);
+ return graph->GetLongConstant(static_cast<int64_t>(value));
+ case Primitive::kPrimFloat:
+ return graph->GetFloatConstant(static_cast<float>(value));
+ default:
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
HConstant* HUnaryOperation::TryStaticEvaluation() const {
if (GetInput()->IsIntConstant()) {
int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
+ // Try to statically evaluate the conversion and return a HConstant
+ // containing the result. If the input cannot be converted, return nullptr.
+ HConstant* TryStaticEvaluation() const;
+
DECLARE_INSTRUCTION(TypeConversion);
private:
assertCharEquals((char)0, $opt$IntToChar(-2147483648)); // -(2^31)
}
+ // A dummy value to defeat inlining of these routines.
+ static boolean doThrow = false;
// These methods produce int-to-long Dex instructions.
- static long $opt$ByteToLong(byte a) { return (long)a; }
- static long $opt$ShortToLong(short a) { return (long)a; }
- static long $opt$IntToLong(int a) { return (long)a; }
- static long $opt$CharToLong(int a) { return (long)a; }
+ static long $opt$ByteToLong(byte a) { if (doThrow) throw new Error(); return (long)a; }
+ static long $opt$ShortToLong(short a) { if (doThrow) throw new Error(); return (long)a; }
+ static long $opt$IntToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
+ static long $opt$CharToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
// These methods produce int-to-float Dex instructions.
- static float $opt$ByteToFloat(byte a) { return (float)a; }
- static float $opt$ShortToFloat(short a) { return (float)a; }
- static float $opt$IntToFloat(int a) { return (float)a; }
- static float $opt$CharToFloat(char a) { return (float)a; }
+ static float $opt$ByteToFloat(byte a) { if (doThrow) throw new Error(); return (float)a; }
+ static float $opt$ShortToFloat(short a) { if (doThrow) throw new Error(); return (float)a; }
+ static float $opt$IntToFloat(int a) { if (doThrow) throw new Error(); return (float)a; }
+ static float $opt$CharToFloat(char a) { if (doThrow) throw new Error(); return (float)a; }
// These methods produce int-to-double Dex instructions.
- static double $opt$ByteToDouble(byte a) { return (double)a; }
- static double $opt$ShortToDouble(short a) { return (double)a; }
- static double $opt$IntToDouble(int a) { return (double)a; }
- static double $opt$CharToDouble(int a) { return (double)a; }
+ static double $opt$ByteToDouble(byte a) { if (doThrow) throw new Error(); return (double)a; }
+ static double $opt$ShortToDouble(short a) { if (doThrow) throw new Error(); return (double)a; }
+ static double $opt$IntToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
+ static double $opt$CharToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
// These methods produce long-to-int Dex instructions.
- static int $opt$LongToInt(long a) { return (int)a; }
- static int $opt$LongLiteralToInt() { return (int)42L; }
+ static int $opt$LongToInt(long a) { if (doThrow) throw new Error(); return (int)a; }
+ static int $opt$LongLiteralToInt() { if (doThrow) throw new Error(); return (int)42L; }
// This method produces a long-to-float Dex instruction.
- static float $opt$LongToFloat(long a) { return (float)a; }
+ static float $opt$LongToFloat(long a) { if (doThrow) throw new Error(); return (float)a; }
// This method produces a long-to-double Dex instruction.
- static double $opt$LongToDouble(long a) { return (double)a; }
+ static double $opt$LongToDouble(long a) { if (doThrow) throw new Error(); return (double)a; }
// This method produces a float-to-int Dex instruction.
- static int $opt$FloatToInt(float a) { return (int)a; }
+ static int $opt$FloatToInt(float a) { if (doThrow) throw new Error(); return (int)a; }
// This method produces a float-to-long Dex instruction.
- static long $opt$FloatToLong(float a){ return (long)a; }
+ static long $opt$FloatToLong(float a){ if (doThrow) throw new Error(); return (long)a; }
// This method produces a float-to-double Dex instruction.
- static double $opt$FloatToDouble(float a) { return (double)a; }
+ static double $opt$FloatToDouble(float a) { if (doThrow) throw new Error(); return (double)a; }
// This method produces a double-to-int Dex instruction.
- static int $opt$DoubleToInt(double a){ return (int)a; }
+ static int $opt$DoubleToInt(double a){ if (doThrow) throw new Error(); return (int)a; }
// This method produces a double-to-long Dex instruction.
- static long $opt$DoubleToLong(double a){ return (long)a; }
+ static long $opt$DoubleToLong(double a){ if (doThrow) throw new Error(); return (long)a; }
// This method produces a double-to-float Dex instruction.
- static float $opt$DoubleToFloat(double a) { return (float)a; }
+ static float $opt$DoubleToFloat(double a) { if (doThrow) throw new Error(); return (float)a; }
// These methods produce int-to-byte Dex instructions.
- static byte $opt$ShortToByte(short a) { return (byte)a; }
- static byte $opt$IntToByte(int a) { return (byte)a; }
- static byte $opt$CharToByte(char a) { return (byte)a; }
+ static byte $opt$ShortToByte(short a) { if (doThrow) throw new Error(); return (byte)a; }
+ static byte $opt$IntToByte(int a) { if (doThrow) throw new Error(); return (byte)a; }
+ static byte $opt$CharToByte(char a) { if (doThrow) throw new Error(); return (byte)a; }
// These methods produce int-to-short Dex instructions.
- static short $opt$ByteToShort(byte a) { return (short)a; }
- static short $opt$IntToShort(int a) { return (short)a; }
- static short $opt$CharToShort(char a) { return (short)a; }
+ static short $opt$ByteToShort(byte a) { if (doThrow) throw new Error(); return (short)a; }
+ static short $opt$IntToShort(int a) { if (doThrow) throw new Error(); return (short)a; }
+ static short $opt$CharToShort(char a) { if (doThrow) throw new Error(); return (short)a; }
// These methods produce int-to-char Dex instructions.
- static char $opt$ByteToChar(byte a) { return (char)a; }
- static char $opt$ShortToChar(short a) { return (char)a; }
- static char $opt$IntToChar(int a) { return (char)a; }
+ static char $opt$ByteToChar(byte a) { if (doThrow) throw new Error(); return (char)a; }
+ static char $opt$ShortToChar(short a) { if (doThrow) throw new Error(); return (char)a; }
+ static char $opt$IntToChar(int a) { if (doThrow) throw new Error(); return (char)a; }
}
}
}
+ public static void assertFloatEquals(float expected, float result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertDoubleEquals(double expected, double result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
/**
* Tiny three-register program exercising int constant folding
* on negation.
return arg < Double.NaN;
}
+ // CHECK-START: int Main.ReturnInt33() constant_folding (before)
+ // CHECK-DAG: [[Const33:j\d+]] LongConstant 33
+ // CHECK-DAG: [[Convert:i\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: int Main.ReturnInt33() constant_folding (after)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static int ReturnInt33() {
+ long imm = 33L;
+ return (int) imm;
+ }
+
+ // CHECK-START: int Main.ReturnIntMax() constant_folding (before)
+ // CHECK-DAG: [[ConstMax:f\d+]] FloatConstant 1e+34
+ // CHECK-DAG: [[Convert:i\d+]] TypeConversion [[ConstMax]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: int Main.ReturnIntMax() constant_folding (after)
+ // CHECK-DAG: [[ConstMax:i\d+]] IntConstant 2147483647
+ // CHECK-DAG: Return [ [[ConstMax]] ]
+
+ public static int ReturnIntMax() {
+ float imm = 1.0e34f;
+ return (int) imm;
+ }
+
+ // CHECK-START: int Main.ReturnInt0() constant_folding (before)
+ // CHECK-DAG: [[ConstNaN:d\d+]] DoubleConstant nan
+ // CHECK-DAG: [[Convert:i\d+]] TypeConversion [[ConstNaN]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: int Main.ReturnInt0() constant_folding (after)
+ // CHECK-DAG: [[Const0:i\d+]] IntConstant 0
+ // CHECK-DAG: Return [ [[Const0]] ]
+
+ public static int ReturnInt0() {
+ double imm = Double.NaN;
+ return (int) imm;
+ }
+
+ // CHECK-START: long Main.ReturnLong33() constant_folding (before)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: [[Convert:j\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: long Main.ReturnLong33() constant_folding (after)
+ // CHECK-DAG: [[Const33:j\d+]] LongConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static long ReturnLong33() {
+ int imm = 33;
+ return (long) imm;
+ }
+
+ // CHECK-START: long Main.ReturnLong34() constant_folding (before)
+ // CHECK-DAG: [[Const34:f\d+]] FloatConstant 34
+ // CHECK-DAG: [[Convert:j\d+]] TypeConversion [[Const34]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: long Main.ReturnLong34() constant_folding (after)
+ // CHECK-DAG: [[Const34:j\d+]] LongConstant 34
+ // CHECK-DAG: Return [ [[Const34]] ]
+
+ public static long ReturnLong34() {
+ float imm = 34.0f;
+ return (long) imm;
+ }
+
+ // CHECK-START: long Main.ReturnLong0() constant_folding (before)
+ // CHECK-DAG: [[ConstNaN:d\d+]] DoubleConstant nan
+ // CHECK-DAG: [[Convert:j\d+]] TypeConversion [[ConstNaN]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: long Main.ReturnLong0() constant_folding (after)
+ // CHECK-DAG: [[Const0:j\d+]] LongConstant 0
+ // CHECK-DAG: Return [ [[Const0]] ]
+
+ public static long ReturnLong0() {
+ double imm = -Double.NaN;
+ return (long) imm;
+ }
+
+ // CHECK-START: float Main.ReturnFloat33() constant_folding (before)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: [[Convert:f\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: float Main.ReturnFloat33() constant_folding (after)
+ // CHECK-DAG: [[Const33:f\d+]] FloatConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static float ReturnFloat33() {
+ int imm = 33;
+ return (float) imm;
+ }
+
+ // CHECK-START: float Main.ReturnFloat34() constant_folding (before)
+ // CHECK-DAG: [[Const34:j\d+]] LongConstant 34
+ // CHECK-DAG: [[Convert:f\d+]] TypeConversion [[Const34]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: float Main.ReturnFloat34() constant_folding (after)
+ // CHECK-DAG: [[Const34:f\d+]] FloatConstant 34
+ // CHECK-DAG: Return [ [[Const34]] ]
+
+ public static float ReturnFloat34() {
+ long imm = 34L;
+ return (float) imm;
+ }
+
+ // CHECK-START: float Main.ReturnFloat99P25() constant_folding (before)
+ // CHECK-DAG: [[Const:d\d+]] DoubleConstant 99.25
+ // CHECK-DAG: [[Convert:f\d+]] TypeConversion [[Const]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: float Main.ReturnFloat99P25() constant_folding (after)
+ // CHECK-DAG: [[Const:f\d+]] FloatConstant 99.25
+ // CHECK-DAG: Return [ [[Const]] ]
+
+ public static float ReturnFloat99P25() {
+ double imm = 99.25;
+ return (float) imm;
+ }
+
+ // CHECK-START: double Main.ReturnDouble33() constant_folding (before)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: [[Convert:d\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: double Main.ReturnDouble33() constant_folding (after)
+ // CHECK-DAG: [[Const33:d\d+]] DoubleConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static double ReturnDouble33() {
+ int imm = 33;
+ return (double) imm;
+ }
+
+ // CHECK-START: double Main.ReturnDouble34() constant_folding (before)
+ // CHECK-DAG: [[Const34:j\d+]] LongConstant 34
+ // CHECK-DAG: [[Convert:d\d+]] TypeConversion [[Const34]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: double Main.ReturnDouble34() constant_folding (after)
+ // CHECK-DAG: [[Const34:d\d+]] DoubleConstant 34
+ // CHECK-DAG: Return [ [[Const34]] ]
+
+ public static double ReturnDouble34() {
+ long imm = 34L;
+ return (double) imm;
+ }
+
+ // CHECK-START: double Main.ReturnDouble99P25() constant_folding (before)
+ // CHECK-DAG: [[Const:f\d+]] FloatConstant 99.25
+ // CHECK-DAG: [[Convert:d\d+]] TypeConversion [[Const]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: double Main.ReturnDouble99P25() constant_folding (after)
+ // CHECK-DAG: [[Const:d\d+]] DoubleConstant 99.25
+ // CHECK-DAG: Return [ [[Const]] ]
+
+ public static double ReturnDouble99P25() {
+ float imm = 99.25f;
+ return (double) imm;
+ }
+
public static void main(String[] args) {
assertIntEquals(IntNegation(), -42);
assertIntEquals(IntAddition1(), 3);
assertIntEquals(XorSameInt(arbitrary), 0);
assertFalse(CmpFloatGreaterThanNaN(arbitrary));
assertFalse(CmpDoubleLessThanNaN(arbitrary));
+ assertIntEquals(ReturnInt33(), 33);
+ assertIntEquals(ReturnIntMax(), 2147483647);
+ assertIntEquals(ReturnInt0(), 0);
+ assertLongEquals(ReturnLong33(), 33);
+ assertLongEquals(ReturnLong34(), 34);
+ assertLongEquals(ReturnLong0(), 0);
+ assertFloatEquals(ReturnFloat33(), 33);
+ assertFloatEquals(ReturnFloat34(), 34);
+ assertFloatEquals(ReturnFloat99P25(), 99.25f);
+ assertDoubleEquals(ReturnDouble33(), 33);
+ assertDoubleEquals(ReturnDouble34(), 34);
+ assertDoubleEquals(ReturnDouble99P25(), 99.25);
}
}