[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}
This commit is contained in:
parent
aa5eb1e0ed
commit
28261daa47
@ -1039,6 +1039,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
break;
|
||||
case kArm64Float32ToInt64:
|
||||
__ 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;
|
||||
case kArm64Float64ToInt64:
|
||||
__ Fcvtzs(i.OutputRegister(0), i.InputDoubleRegister(0));
|
||||
|
@ -1237,8 +1237,20 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
|
||||
VisitRR(this, kArm64Float32ToInt64, node);
|
||||
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* 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) {
|
||||
return MarkAsWord32(node), VisitChangeFloat64ToInt32(node);
|
||||
case IrOpcode::kChangeFloat64ToUint32:
|
||||
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
|
||||
case IrOpcode::kTruncateFloat32ToInt64:
|
||||
return MarkAsWord64(node), VisitTruncateFloat32ToInt64(node);
|
||||
case IrOpcode::kTryTruncateFloat32ToInt64:
|
||||
return MarkAsWord64(node), VisitTryTruncateFloat32ToInt64(node);
|
||||
case IrOpcode::kTryTruncateFloat64ToInt64:
|
||||
return MarkAsWord64(node), VisitTryTruncateFloat64ToInt64(node);
|
||||
case IrOpcode::kTruncateFloat32ToUint64:
|
||||
@ -1082,7 +1082,7 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
|
||||
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -1208,6 +1208,7 @@ void InstructionSelector::VisitProjection(Node* node) {
|
||||
switch (value->opcode()) {
|
||||
case IrOpcode::kInt32AddWithOverflow:
|
||||
case IrOpcode::kInt32SubWithOverflow:
|
||||
case IrOpcode::kTryTruncateFloat32ToInt64:
|
||||
case IrOpcode::kTryTruncateFloat64ToInt64:
|
||||
case IrOpcode::kTryTruncateFloat64ToUint64:
|
||||
if (ProjectionIndexOf(node->op()) == 0u) {
|
||||
|
@ -135,7 +135,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
|
||||
V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(ChangeFloat64ToInt32, 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(TruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(TryTruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 2) \
|
||||
|
@ -207,7 +207,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
const Operator* ChangeFloat32ToFloat64();
|
||||
const Operator* ChangeFloat64ToInt32(); // narrowing
|
||||
const Operator* ChangeFloat64ToUint32(); // narrowing
|
||||
const Operator* TruncateFloat32ToInt64();
|
||||
const Operator* TryTruncateFloat32ToInt64();
|
||||
const Operator* TryTruncateFloat64ToInt64();
|
||||
const Operator* TruncateFloat32ToUint64();
|
||||
const Operator* TryTruncateFloat64ToUint64();
|
||||
|
@ -1079,9 +1079,30 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
}
|
||||
case kMips64TruncLS: {
|
||||
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.
|
||||
__ trunc_l_s(scratch, i.InputDoubleRegister(0));
|
||||
__ 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;
|
||||
}
|
||||
case kMips64TruncLD: {
|
||||
|
@ -850,8 +850,19 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
|
||||
VisitRR(this, kMips64TruncLS, node);
|
||||
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* 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 @@
|
||||
V(ChangeFloat32ToFloat64) \
|
||||
V(ChangeFloat64ToInt32) \
|
||||
V(ChangeFloat64ToUint32) \
|
||||
V(TruncateFloat32ToInt64) \
|
||||
V(TryTruncateFloat32ToInt64) \
|
||||
V(TryTruncateFloat64ToInt64) \
|
||||
V(TruncateFloat32ToUint64) \
|
||||
V(TryTruncateFloat64ToUint64) \
|
||||
|
@ -428,7 +428,12 @@ class RawMachineAssembler {
|
||||
return AddNode(machine()->ChangeFloat64ToUint32(), 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) {
|
||||
// TODO(ahaas): Remove this function as soon as it is not used anymore in
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -917,7 +917,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kChangeFloat32ToFloat64:
|
||||
case IrOpcode::kChangeFloat64ToInt32:
|
||||
case IrOpcode::kChangeFloat64ToUint32:
|
||||
case IrOpcode::kTruncateFloat32ToInt64:
|
||||
case IrOpcode::kTryTruncateFloat32ToInt64:
|
||||
case IrOpcode::kTryTruncateFloat64ToInt64:
|
||||
case IrOpcode::kTruncateFloat32ToUint64:
|
||||
case IrOpcode::kTryTruncateFloat64ToUint64:
|
||||
|
@ -1051,6 +1051,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
} else {
|
||||
__ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
|
||||
}
|
||||
if (instr->OutputCount() > 1) {
|
||||
__ Set(i.OutputRegister(1), 0x8000000000000000);
|
||||
__ subq(i.OutputRegister(1), i.OutputRegister(0));
|
||||
}
|
||||
break;
|
||||
case kSSEFloat64ToInt64:
|
||||
if (instr->InputAt(0)->IsDoubleRegister()) {
|
||||
|
@ -834,9 +834,19 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitTruncateFloat32ToInt64(Node* node) {
|
||||
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
|
||||
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) {
|
||||
}
|
||||
|
||||
|
||||
TEST(RunTruncateFloat32ToInt64) {
|
||||
TEST(RunTryTruncateFloat32ToInt64WithoutCheck) {
|
||||
BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat32);
|
||||
m.Return(m.TruncateFloat32ToInt64(m.Parameter(0)));
|
||||
m.Return(m.TryTruncateFloat32ToInt64(m.Parameter(0)));
|
||||
|
||||
FOR_INT64_INPUTS(i) {
|
||||
float input = static_cast<float>(*i);
|
||||
@ -5397,9 +5397,25 @@ TEST(RunTruncateFloat32ToInt64) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user