Commit 28261daa authored by ahaas's avatar ahaas Committed by Commit bot

[turbofan] Change TruncateFloat32ToInt64 to TryTruncateFloat32ToInt64.

This operator now provides a second output which indicates whether the
conversion from float32 to int64 was successful or not. The second output
returns 0 if the conversion fails, or something else if the conversion succeeds.

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

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

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

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

Cr-Commit-Position: refs/heads/master@{#32737}
parent aa5eb1e0
...@@ -1039,6 +1039,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1039,6 +1039,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break; break;
case kArm64Float32ToInt64: case kArm64Float32ToInt64:
__ Fcvtzs(i.OutputRegister64(), i.InputFloat32Register(0)); __ Fcvtzs(i.OutputRegister64(), i.InputFloat32Register(0));
if (i.OutputCount() > 1) {
__ Cmp(i.OutputRegister(0), 1);
__ Ccmp(i.OutputRegister(0), -1, VFlag, vc);
__ Fccmp(i.InputFloat32Register(0), i.InputFloat32Register(0), VFlag,
vc);
__ Cset(i.OutputRegister(1), vc);
}
break; break;
case kArm64Float64ToInt64: case kArm64Float64ToInt64:
__ Fcvtzs(i.OutputRegister(0), i.InputDoubleRegister(0)); __ Fcvtzs(i.OutputRegister(0), i.InputDoubleRegister(0));
......
...@@ -1237,8 +1237,20 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { ...@@ -1237,8 +1237,20 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
VisitRR(this, kArm64Float32ToInt64, 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(kArm64Float32ToInt64, output_count, outputs, 1, inputs);
} }
......
...@@ -826,8 +826,8 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -826,8 +826,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitChangeFloat64ToInt32(node); return MarkAsWord32(node), VisitChangeFloat64ToInt32(node);
case IrOpcode::kChangeFloat64ToUint32: case IrOpcode::kChangeFloat64ToUint32:
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node); return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
case IrOpcode::kTruncateFloat32ToInt64: case IrOpcode::kTryTruncateFloat32ToInt64:
return MarkAsWord64(node), VisitTruncateFloat32ToInt64(node); return MarkAsWord64(node), VisitTryTruncateFloat32ToInt64(node);
case IrOpcode::kTryTruncateFloat64ToInt64: case IrOpcode::kTryTruncateFloat64ToInt64:
return MarkAsWord64(node), VisitTryTruncateFloat64ToInt64(node); return MarkAsWord64(node), VisitTryTruncateFloat64ToInt64(node);
case IrOpcode::kTruncateFloat32ToUint64: case IrOpcode::kTruncateFloat32ToUint64:
...@@ -1082,7 +1082,7 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { ...@@ -1082,7 +1082,7 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat32ToInt64(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::kTryTruncateFloat32ToInt64:
case IrOpcode::kTryTruncateFloat64ToInt64: case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTryTruncateFloat64ToUint64: case IrOpcode::kTryTruncateFloat64ToUint64:
if (ProjectionIndexOf(node->op()) == 0u) { if (ProjectionIndexOf(node->op()) == 0u) {
......
...@@ -135,7 +135,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { ...@@ -135,7 +135,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1) \ V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
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(TryTruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 2) \
V(TryTruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 2) \ V(TryTruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 2) \
V(TruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 1) \ V(TruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 1) \
V(TryTruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 2) \ V(TryTruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 2) \
......
...@@ -207,7 +207,7 @@ class MachineOperatorBuilder final : public ZoneObject { ...@@ -207,7 +207,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* ChangeFloat32ToFloat64(); const Operator* ChangeFloat32ToFloat64();
const Operator* ChangeFloat64ToInt32(); // narrowing const Operator* ChangeFloat64ToInt32(); // narrowing
const Operator* ChangeFloat64ToUint32(); // narrowing const Operator* ChangeFloat64ToUint32(); // narrowing
const Operator* TruncateFloat32ToInt64(); const Operator* TryTruncateFloat32ToInt64();
const Operator* TryTruncateFloat64ToInt64(); const Operator* TryTruncateFloat64ToInt64();
const Operator* TruncateFloat32ToUint64(); const Operator* TruncateFloat32ToUint64();
const Operator* TryTruncateFloat64ToUint64(); const Operator* TryTruncateFloat64ToUint64();
......
...@@ -1079,9 +1079,30 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1079,9 +1079,30 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
} }
case kMips64TruncLS: { case kMips64TruncLS: {
FPURegister scratch = kScratchDoubleReg; FPURegister scratch = kScratchDoubleReg;
Register tmp_fcsr = kScratchReg;
Register result = kScratchReg2;
bool load_status = instr->OutputCount() > 1;
if (load_status) {
// Save FCSR.
__ cfc1(tmp_fcsr, FCSR);
// Clear FPU flags.
__ ctc1(zero_reg, FCSR);
}
// Other arches use round to zero here, so we follow. // Other arches use round to zero here, so we follow.
__ trunc_l_s(scratch, i.InputDoubleRegister(0)); __ trunc_l_s(scratch, i.InputDoubleRegister(0));
__ dmfc1(i.OutputRegister(), scratch); __ dmfc1(i.OutputRegister(), scratch);
if (load_status) {
__ cfc1(result, FCSR);
// Check for overflow and NaNs.
__ andi(result, result,
(kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask));
__ Slt(result, zero_reg, result);
__ xori(result, result, 1);
__ mov(i.OutputRegister(1), result);
// Restore FCSR
__ ctc1(tmp_fcsr, FCSR);
}
break; break;
} }
case kMips64TruncLD: { case kMips64TruncLD: {
......
...@@ -850,8 +850,19 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { ...@@ -850,8 +850,19 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
VisitRR(this, kMips64TruncLS, node); Mips64OperandGenerator 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);
}
this->Emit(kMips64TruncLS, output_count, outputs, 1, inputs);
} }
......
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
V(ChangeFloat32ToFloat64) \ V(ChangeFloat32ToFloat64) \
V(ChangeFloat64ToInt32) \ V(ChangeFloat64ToInt32) \
V(ChangeFloat64ToUint32) \ V(ChangeFloat64ToUint32) \
V(TruncateFloat32ToInt64) \ V(TryTruncateFloat32ToInt64) \
V(TryTruncateFloat64ToInt64) \ V(TryTruncateFloat64ToInt64) \
V(TruncateFloat32ToUint64) \ V(TruncateFloat32ToUint64) \
V(TryTruncateFloat64ToUint64) \ V(TryTruncateFloat64ToUint64) \
......
...@@ -428,7 +428,12 @@ class RawMachineAssembler { ...@@ -428,7 +428,12 @@ class RawMachineAssembler {
return AddNode(machine()->ChangeFloat64ToUint32(), a); return AddNode(machine()->ChangeFloat64ToUint32(), a);
} }
Node* TruncateFloat32ToInt64(Node* a) { Node* TruncateFloat32ToInt64(Node* a) {
return AddNode(machine()->TruncateFloat32ToInt64(), a); // TODO(ahaas): Remove this function as soon as it is not used anymore in
// WebAssembly.
return AddNode(machine()->TryTruncateFloat32ToInt64(), a);
}
Node* TryTruncateFloat32ToInt64(Node* a) {
return AddNode(machine()->TryTruncateFloat32ToInt64(), a);
} }
Node* TruncateFloat64ToInt64(Node* a) { Node* TruncateFloat64ToInt64(Node* a) {
// TODO(ahaas): Remove this function as soon as it is not used anymore in // TODO(ahaas): Remove this function as soon as it is not used anymore in
......
...@@ -2121,7 +2121,7 @@ Type* Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) { ...@@ -2121,7 +2121,7 @@ Type* Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) {
} }
Type* Typer::Visitor::TypeTruncateFloat32ToInt64(Node* node) { Type* Typer::Visitor::TypeTryTruncateFloat32ToInt64(Node* node) {
return Type::Internal(); return Type::Internal();
} }
......
...@@ -917,7 +917,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -917,7 +917,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kChangeFloat32ToFloat64: case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kChangeFloat64ToInt32: case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32: case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kTruncateFloat32ToInt64: case IrOpcode::kTryTruncateFloat32ToInt64:
case IrOpcode::kTryTruncateFloat64ToInt64: case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTruncateFloat32ToUint64: case IrOpcode::kTruncateFloat32ToUint64:
case IrOpcode::kTryTruncateFloat64ToUint64: case IrOpcode::kTryTruncateFloat64ToUint64:
......
...@@ -1051,6 +1051,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1051,6 +1051,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
} else { } else {
__ Cvttss2siq(i.OutputRegister(), i.InputOperand(0)); __ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
} }
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 0x8000000000000000);
__ subq(i.OutputRegister(1), i.OutputRegister(0));
}
break; break;
case kSSEFloat64ToInt64: case kSSEFloat64ToInt64:
if (instr->InputAt(0)->IsDoubleRegister()) { if (instr->InputAt(0)->IsDoubleRegister()) {
......
...@@ -834,9 +834,19 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { ...@@ -834,9 +834,19 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
} }
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) { void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
X64OperandGenerator g(this); X64OperandGenerator g(this);
Emit(kSSEFloat32ToInt64, 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(kSSEFloat32ToInt64, output_count, outputs, 1, inputs);
} }
......
...@@ -5387,9 +5387,9 @@ TEST(RunBitcastFloat64ToInt64) { ...@@ -5387,9 +5387,9 @@ TEST(RunBitcastFloat64ToInt64) {
} }
TEST(RunTruncateFloat32ToInt64) { TEST(RunTryTruncateFloat32ToInt64WithoutCheck) {
BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat32); BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat32);
m.Return(m.TruncateFloat32ToInt64(m.Parameter(0))); m.Return(m.TryTruncateFloat32ToInt64(m.Parameter(0)));
FOR_INT64_INPUTS(i) { FOR_INT64_INPUTS(i) {
float input = static_cast<float>(*i); float input = static_cast<float>(*i);
...@@ -5397,9 +5397,25 @@ TEST(RunTruncateFloat32ToInt64) { ...@@ -5397,9 +5397,25 @@ TEST(RunTruncateFloat32ToInt64) {
CHECK_EQ(static_cast<int64_t>(input), m.Call(input)); CHECK_EQ(static_cast<int64_t>(input), m.Call(input));
} }
} }
FOR_FLOAT32_INPUTS(j) { }
if (*j < 9223372036854775808.0 && *j > -9223372036854775809.0) {
CHECK_EQ(static_cast<int64_t>(*j), m.Call(*j));
TEST(RunTryTruncateFloat32ToInt64WithCheck) {
int64_t success = 0;
BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat32);
Node* trunc = m.TryTruncateFloat32ToInt64(m.Parameter(0));
Node* val = m.Projection(0, trunc);
Node* check = m.Projection(1, trunc);
m.StoreToPointer(&success, kMachInt64, check);
m.Return(val);
FOR_FLOAT32_INPUTS(i) {
if (*i < 9223372036854775808.0 && *i > -9223372036854775809.0) {
CHECK_EQ(static_cast<int64_t>(*i), m.Call(*i));
CHECK_NE(0, success);
} else {
m.Call(*i);
CHECK_EQ(0, success);
} }
} }
} }
......
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