Commit 95844d94 authored by ahaas's avatar ahaas Committed by Commit bot

[turbofan] Changed TruncateFloat64ToInt64 to TryTruncateFloat64ToInt64.

The new operator provides a second output which indicates whether the
conversion from float64 to int64 was successful or not. The second
output returns 0 if the conversion fails. If the conversion succeeds,
then the second output is differs from 0.

The second output can be ignored, which means that the operator can be
used the same way as the original operator.

I implemented the new operator on x64 and arm64. @v8-mips-ports and
@v8-ppc-ports, can you please take care of the mips64 and ppc64
implementation of the second output?

R=titzer@chromium.org, v8-arm-ports@googlegroups.com

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

Cr-Commit-Position: refs/heads/master@{#32653}
parent 1c44aa0e
...@@ -33,6 +33,8 @@ class Arm64OperandConverter final : public InstructionOperandConverter { ...@@ -33,6 +33,8 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
return InputDoubleRegister(index); return InputDoubleRegister(index);
} }
size_t OutputCount() { return instr_->OutputCount(); }
DoubleRegister OutputFloat32Register() { return OutputDoubleRegister().S(); } DoubleRegister OutputFloat32Register() { return OutputDoubleRegister().S(); }
DoubleRegister OutputFloat64Register() { return OutputDoubleRegister(); } DoubleRegister OutputFloat64Register() { return OutputDoubleRegister(); }
...@@ -1037,7 +1039,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1037,7 +1039,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Fcvtzs(i.OutputRegister64(), i.InputFloat32Register(0)); __ Fcvtzs(i.OutputRegister64(), i.InputFloat32Register(0));
break; break;
case kArm64Float64ToInt64: case kArm64Float64ToInt64:
__ Fcvtzs(i.OutputRegister64(), i.InputDoubleRegister(0)); __ Fcvtzs(i.OutputRegister(0), i.InputDoubleRegister(0));
if (i.OutputCount() > 1) {
__ Cmp(i.OutputRegister(0), 1);
__ Ccmp(i.OutputRegister(0), -1, VFlag, vc);
__ Fccmp(i.InputDoubleRegister(0), i.InputDoubleRegister(0), VFlag, vc);
__ Cset(i.OutputRegister(1), vc);
}
break; break;
case kArm64Float32ToUint64: case kArm64Float32ToUint64:
__ Fcvtzu(i.OutputRegister64(), i.InputFloat32Register(0)); __ Fcvtzu(i.OutputRegister64(), i.InputFloat32Register(0));
......
...@@ -1242,8 +1242,20 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { ...@@ -1242,8 +1242,20 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
VisitRR(this, kArm64Float64ToInt64, node); Arm64OperandGenerator g(this);
InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
InstructionOperand outputs[2];
size_t output_count = 0;
outputs[output_count++] = g.DefineAsRegister(node);
Node* success_output = NodeProperties::FindProjection(node, 1);
if (success_output) {
outputs[output_count++] = g.DefineAsRegister(success_output);
}
Emit(kArm64Float64ToInt64, output_count, outputs, 1, inputs);
} }
......
...@@ -828,8 +828,8 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -828,8 +828,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node); return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
case IrOpcode::kTruncateFloat32ToInt64: case IrOpcode::kTruncateFloat32ToInt64:
return MarkAsWord64(node), VisitTruncateFloat32ToInt64(node); return MarkAsWord64(node), VisitTruncateFloat32ToInt64(node);
case IrOpcode::kTruncateFloat64ToInt64: case IrOpcode::kTryTruncateFloat64ToInt64:
return MarkAsWord64(node), VisitTruncateFloat64ToInt64(node); return MarkAsWord64(node), VisitTryTruncateFloat64ToInt64(node);
case IrOpcode::kTruncateFloat32ToUint64: case IrOpcode::kTruncateFloat32ToUint64:
return MarkAsWord64(node), VisitTruncateFloat32ToUint64(node); return MarkAsWord64(node), VisitTruncateFloat32ToUint64(node);
case IrOpcode::kTruncateFloat64ToUint64: case IrOpcode::kTruncateFloat64ToUint64:
...@@ -1087,7 +1087,7 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { ...@@ -1087,7 +1087,7 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -1208,6 +1208,7 @@ void InstructionSelector::VisitProjection(Node* node) { ...@@ -1208,6 +1208,7 @@ void InstructionSelector::VisitProjection(Node* node) {
switch (value->opcode()) { switch (value->opcode()) {
case IrOpcode::kInt32AddWithOverflow: case IrOpcode::kInt32AddWithOverflow:
case IrOpcode::kInt32SubWithOverflow: case IrOpcode::kInt32SubWithOverflow:
case IrOpcode::kTryTruncateFloat64ToInt64:
if (ProjectionIndexOf(node->op()) == 0u) { if (ProjectionIndexOf(node->op()) == 0u) {
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value)); Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
} else { } else {
......
...@@ -136,7 +136,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { ...@@ -136,7 +136,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \ V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \
V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1) \ V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 1) \ V(TruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 1) \ V(TryTruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 2) \
V(TruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 1) \ V(TruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 1) \ V(TruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 1) \
V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 0, 1) \ V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
......
...@@ -208,7 +208,7 @@ class MachineOperatorBuilder final : public ZoneObject { ...@@ -208,7 +208,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* ChangeFloat64ToInt32(); // narrowing const Operator* ChangeFloat64ToInt32(); // narrowing
const Operator* ChangeFloat64ToUint32(); // narrowing const Operator* ChangeFloat64ToUint32(); // narrowing
const Operator* TruncateFloat32ToInt64(); const Operator* TruncateFloat32ToInt64();
const Operator* TruncateFloat64ToInt64(); const Operator* TryTruncateFloat64ToInt64();
const Operator* TruncateFloat32ToUint64(); const Operator* TruncateFloat32ToUint64();
const Operator* TruncateFloat64ToUint64(); const Operator* TruncateFloat64ToUint64();
const Operator* ChangeInt32ToFloat64(); const Operator* ChangeInt32ToFloat64();
......
...@@ -828,7 +828,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { ...@@ -828,7 +828,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
if (NodeProperties::FindProjection(node, 1)) {
// TODO(mips): implement the second return value.
UNIMPLEMENTED();
}
VisitRR(this, kMips64TruncLD, node); VisitRR(this, kMips64TruncLD, node);
} }
......
...@@ -267,7 +267,7 @@ ...@@ -267,7 +267,7 @@
V(ChangeFloat64ToInt32) \ V(ChangeFloat64ToInt32) \
V(ChangeFloat64ToUint32) \ V(ChangeFloat64ToUint32) \
V(TruncateFloat32ToInt64) \ V(TruncateFloat32ToInt64) \
V(TruncateFloat64ToInt64) \ V(TryTruncateFloat64ToInt64) \
V(TruncateFloat32ToUint64) \ V(TruncateFloat32ToUint64) \
V(TruncateFloat64ToUint64) \ V(TruncateFloat64ToUint64) \
V(ChangeInt32ToFloat64) \ V(ChangeInt32ToFloat64) \
......
...@@ -932,7 +932,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { ...@@ -932,7 +932,11 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
if (NodeProperties::FindProjection(node, 1)) {
// TODO(ppc): implement the second return value.
UNIMPLEMENTED();
}
VisitRR(this, kPPC_DoubleToInt64, node); VisitRR(this, kPPC_DoubleToInt64, node);
} }
......
...@@ -431,7 +431,12 @@ class RawMachineAssembler { ...@@ -431,7 +431,12 @@ class RawMachineAssembler {
return AddNode(machine()->TruncateFloat32ToInt64(), a); return AddNode(machine()->TruncateFloat32ToInt64(), a);
} }
Node* TruncateFloat64ToInt64(Node* a) { Node* TruncateFloat64ToInt64(Node* a) {
return AddNode(machine()->TruncateFloat64ToInt64(), a); // TODO(ahaas): Remove this function as soon as it is not used anymore in
// WebAssembly.
return AddNode(machine()->TryTruncateFloat64ToInt64(), a);
}
Node* TryTruncateFloat64ToInt64(Node* a) {
return AddNode(machine()->TryTruncateFloat64ToInt64(), a);
} }
Node* TruncateFloat32ToUint64(Node* a) { Node* TruncateFloat32ToUint64(Node* a) {
return AddNode(machine()->TruncateFloat32ToUint64(), a); return AddNode(machine()->TruncateFloat32ToUint64(), a);
......
...@@ -2126,7 +2126,7 @@ Type* Typer::Visitor::TypeTruncateFloat32ToInt64(Node* node) { ...@@ -2126,7 +2126,7 @@ Type* Typer::Visitor::TypeTruncateFloat32ToInt64(Node* node) {
} }
Type* Typer::Visitor::TypeTruncateFloat64ToInt64(Node* node) { Type* Typer::Visitor::TypeTryTruncateFloat64ToInt64(Node* node) {
return Type::Internal(); return Type::Internal();
} }
......
...@@ -918,7 +918,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -918,7 +918,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kChangeFloat64ToInt32: case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32: case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kTruncateFloat32ToInt64: case IrOpcode::kTruncateFloat32ToInt64:
case IrOpcode::kTruncateFloat64ToInt64: case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTruncateFloat32ToUint64: case IrOpcode::kTruncateFloat32ToUint64:
case IrOpcode::kTruncateFloat64ToUint64: case IrOpcode::kTruncateFloat64ToUint64:
case IrOpcode::kFloat64ExtractLowWord32: case IrOpcode::kFloat64ExtractLowWord32:
......
...@@ -1052,9 +1052,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1052,9 +1052,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break; break;
case kSSEFloat64ToInt64: case kSSEFloat64ToInt64:
if (instr->InputAt(0)->IsDoubleRegister()) { if (instr->InputAt(0)->IsDoubleRegister()) {
__ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0)); __ Cvttsd2siq(i.OutputRegister(0), i.InputDoubleRegister(0));
} else { } else {
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0)); __ Cvttsd2siq(i.OutputRegister(0), i.InputOperand(0));
}
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 0x8000000000000000);
__ subq(i.OutputRegister(1), i.OutputRegister(0));
} }
break; break;
case kSSEFloat32ToUint64: { case kSSEFloat32ToUint64: {
...@@ -1087,8 +1091,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1087,8 +1091,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
// The input value is within uint64 range and the second conversion worked // The input value is within uint64 range and the second conversion worked
// successfully, but we still have to undo the subtraction we did // successfully, but we still have to undo the subtraction we did
// earlier. // earlier.
__ movq(kScratchRegister, Immediate(1)); __ Set(kScratchRegister, 0x8000000000000000);
__ shlq(kScratchRegister, Immediate(63));
__ orq(i.OutputRegister(), kScratchRegister); __ orq(i.OutputRegister(), kScratchRegister);
__ bind(&done); __ bind(&done);
break; break;
......
...@@ -840,9 +840,19 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { ...@@ -840,9 +840,19 @@ void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
X64OperandGenerator g(this); X64OperandGenerator g(this);
Emit(kSSEFloat64ToInt64, g.DefineAsRegister(node), g.Use(node->InputAt(0))); InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
InstructionOperand outputs[2];
size_t output_count = 0;
outputs[output_count++] = g.DefineAsRegister(node);
Node* success_output = NodeProperties::FindProjection(node, 1);
if (success_output) {
outputs[output_count++] = g.DefineAsRegister(success_output);
}
Emit(kSSEFloat64ToInt64, output_count, outputs, 1, inputs);
} }
...@@ -1454,6 +1464,8 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1454,6 +1464,8 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
case IrOpcode::kInt32SubWithOverflow: case IrOpcode::kInt32SubWithOverflow:
cont.OverwriteAndNegateIfEqual(kOverflow); cont.OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop(this, node, kX64Sub32, &cont); return VisitBinop(this, node, kX64Sub32, &cont);
case IrOpcode::kTryTruncateFloat64ToInt64:
return VisitTryTruncateFloat64ToInt64(result);
default: default:
break; break;
} }
......
...@@ -5408,9 +5408,9 @@ TEST(RunTruncateFloat32ToInt64) { ...@@ -5408,9 +5408,9 @@ TEST(RunTruncateFloat32ToInt64) {
} }
TEST(RunTruncateFloat64ToInt64) { TEST(RunTryTruncateFloat64ToInt64WithoutCheck) {
BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat64); BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat64);
m.Return(m.TruncateFloat64ToInt64(m.Parameter(0))); m.Return(m.TryTruncateFloat64ToInt64(m.Parameter(0)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
double input = static_cast<double>(*i); double input = static_cast<double>(*i);
...@@ -5419,6 +5419,28 @@ TEST(RunTruncateFloat64ToInt64) { ...@@ -5419,6 +5419,28 @@ TEST(RunTruncateFloat64ToInt64) {
} }
TEST(RunTryTruncateFloat64ToInt64WithCheck) {
int64_t success = 0;
BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat64);
Node* trunc = m.TryTruncateFloat64ToInt64(m.Parameter(0));
Node* val = m.Projection(0, trunc);
Node* check = m.Projection(1, trunc);
m.StoreToPointer(&success, kMachInt64, check);
m.Return(val);
FOR_FLOAT64_INPUTS(i) {
if (*i < 9223372036854775808.0 && *i > -9223372036854775809.0) {
// Conversions within this range
CHECK_EQ(static_cast<int64_t>(*i), m.Call(*i));
CHECK_NE(0, success);
} else {
m.Call(*i);
CHECK_EQ(0, success);
}
}
}
TEST(RunTruncateFloat32ToUint64) { TEST(RunTruncateFloat32ToUint64) {
BufferedRawMachineAssemblerTester<uint64_t> m(kMachFloat32); BufferedRawMachineAssemblerTester<uint64_t> m(kMachFloat32);
m.Return(m.TruncateFloat32ToUint64(m.Parameter(0))); m.Return(m.TruncateFloat32ToUint64(m.Parameter(0)));
......
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