#include "src/compiler/common-operator.h"
+#include <limits>
+
#include "src/compiler/operator-properties-inl.h"
#include "src/test/test-utils.h"
const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
+const float kFloat32Values[] = {
+ std::numeric_limits<float>::min(), -1.0f, -0.0f, 0.0f, 1.0f,
+ std::numeric_limits<float>::max()};
+
} // namespace
+TEST_F(CommonOperatorTest, Float32Constant) {
+ TRACED_FOREACH(float, value, kFloat32Values) {
+ const Operator* op = common()->Float32Constant(value);
+ EXPECT_FLOAT_EQ(value, OpParameter<float>(op));
+ EXPECT_EQ(0, OperatorProperties::GetValueInputCount(op));
+ EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+ EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+ EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
+ EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
+ }
+}
+
+
TEST_F(CommonOperatorTest, ValueEffect) {
TRACED_FOREACH(int, arguments, kArguments) {
const Operator* op = common()->ValueEffect(arguments);
}
+const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) {
+ return new (zone())
+ Operator1<float>(IrOpcode::kFloat32Constant, Operator::kPure, 0, 1,
+ "Float32Constant", value);
+}
+
+
const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) {
return new (zone())
Operator1<double>(IrOpcode::kFloat64Constant, Operator::kPure, 0, 1,
const Operator* Int32Constant(int32_t);
const Operator* Int64Constant(int64_t);
+ const Operator* Float32Constant(volatile float);
const Operator* Float64Constant(volatile double);
const Operator* ExternalConstant(const ExternalReference&);
const Operator* NumberConstant(volatile double);
}
-Node* GraphTest::Float64Constant(double value) {
+Node* GraphTest::Float32Constant(volatile float value) {
+ return graph()->NewNode(common()->Float32Constant(value));
+}
+
+
+Node* GraphTest::Float64Constant(volatile double value) {
return graph()->NewNode(common()->Float64Constant(value));
}
}
-Node* GraphTest::NumberConstant(double value) {
+Node* GraphTest::NumberConstant(volatile double value) {
return graph()->NewNode(common()->NumberConstant(value));
}
}
+Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher) {
+ return MakeMatcher(
+ new IsConstantMatcher<float>(IrOpcode::kFloat32Constant, value_matcher));
+}
+
+
Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher) {
return MakeMatcher(
new IsConstantMatcher<double>(IrOpcode::kFloat64Constant, value_matcher));
protected:
Node* Parameter(int32_t index);
- Node* Float64Constant(double value);
+ Node* Float32Constant(volatile float value);
+ Node* Float64Constant(volatile double value);
Node* Int32Constant(int32_t value);
Node* Int64Constant(int64_t value);
- Node* NumberConstant(double value);
+ Node* NumberConstant(volatile double value);
Node* HeapConstant(const Unique<HeapObject>& value);
Node* FalseConstant();
Node* TrueConstant();
const Matcher<ExternalReference>& value_matcher);
Matcher<Node*> IsHeapConstant(
const Matcher<Unique<HeapObject> >& value_matcher);
+Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher);
Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher);
Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher);
namespace {
+static const float kFloat32Values[] = {
+ -V8_INFINITY, -2.70497e+38f, -1.4698e+37f, -1.22813e+35f, -1.20555e+35f,
+ -1.34584e+34f, -1.0079e+32f, -6.49364e+26f, -3.06077e+25f, -1.46821e+25f,
+ -1.17658e+23f, -1.9617e+22f, -2.7357e+20f, -1.48708e+13f, -1.89633e+12f,
+ -4.66622e+11f, -2.22581e+11f, -1.45381e+10f, -1.3956e+09f, -1.32951e+09f,
+ -1.30721e+09f, -1.19756e+09f, -9.26822e+08f, -6.35647e+08f, -4.00037e+08f,
+ -1.81227e+08f, -5.09256e+07f, -964300.0f, -192446.0f, -28455.0f,
+ -27194.0f, -26401.0f, -20575.0f, -17069.0f, -9167.0f,
+ -960.178f, -113.0f, -62.0f, -15.0f, -7.0f,
+ -0.0256635f, -4.60374e-07f, -3.63759e-10f, -4.30175e-14f, -5.27385e-15f,
+ -1.48084e-15f, -1.05755e-19f, -3.2995e-21f, -1.67354e-23f, -1.11885e-23f,
+ -1.78506e-30f, -5.07594e-31f, -3.65799e-31f, -1.43718e-34f, -1.27126e-38f,
+ -0.0f, 0.0f, 1.17549e-38f, 1.56657e-37f, 4.08512e-29f,
+ 3.31357e-28f, 6.25073e-22f, 4.1723e-13f, 1.44343e-09f, 5.27004e-08f,
+ 9.48298e-08f, 5.57888e-07f, 4.89988e-05f, 0.244326f, 12.4895f,
+ 19.0f, 47.0f, 106.0f, 538.324f, 564.536f,
+ 819.124f, 7048.0f, 12611.0f, 19878.0f, 20309.0f,
+ 797056.0f, 1.77219e+09f, 1.51116e+11f, 4.18193e+13f, 3.59167e+16f,
+ 3.38211e+19f, 2.67488e+20f, 1.78831e+21f, 9.20914e+21f, 8.35654e+23f,
+ 1.4495e+24f, 5.94015e+25f, 4.43608e+30f, 2.44502e+33f, 2.61152e+33f,
+ 1.38178e+37f, 1.71306e+37f, 3.31899e+38f, 3.40282e+38f, V8_INFINITY};
+
+
static const double kFloat64Values[] = {
-V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
-2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
::testing::ValuesIn(kUnaryOperators));
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToFloat32
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToFloat32WithConstant) {
+ TRACED_FOREACH(float, x, kFloat32Values) {
+ Reduction reduction = Reduce(graph()->NewNode(
+ machine()->ChangeFloat32ToFloat64(), Float32Constant(x)));
+ ASSERT_TRUE(reduction.Changed());
+ EXPECT_THAT(reduction.replacement(), IsFloat64Constant(x));
+ }
+}
+
+
// -----------------------------------------------------------------------------
// ChangeFloat64ToInt32
}
+// -----------------------------------------------------------------------------
+// TruncateFloat64ToFloat32
+
+
+TEST_F(MachineOperatorReducerTest,
+ TruncateFloat64ToFloat32WithChangeFloat32ToFloat64) {
+ Node* value = Parameter(0);
+ Reduction reduction = Reduce(graph()->NewNode(
+ machine()->TruncateFloat64ToFloat32(),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), value)));
+ ASSERT_TRUE(reduction.Changed());
+ EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) {
+ TRACED_FOREACH(double, x, kFloat64Values) {
+ Reduction reduction = Reduce(graph()->NewNode(
+ machine()->TruncateFloat64ToFloat32(), Float64Constant(x)));
+ ASSERT_TRUE(reduction.Changed());
+ EXPECT_THAT(reduction.replacement(), IsFloat32Constant(DoubleToFloat32(x)));
+ }
+}
+
+
// -----------------------------------------------------------------------------
// TruncateFloat64ToInt32
MachineOperatorReducer::~MachineOperatorReducer() {}
+Node* MachineOperatorReducer::Float32Constant(volatile float value) {
+ return graph()->NewNode(common()->Float32Constant(value));
+}
+
+
Node* MachineOperatorReducer::Float64Constant(volatile double value) {
return jsgraph()->Float64Constant(value);
}
}
break;
}
+ case IrOpcode::kChangeFloat32ToFloat64: {
+ Float32Matcher m(node->InputAt(0));
+ if (m.HasValue()) return ReplaceFloat64(m.Value());
+ break;
+ }
case IrOpcode::kChangeFloat64ToInt32: {
Float64Matcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceInt32(FastD2I(m.Value()));
if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
break;
}
+ case IrOpcode::kTruncateFloat64ToFloat32: {
+ Float64Matcher m(node->InputAt(0));
+ if (m.HasValue()) return ReplaceFloat32(DoubleToFloat32(m.Value()));
+ if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
+ break;
+ }
// TODO(turbofan): strength-reduce and fold floating point operations.
default:
break;
virtual Reduction Reduce(Node* node) OVERRIDE;
private:
+ Node* Float32Constant(volatile float value);
Node* Float64Constant(volatile double value);
Node* Int32Constant(int32_t value);
Node* Int64Constant(int64_t value);
Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); }
+ Reduction ReplaceFloat32(volatile float value) {
+ return Replace(Float32Constant(value));
+ }
Reduction ReplaceFloat64(volatile double value) {
return Replace(Float64Constant(value));
}
&MachineOperatorBuilder::Name, IrOpcode::k##Name, input_count, \
output_count \
}
- PURE(Word32And, 2, 1), PURE(Word32Or, 2, 1),
- PURE(Word32Xor, 2, 1), PURE(Word32Shl, 2, 1),
- PURE(Word32Shr, 2, 1), PURE(Word32Sar, 2, 1),
- PURE(Word32Ror, 2, 1), PURE(Word32Equal, 2, 1),
- PURE(Word64And, 2, 1), PURE(Word64Or, 2, 1),
- PURE(Word64Xor, 2, 1), PURE(Word64Shl, 2, 1),
- PURE(Word64Shr, 2, 1), PURE(Word64Sar, 2, 1),
- PURE(Word64Ror, 2, 1), PURE(Word64Equal, 2, 1),
- PURE(Int32Add, 2, 1), PURE(Int32AddWithOverflow, 2, 2),
- PURE(Int32Sub, 2, 1), PURE(Int32SubWithOverflow, 2, 2),
- PURE(Int32Mul, 2, 1), PURE(Int32Div, 2, 1),
- PURE(Int32UDiv, 2, 1), PURE(Int32Mod, 2, 1),
- PURE(Int32UMod, 2, 1), PURE(Int32LessThan, 2, 1),
- PURE(Int32LessThanOrEqual, 2, 1), PURE(Uint32LessThan, 2, 1),
- PURE(Uint32LessThanOrEqual, 2, 1), PURE(Int64Add, 2, 1),
- PURE(Int64Sub, 2, 1), PURE(Int64Mul, 2, 1),
- PURE(Int64Div, 2, 1), PURE(Int64UDiv, 2, 1),
- PURE(Int64Mod, 2, 1), PURE(Int64UMod, 2, 1),
- PURE(Int64LessThan, 2, 1), PURE(Int64LessThanOrEqual, 2, 1),
- PURE(ChangeFloat64ToInt32, 1, 1), PURE(ChangeFloat64ToUint32, 1, 1),
- PURE(ChangeInt32ToInt64, 1, 1), PURE(ChangeUint32ToFloat64, 1, 1),
- PURE(ChangeUint32ToUint64, 1, 1), PURE(TruncateFloat64ToInt32, 1, 1),
- PURE(TruncateInt64ToInt32, 1, 1), PURE(Float64Add, 2, 1),
- PURE(Float64Sub, 2, 1), PURE(Float64Mul, 2, 1),
- PURE(Float64Div, 2, 1), PURE(Float64Mod, 2, 1),
- PURE(Float64Equal, 2, 1), PURE(Float64LessThan, 2, 1),
+ PURE(Word32And, 2, 1), PURE(Word32Or, 2, 1),
+ PURE(Word32Xor, 2, 1), PURE(Word32Shl, 2, 1),
+ PURE(Word32Shr, 2, 1), PURE(Word32Sar, 2, 1),
+ PURE(Word32Ror, 2, 1), PURE(Word32Equal, 2, 1),
+ PURE(Word64And, 2, 1), PURE(Word64Or, 2, 1),
+ PURE(Word64Xor, 2, 1), PURE(Word64Shl, 2, 1),
+ PURE(Word64Shr, 2, 1), PURE(Word64Sar, 2, 1),
+ PURE(Word64Ror, 2, 1), PURE(Word64Equal, 2, 1),
+ PURE(Int32Add, 2, 1), PURE(Int32AddWithOverflow, 2, 2),
+ PURE(Int32Sub, 2, 1), PURE(Int32SubWithOverflow, 2, 2),
+ PURE(Int32Mul, 2, 1), PURE(Int32Div, 2, 1),
+ PURE(Int32UDiv, 2, 1), PURE(Int32Mod, 2, 1),
+ PURE(Int32UMod, 2, 1), PURE(Int32LessThan, 2, 1),
+ PURE(Int32LessThanOrEqual, 2, 1), PURE(Uint32LessThan, 2, 1),
+ PURE(Uint32LessThanOrEqual, 2, 1), PURE(Int64Add, 2, 1),
+ PURE(Int64Sub, 2, 1), PURE(Int64Mul, 2, 1),
+ PURE(Int64Div, 2, 1), PURE(Int64UDiv, 2, 1),
+ PURE(Int64Mod, 2, 1), PURE(Int64UMod, 2, 1),
+ PURE(Int64LessThan, 2, 1), PURE(Int64LessThanOrEqual, 2, 1),
+ PURE(ChangeFloat32ToFloat64, 1, 1), PURE(ChangeFloat64ToInt32, 1, 1),
+ PURE(ChangeFloat64ToUint32, 1, 1), PURE(ChangeInt32ToInt64, 1, 1),
+ PURE(ChangeUint32ToFloat64, 1, 1), PURE(ChangeUint32ToUint64, 1, 1),
+ PURE(TruncateFloat64ToFloat32, 1, 1), PURE(TruncateFloat64ToInt32, 1, 1),
+ PURE(TruncateInt64ToInt32, 1, 1), PURE(Float64Add, 2, 1),
+ PURE(Float64Sub, 2, 1), PURE(Float64Mul, 2, 1),
+ PURE(Float64Div, 2, 1), PURE(Float64Mod, 2, 1),
+ PURE(Float64Equal, 2, 1), PURE(Float64LessThan, 2, 1),
PURE(Float64LessThanOrEqual, 2, 1)
#undef PURE
};
V(Int64UMod, Operator::kNoProperties, 2, 1) \
V(Int64LessThan, Operator::kNoProperties, 2, 1) \
V(Int64LessThanOrEqual, Operator::kNoProperties, 2, 1) \
+ V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 1) \
V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 1) \
V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 1) \
V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 1) \
V(ChangeInt32ToInt64, Operator::kNoProperties, 1, 1) \
V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 1) \
V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 1) \
+ V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 1) \
V(TruncateFloat64ToInt32, Operator::kNoProperties, 1, 1) \
V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 1) \
V(Float64Add, Operator::kCommutative, 2, 1) \
const Operator* Int64LessThan();
const Operator* Int64LessThanOrEqual();
- // Convert representation of integers between float64 and int32/uint32.
- // The precise rounding mode and handling of out of range inputs are *not*
- // defined for these operators, since they are intended only for use with
- // integers.
+ // These operators change the representation of numbers while preserving the
+ // value of the number. Narrowing operators assume the input is representable
+ // in the target type and are *not* defined for other inputs.
+ // Use narrowing change operators only when there is a static guarantee that
+ // the input value is representable in the target value.
+ const Operator* ChangeFloat32ToFloat64();
+ const Operator* ChangeFloat64ToInt32(); // narrowing
+ const Operator* ChangeFloat64ToUint32(); // narrowing
const Operator* ChangeInt32ToFloat64();
- const Operator* ChangeUint32ToFloat64();
- const Operator* ChangeFloat64ToInt32();
- const Operator* ChangeFloat64ToUint32();
-
- // Sign/zero extend int32/uint32 to int64/uint64.
const Operator* ChangeInt32ToInt64();
+ const Operator* ChangeUint32ToFloat64();
const Operator* ChangeUint32ToUint64();
- // Truncate double to int32 using JavaScript semantics.
- const Operator* TruncateFloat64ToInt32();
-
- // Truncate the high order bits and convert the remaining bits to int32.
+ // These operators truncate numbers, both changing the representation of
+ // the number and mapping multiple input values onto the same output value.
+ const Operator* TruncateFloat64ToFloat32();
+ const Operator* TruncateFloat64ToInt32(); // JavaScript semantics.
const Operator* TruncateInt64ToInt32();
// Floating point operators always operate with IEEE 754 round-to-nearest.
bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
};
+typedef FloatMatcher<float, IrOpcode::kFloat32Constant> Float32Matcher;
typedef FloatMatcher<double, IrOpcode::kFloat64Constant> Float64Matcher;
typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;
#define LEAF_OP_LIST(V) \
V(Int32Constant) \
V(Int64Constant) \
+ V(Float32Constant) \
V(Float64Constant) \
V(ExternalConstant) \
V(NumberConstant) \
V(StoreElement)
// Opcodes for Machine-level operators.
-#define MACHINE_OP_LIST(V) \
- V(Load) \
- V(Store) \
- V(Word32And) \
- V(Word32Or) \
- V(Word32Xor) \
- V(Word32Shl) \
- V(Word32Shr) \
- V(Word32Sar) \
- V(Word32Ror) \
- V(Word32Equal) \
- V(Word64And) \
- V(Word64Or) \
- V(Word64Xor) \
- V(Word64Shl) \
- V(Word64Shr) \
- V(Word64Sar) \
- V(Word64Ror) \
- V(Word64Equal) \
- V(Int32Add) \
- V(Int32AddWithOverflow) \
- V(Int32Sub) \
- V(Int32SubWithOverflow) \
- V(Int32Mul) \
- V(Int32Div) \
- V(Int32UDiv) \
- V(Int32Mod) \
- V(Int32UMod) \
- V(Int32LessThan) \
- V(Int32LessThanOrEqual) \
- V(Uint32LessThan) \
- V(Uint32LessThanOrEqual) \
- V(Int64Add) \
- V(Int64Sub) \
- V(Int64Mul) \
- V(Int64Div) \
- V(Int64UDiv) \
- V(Int64Mod) \
- V(Int64UMod) \
- V(Int64LessThan) \
- V(Int64LessThanOrEqual) \
- V(ChangeInt32ToFloat64) \
- V(ChangeUint32ToFloat64) \
- V(ChangeFloat64ToInt32) \
- V(ChangeFloat64ToUint32) \
- V(ChangeInt32ToInt64) \
- V(ChangeUint32ToUint64) \
- V(TruncateFloat64ToInt32) \
- V(TruncateInt64ToInt32) \
- V(Float64Add) \
- V(Float64Sub) \
- V(Float64Mul) \
- V(Float64Div) \
- V(Float64Mod) \
- V(Float64Equal) \
- V(Float64LessThan) \
+#define MACHINE_OP_LIST(V) \
+ V(Load) \
+ V(Store) \
+ V(Word32And) \
+ V(Word32Or) \
+ V(Word32Xor) \
+ V(Word32Shl) \
+ V(Word32Shr) \
+ V(Word32Sar) \
+ V(Word32Ror) \
+ V(Word32Equal) \
+ V(Word64And) \
+ V(Word64Or) \
+ V(Word64Xor) \
+ V(Word64Shl) \
+ V(Word64Shr) \
+ V(Word64Sar) \
+ V(Word64Ror) \
+ V(Word64Equal) \
+ V(Int32Add) \
+ V(Int32AddWithOverflow) \
+ V(Int32Sub) \
+ V(Int32SubWithOverflow) \
+ V(Int32Mul) \
+ V(Int32Div) \
+ V(Int32UDiv) \
+ V(Int32Mod) \
+ V(Int32UMod) \
+ V(Int32LessThan) \
+ V(Int32LessThanOrEqual) \
+ V(Uint32LessThan) \
+ V(Uint32LessThanOrEqual) \
+ V(Int64Add) \
+ V(Int64Sub) \
+ V(Int64Mul) \
+ V(Int64Div) \
+ V(Int64UDiv) \
+ V(Int64Mod) \
+ V(Int64UMod) \
+ V(Int64LessThan) \
+ V(Int64LessThanOrEqual) \
+ V(ChangeFloat32ToFloat64) \
+ V(ChangeFloat64ToInt32) \
+ V(ChangeFloat64ToUint32) \
+ V(ChangeInt32ToFloat64) \
+ V(ChangeInt32ToInt64) \
+ V(ChangeUint32ToFloat64) \
+ V(ChangeUint32ToUint64) \
+ V(TruncateFloat64ToFloat32) \
+ V(TruncateFloat64ToInt32) \
+ V(TruncateInt64ToInt32) \
+ V(Float64Add) \
+ V(Float64Sub) \
+ V(Float64Mul) \
+ V(Float64Div) \
+ V(Float64Mod) \
+ V(Float64Equal) \
+ V(Float64LessThan) \
V(Float64LessThanOrEqual)
#define VALUE_OP_LIST(V) \
}
+Bounds Typer::Visitor::TypeFloat32Constant(Node* node) {
+ // TODO(titzer): only call Type::Of() if the type is not already known.
+ return Bounds(Type::Of(OpParameter<float>(node), zone()));
+}
+
+
Bounds Typer::Visitor::TypeFloat64Constant(Node* node) {
// TODO(titzer): only call Type::Of() if the type is not already known.
return Bounds(Type::Of(OpParameter<double>(node), zone()));
}
+inline float DoubleToFloat32(double x) {
+ // TODO(yanggou): This static_cast is implementation-defined behaviour in C++,
+ // so we may need to do the conversion manually instead to match the spec.
+ volatile float f = static_cast<float>(x);
+ return f;
+}
+
+
inline double DoubleToInteger(double x) {
if (std::isnan(x)) return 0;
if (!std::isfinite(x) || x == 0) return x;
}
+// This function should match the exact semantics of ECMA-262 20.2.2.17.
+inline float DoubleToFloat32(double x);
+
+
// This function should match the exact semantics of ECMA-262 9.4.
inline double DoubleToInteger(double x);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
- float xf = static_cast<float>(x);
+ float xf = DoubleToFloat32(x);
return *isolate->factory()->NewNumber(xf);
}