Commit d521ed25 authored by titzer@chromium.org's avatar titzer@chromium.org

TF: Add ConvertFloat64ToUint32 and ConvertUint32ToFloat64 machine operators.

R=bmeurer@chromium.org
BUG=

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22752 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2fbf073f
......@@ -659,6 +659,13 @@ void InstructionSelector::VisitConvertInt32ToFloat64(Node* node) {
}
void InstructionSelector::VisitConvertUint32ToFloat64(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmVcvtF64U32, g.DefineAsDoubleRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmVcvtS32F64, g.DefineAsRegister(node),
......@@ -666,6 +673,13 @@ void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
}
void InstructionSelector::VisitConvertFloat64ToUint32(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmVcvtU32F64, g.DefineAsRegister(node),
g.UseDoubleRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat64Add(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
......
......@@ -378,9 +378,15 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Float64ToInt32:
__ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
break;
case kArm64Float64ToUint32:
__ Fcvtzu(i.OutputRegister32(), i.InputDoubleRegister(0));
break;
case kArm64Int32ToFloat64:
__ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
break;
case kArm64Uint32ToFloat64:
__ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
break;
case kArm64LoadWord8:
__ Ldrb(i.OutputRegister(), i.MemoryOperand());
break;
......
......@@ -63,7 +63,9 @@ namespace compiler {
V(Arm64Int32ToInt64) \
V(Arm64Int64ToInt32) \
V(Arm64Float64ToInt32) \
V(Arm64Float64ToUint32) \
V(Arm64Int32ToFloat64) \
V(Arm64Uint32ToFloat64) \
V(Arm64Float64Load) \
V(Arm64Float64Store) \
V(Arm64LoadWord8) \
......
......@@ -395,6 +395,13 @@ void InstructionSelector::VisitConvertInt32ToFloat64(Node* node) {
}
void InstructionSelector::VisitConvertUint32ToFloat64(Node* node) {
Arm64OperandGenerator g(this);
Emit(kArm64Uint32ToFloat64, g.DefineAsDoubleRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
Arm64OperandGenerator g(this);
Emit(kArm64Float64ToInt32, g.DefineAsRegister(node),
......@@ -402,6 +409,13 @@ void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
}
void InstructionSelector::VisitConvertFloat64ToUint32(Node* node) {
Arm64OperandGenerator g(this);
Emit(kArm64Float64ToUint32, g.DefineAsRegister(node),
g.UseDoubleRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat64Add(Node* node) {
VisitRRRFloat64(this, kArm64Float64Add, node);
}
......
......@@ -315,9 +315,22 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kSSEFloat64ToInt32:
__ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
break;
case kSSEFloat64ToUint32: {
XMMRegister scratch = xmm0;
__ Move(scratch, -2147483648.0);
// TODO(turbofan): IA32 SSE subsd() should take an operand.
__ addsd(scratch, i.InputDoubleRegister(0));
__ cvttsd2si(i.OutputRegister(), scratch);
__ add(i.OutputRegister(), Immediate(0x80000000));
break;
}
case kSSEInt32ToFloat64:
__ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
break;
case kSSEUint32ToFloat64:
// TODO(turbofan): IA32 SSE LoadUint32() should take an operand.
__ LoadUint32(i.OutputDoubleRegister(), i.InputRegister(0));
break;
case kSSELoad:
__ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
break;
......
......@@ -39,7 +39,9 @@ namespace compiler {
V(SSEFloat64Div) \
V(SSEFloat64Mod) \
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat64) \
V(SSEUint32ToFloat64) \
V(SSELoad) \
V(SSEStore) \
V(IA32LoadWord8) \
......
......@@ -326,12 +326,28 @@ void InstructionSelector::VisitConvertInt32ToFloat64(Node* node) {
}
void InstructionSelector::VisitConvertUint32ToFloat64(Node* node) {
IA32OperandGenerator g(this);
// TODO(turbofan): IA32 SSE LoadUint32() should take an operand.
Emit(kSSEUint32ToFloat64, g.DefineAsDoubleRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
IA32OperandGenerator g(this);
Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
}
void InstructionSelector::VisitConvertFloat64ToUint32(Node* node) {
IA32OperandGenerator g(this);
// TODO(turbofan): IA32 SSE subsd() should take an operand.
Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node),
g.UseDoubleRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat64Add(Node* node) {
IA32OperandGenerator g(this);
Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
......
......@@ -558,8 +558,12 @@ void InstructionSelector::VisitNode(Node* node) {
return VisitConvertInt64ToInt32(node);
case IrOpcode::kConvertInt32ToFloat64:
return MarkAsDouble(node), VisitConvertInt32ToFloat64(node);
case IrOpcode::kConvertUint32ToFloat64:
return MarkAsDouble(node), VisitConvertUint32ToFloat64(node);
case IrOpcode::kConvertFloat64ToInt32:
return VisitConvertFloat64ToInt32(node);
case IrOpcode::kConvertFloat64ToUint32:
return VisitConvertFloat64ToUint32(node);
case IrOpcode::kFloat64Add:
return MarkAsDouble(node), VisitFloat64Add(node);
case IrOpcode::kFloat64Sub:
......
......@@ -332,9 +332,15 @@ class MachineNodeFactory {
Node* ConvertInt32ToFloat64(Node* a) {
return NEW_NODE_1(MACHINE()->ConvertInt32ToFloat64(), a);
}
Node* ConvertUint32ToFloat64(Node* a) {
return NEW_NODE_1(MACHINE()->ConvertUint32ToFloat64(), a);
}
Node* ConvertFloat64ToInt32(Node* a) {
return NEW_NODE_1(MACHINE()->ConvertFloat64ToInt32(), a);
}
Node* ConvertFloat64ToUint32(Node* a) {
return NEW_NODE_1(MACHINE()->ConvertFloat64ToUint32(), a);
}
#ifdef MACHINE_ASSEMBLER_SUPPORTS_CALL_C
// Call to C.
......
......@@ -136,18 +136,25 @@ class MachineOperatorBuilder {
Operator* ConvertInt32ToInt64() { UNOP(ConvertInt32ToInt64); }
Operator* ConvertInt64ToInt32() { UNOP(ConvertInt64ToInt32); }
// 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.
// TODO(titzer): rename ConvertXXX to ChangeXXX in machine operators.
Operator* ConvertInt32ToFloat64() { UNOP(ConvertInt32ToFloat64); }
Operator* ConvertUint32ToFloat64() { UNOP(ConvertUint32ToFloat64); }
// TODO(titzer): add rounding mode to floating point conversion.
Operator* ConvertFloat64ToInt32() { UNOP(ConvertFloat64ToInt32); }
Operator* ConvertFloat64ToUint32() { UNOP(ConvertFloat64ToUint32); }
// TODO(titzer): do we need different rounding modes for float arithmetic?
// Floating point operators always operate with IEEE 754 round-to-nearest.
Operator* Float64Add() { BINOP_C(Float64Add); }
Operator* Float64Sub() { BINOP(Float64Sub); }
Operator* Float64Mul() { BINOP_C(Float64Mul); }
Operator* Float64Div() { BINOP(Float64Div); }
Operator* Float64Mod() { BINOP(Float64Mod); }
// Floating point comparisons complying to IEEE 754.
Operator* Float64Equal() { BINOP_C(Float64Equal); }
Operator* Float64LessThan() { BINOP(Float64LessThan); }
Operator* Float64LessThanOrEqual() { BINOP(Float64LessThanOrEqual); }
......
......@@ -493,6 +493,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
}
break;
}
case kSSEFloat64ToUint32: {
// TODO(turbofan): X64 SSE cvttsd2siq should support operands.
__ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
break;
}
case kSSEInt32ToFloat64: {
RegisterOrOperand input = i.InputRegisterOrOperand(0);
if (input.type == kRegister) {
......@@ -502,6 +507,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
}
break;
}
case kSSEUint32ToFloat64: {
// TODO(turbofan): X64 SSE cvtqsi2sd should support operands.
__ cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
break;
}
case kSSELoad:
__ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
break;
......
......@@ -57,7 +57,9 @@ namespace compiler {
V(X64Int32ToInt64) \
V(X64Int64ToInt32) \
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat64) \
V(SSEUint32ToFloat64) \
V(SSELoad) \
V(SSEStore) \
V(X64LoadWord8) \
......
......@@ -450,12 +450,28 @@ void InstructionSelector::VisitConvertInt32ToFloat64(Node* node) {
}
void InstructionSelector::VisitConvertUint32ToFloat64(Node* node) {
X64OperandGenerator g(this);
// TODO(turbofan): X64 SSE cvtqsi2sd should support operands.
Emit(kSSEUint32ToFloat64, g.DefineAsDoubleRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
}
void InstructionSelector::VisitConvertFloat64ToUint32(Node* node) {
X64OperandGenerator g(this);
// TODO(turbofan): X64 SSE cvttsd2siq should support operands.
Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node),
g.UseDoubleRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat64Add(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
......
......@@ -2888,7 +2888,21 @@ TEST(RunConvertInt32ToFloat64_B) {
}
// TODO(titzer): Test ConvertUint32ToFloat64
TEST(RunConvertUint32ToFloat64_B) {
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
double output = 0;
Node* convert = m.ConvertUint32ToFloat64(m.Parameter(0));
m.Store(kMachineFloat64, m.PointerConstant(&output), m.Int32Constant(0),
convert);
m.Return(m.Parameter(0));
FOR_UINT32_INPUTS(i) {
uint32_t expect = *i;
CHECK_EQ(expect, m.Call(expect));
CHECK_EQ(static_cast<double>(expect), output);
}
}
TEST(RunConvertFloat64ToInt32_A) {
......@@ -2921,49 +2935,73 @@ TEST(RunConvertFloat64ToInt32_B) {
{
FOR_INT32_INPUTS(i) {
input = *i;
int expect = *i;
int32_t expect = *i;
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
{
FOR_FLOAT64_INPUTS(i) {
input = *i;
// TODO(titzer): float64 -> int32 outside of the int32 range; the machine
// backends are all wrong in different ways, and they certainly don't
// implement the JavaScript conversions correctly.
if (std::isnan(input) || input > INT_MAX || input < INT_MIN) {
continue;
}
int32_t expect = static_cast<int32_t>(input);
// Check various powers of 2.
for (int32_t n = 1; n < 31; ++n) {
{
input = 1 << n;
int32_t expect = input;
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
{
input = 3 << n;
int32_t expect = input;
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Note we don't check fractional inputs, because these Convert operators
// really should be Change operators.
}
// TODO(titzer): test ConvertFloat64ToUint32
TEST(RunConvertFloat64ToInt32_truncation) {
TEST(RunConvertFloat64ToUint32_B) {
RawMachineAssemblerTester<int32_t> m;
int32_t magic = 0x786234;
double input = 3.9;
int32_t result = 0;
double input = 0;
int32_t output = 0;
Node* input_node =
Node* load =
m.Load(kMachineFloat64, m.PointerConstant(&input), m.Int32Constant(0));
m.Store(kMachineWord32, m.PointerConstant(&result), m.Int32Constant(0),
m.ConvertFloat64ToInt32(input_node));
m.Return(m.Int32Constant(magic));
Node* convert = m.ConvertFloat64ToUint32(load);
m.Store(kMachineWord32, m.PointerConstant(&output), m.Int32Constant(0),
convert);
m.Return(convert);
for (int i = -200; i < 200; i++) {
input = i + (i < 0 ? -0.9 : 0.9);
CHECK_EQ(magic, m.Call());
CHECK_EQ(i, result);
{
FOR_UINT32_INPUTS(i) {
input = *i;
// TODO(titzer): add a CheckEqualsHelper overload for uint32_t.
int32_t expect = static_cast<int32_t>(*i);
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Check various powers of 2.
for (int32_t n = 1; n < 31; ++n) {
{
input = 1u << n;
int32_t expect = static_cast<int32_t>(static_cast<uint32_t>(input));
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
{
input = 3u << n;
int32_t expect = static_cast<int32_t>(static_cast<uint32_t>(input));
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Note we don't check fractional inputs, because these Convert operators
// really should be Change operators.
}
......
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