Commit 6aa1dfca authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Add operators for float32 support.

This adds Float32Constant, ChangeFloat32ToFloat64 and
TruncateFloat64ToFloat32 operators.

TEST=compiler-unittests
BUG=v8:3589
LOG=n
R=titzer@chromium.org

Review URL: https://codereview.chromium.org/594493002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent bc609aff
......@@ -4,6 +4,8 @@
#include "src/compiler/common-operator.h"
#include <limits>
#include "src/compiler/operator-properties-inl.h"
#include "src/test/test-utils.h"
......@@ -132,9 +134,26 @@ class CommonOperatorTest : public TestWithZone {
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);
......
......@@ -137,6 +137,13 @@ const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) {
}
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,
......
......@@ -84,6 +84,7 @@ class CommonOperatorBuilder FINAL {
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);
......
......@@ -44,7 +44,12 @@ Node* GraphTest::Parameter(int32_t index) {
}
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));
}
......@@ -59,7 +64,7 @@ Node* GraphTest::Int64Constant(int64_t value) {
}
Node* GraphTest::NumberConstant(double value) {
Node* GraphTest::NumberConstant(volatile double value) {
return graph()->NewNode(common()->NumberConstant(value));
}
......@@ -664,6 +669,12 @@ Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher) {
}
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));
......
......@@ -31,10 +31,11 @@ class GraphTest : public TestWithContext, public TestWithZone {
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();
......@@ -65,6 +66,7 @@ Matcher<Node*> IsExternalConstant(
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);
......
......@@ -46,6 +46,29 @@ class MachineOperatorReducerTestWithParam
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,
......@@ -205,6 +228,20 @@ INSTANTIATE_TEST_CASE_P(MachineOperatorReducerTest,
::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
......@@ -314,6 +351,31 @@ TEST_F(MachineOperatorReducerTest, ChangeUint32ToUint64WithConstant) {
}
// -----------------------------------------------------------------------------
// 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
......
......@@ -21,6 +21,11 @@ MachineOperatorReducer::MachineOperatorReducer(JSGraph* jsgraph)
MachineOperatorReducer::~MachineOperatorReducer() {}
Node* MachineOperatorReducer::Float32Constant(volatile float value) {
return graph()->NewNode(common()->Float32Constant(value));
}
Node* MachineOperatorReducer::Float64Constant(volatile double value) {
return jsgraph()->Float64Constant(value);
}
......@@ -383,6 +388,11 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
}
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()));
......@@ -427,6 +437,12 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
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;
......
......@@ -27,11 +27,15 @@ class MachineOperatorReducer FINAL : public Reducer {
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));
}
......
......@@ -187,32 +187,33 @@ const PureOperator kPureOperators[] = {
&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
};
......
......@@ -97,12 +97,14 @@ struct StaticParameterTraits<LoadRepresentation> {
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) \
......
......@@ -104,23 +104,23 @@ class MachineOperatorBuilder FINAL {
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.
......
......@@ -90,6 +90,7 @@ struct FloatMatcher FINAL : public ValueMatcher<T, kOpcode> {
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;
......
......@@ -25,6 +25,7 @@
#define LEAF_OP_LIST(V) \
V(Int32Constant) \
V(Int64Constant) \
V(Float32Constant) \
V(Float64Constant) \
V(ExternalConstant) \
V(NumberConstant) \
......@@ -161,62 +162,64 @@
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) \
......
......@@ -255,6 +255,12 @@ Bounds Typer::Visitor::TypeInt64Constant(Node* node) {
}
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()));
......
......@@ -67,6 +67,14 @@ inline unsigned int FastD2UI(double x) {
}
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;
......
......@@ -77,6 +77,10 @@ inline double FastUI2D(unsigned 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);
......
......@@ -7971,7 +7971,7 @@ RUNTIME_FUNCTION(Runtime_MathFround) {
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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment