[turbofan] Implemented the TruncateFloat64ToUint64 TurboFan operator.
The TruncateFloat64ToUint64 operator converts a float64 to an uint64 using round-to-zero rounding mode (truncate). If the input value is outside uint64 range, then the result depends on the architecture. I provide an implementation for x64 and arm64. @v8-ppc-ports and @v8-mips-ports, can you do the implementations for ppc64 and mips64? R=titzer@chromium.org Review URL: https://codereview.chromium.org/1457373002 Cr-Commit-Position: refs/heads/master@{#32127}
This commit is contained in:
parent
adec263860
commit
f6e689cebb
@ -1000,6 +1000,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
case kArm64Float64ToInt64:
|
case kArm64Float64ToInt64:
|
||||||
__ Fcvtzs(i.OutputRegister64(), i.InputDoubleRegister(0));
|
__ Fcvtzs(i.OutputRegister64(), i.InputDoubleRegister(0));
|
||||||
break;
|
break;
|
||||||
|
case kArm64Float64ToUint64:
|
||||||
|
__ Fcvtzu(i.OutputRegister64(), i.InputDoubleRegister(0));
|
||||||
|
break;
|
||||||
case kArm64Int32ToFloat64:
|
case kArm64Int32ToFloat64:
|
||||||
__ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
|
__ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
|
||||||
break;
|
break;
|
||||||
|
@ -109,6 +109,7 @@ namespace compiler {
|
|||||||
V(Arm64Float64ToInt32) \
|
V(Arm64Float64ToInt32) \
|
||||||
V(Arm64Float64ToUint32) \
|
V(Arm64Float64ToUint32) \
|
||||||
V(Arm64Float64ToInt64) \
|
V(Arm64Float64ToInt64) \
|
||||||
|
V(Arm64Float64ToUint64) \
|
||||||
V(Arm64Int32ToFloat64) \
|
V(Arm64Int32ToFloat64) \
|
||||||
V(Arm64Int64ToFloat32) \
|
V(Arm64Int64ToFloat32) \
|
||||||
V(Arm64Int64ToFloat64) \
|
V(Arm64Int64ToFloat64) \
|
||||||
|
@ -1242,6 +1242,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
|
||||||
|
VisitRR(this, kArm64Float64ToUint64, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
||||||
VisitRR(this, kArm64Sxtw, node);
|
VisitRR(this, kArm64Sxtw, node);
|
||||||
}
|
}
|
||||||
|
@ -815,6 +815,8 @@ void InstructionSelector::VisitNode(Node* node) {
|
|||||||
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
|
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
|
||||||
case IrOpcode::kChangeFloat64ToInt64:
|
case IrOpcode::kChangeFloat64ToInt64:
|
||||||
return MarkAsWord64(node), VisitChangeFloat64ToInt64(node);
|
return MarkAsWord64(node), VisitChangeFloat64ToInt64(node);
|
||||||
|
case IrOpcode::kTruncateFloat64ToUint64:
|
||||||
|
return MarkAsWord64(node), VisitTruncateFloat64ToUint64(node);
|
||||||
case IrOpcode::kChangeInt32ToInt64:
|
case IrOpcode::kChangeInt32ToInt64:
|
||||||
return MarkAsWord64(node), VisitChangeInt32ToInt64(node);
|
return MarkAsWord64(node), VisitChangeInt32ToInt64(node);
|
||||||
case IrOpcode::kChangeUint32ToUint64:
|
case IrOpcode::kChangeUint32ToUint64:
|
||||||
@ -1060,6 +1062,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
|
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
@ -136,6 +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(ChangeFloat64ToInt64, Operator::kNoProperties, 1, 0, 1) \
|
V(ChangeFloat64ToInt64, 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) \
|
||||||
V(RoundInt64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
|
V(RoundInt64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
|
||||||
V(RoundInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \
|
V(RoundInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \
|
||||||
|
@ -203,6 +203,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
|||||||
const Operator* ChangeFloat64ToInt32(); // narrowing
|
const Operator* ChangeFloat64ToInt32(); // narrowing
|
||||||
const Operator* ChangeFloat64ToUint32(); // narrowing
|
const Operator* ChangeFloat64ToUint32(); // narrowing
|
||||||
const Operator* ChangeFloat64ToInt64(); // narrowing
|
const Operator* ChangeFloat64ToInt64(); // narrowing
|
||||||
|
const Operator* TruncateFloat64ToUint64();
|
||||||
const Operator* ChangeInt32ToFloat64();
|
const Operator* ChangeInt32ToFloat64();
|
||||||
const Operator* ChangeInt32ToInt64();
|
const Operator* ChangeInt32ToInt64();
|
||||||
const Operator* ChangeUint32ToFloat64();
|
const Operator* ChangeUint32ToFloat64();
|
||||||
|
@ -712,6 +712,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
||||||
Mips64OperandGenerator g(this);
|
Mips64OperandGenerator g(this);
|
||||||
Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
|
Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
|
||||||
|
@ -268,6 +268,7 @@
|
|||||||
V(ChangeFloat64ToInt32) \
|
V(ChangeFloat64ToInt32) \
|
||||||
V(ChangeFloat64ToUint32) \
|
V(ChangeFloat64ToUint32) \
|
||||||
V(ChangeFloat64ToInt64) \
|
V(ChangeFloat64ToInt64) \
|
||||||
|
V(TruncateFloat64ToUint64) \
|
||||||
V(ChangeInt32ToFloat64) \
|
V(ChangeInt32ToFloat64) \
|
||||||
V(ChangeInt32ToInt64) \
|
V(ChangeInt32ToInt64) \
|
||||||
V(ChangeUint32ToFloat64) \
|
V(ChangeUint32ToFloat64) \
|
||||||
|
@ -932,6 +932,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
||||||
// TODO(mbrandy): inspect input to see if nop is appropriate.
|
// TODO(mbrandy): inspect input to see if nop is appropriate.
|
||||||
VisitRR(this, kPPC_ExtendSignWord32, node);
|
VisitRR(this, kPPC_ExtendSignWord32, node);
|
||||||
|
@ -446,6 +446,9 @@ class RawMachineAssembler {
|
|||||||
Node* ChangeFloat64ToInt64(Node* a) {
|
Node* ChangeFloat64ToInt64(Node* a) {
|
||||||
return AddNode(machine()->ChangeFloat64ToInt64(), a);
|
return AddNode(machine()->ChangeFloat64ToInt64(), a);
|
||||||
}
|
}
|
||||||
|
Node* TruncateFloat64ToUint64(Node* a) {
|
||||||
|
return AddNode(machine()->TruncateFloat64ToUint64(), a);
|
||||||
|
}
|
||||||
Node* ChangeInt32ToInt64(Node* a) {
|
Node* ChangeInt32ToInt64(Node* a) {
|
||||||
return AddNode(machine()->ChangeInt32ToInt64(), a);
|
return AddNode(machine()->ChangeInt32ToInt64(), a);
|
||||||
}
|
}
|
||||||
|
@ -2085,6 +2085,11 @@ Type* Typer::Visitor::TypeChangeFloat64ToInt64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type* Typer::Visitor::TypeTruncateFloat64ToUint64(Node* node) {
|
||||||
|
return Type::Internal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeChangeInt32ToFloat64(Node* node) {
|
Type* Typer::Visitor::TypeChangeInt32ToFloat64(Node* node) {
|
||||||
return Type::Intersect(Type::Signed32(), Type::UntaggedFloat64(), zone());
|
return Type::Intersect(Type::Signed32(), Type::UntaggedFloat64(), zone());
|
||||||
}
|
}
|
||||||
|
@ -902,7 +902,6 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
case IrOpcode::kBitcastFloat64ToInt64:
|
case IrOpcode::kBitcastFloat64ToInt64:
|
||||||
case IrOpcode::kBitcastInt32ToFloat32:
|
case IrOpcode::kBitcastInt32ToFloat32:
|
||||||
case IrOpcode::kBitcastInt64ToFloat64:
|
case IrOpcode::kBitcastInt64ToFloat64:
|
||||||
case IrOpcode::kChangeFloat64ToInt64:
|
|
||||||
case IrOpcode::kChangeInt32ToInt64:
|
case IrOpcode::kChangeInt32ToInt64:
|
||||||
case IrOpcode::kChangeUint32ToUint64:
|
case IrOpcode::kChangeUint32ToUint64:
|
||||||
case IrOpcode::kChangeInt32ToFloat64:
|
case IrOpcode::kChangeInt32ToFloat64:
|
||||||
@ -910,6 +909,8 @@ 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::kChangeFloat64ToInt64:
|
||||||
|
case IrOpcode::kTruncateFloat64ToUint64:
|
||||||
case IrOpcode::kFloat64ExtractLowWord32:
|
case IrOpcode::kFloat64ExtractLowWord32:
|
||||||
case IrOpcode::kFloat64ExtractHighWord32:
|
case IrOpcode::kFloat64ExtractHighWord32:
|
||||||
case IrOpcode::kFloat64InsertLowWord32:
|
case IrOpcode::kFloat64InsertLowWord32:
|
||||||
|
@ -1027,6 +1027,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
|
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case kSSEFloat64ToUint64: {
|
||||||
|
// There does not exist a Float64ToUint64 instruction, so we have to use
|
||||||
|
// the Float64ToInt64 instruction.
|
||||||
|
if (instr->InputAt(0)->IsDoubleRegister()) {
|
||||||
|
__ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
|
||||||
|
} else {
|
||||||
|
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
|
||||||
|
}
|
||||||
|
// Check if the result of the Float64ToInt64 conversion is positive, we
|
||||||
|
// are already done.
|
||||||
|
__ testq(i.OutputRegister(), i.OutputRegister());
|
||||||
|
Label done;
|
||||||
|
__ j(positive, &done);
|
||||||
|
// The result of the first conversion was negative, which means that the
|
||||||
|
// input value was not within the positive int64 range. We subtract 2^64
|
||||||
|
// and convert it again to see if it is within the uint64 range.
|
||||||
|
__ Move(kScratchDoubleReg, -9223372036854775808.0);
|
||||||
|
if (instr->InputAt(0)->IsDoubleRegister()) {
|
||||||
|
__ addsd(kScratchDoubleReg, i.InputDoubleRegister(0));
|
||||||
|
} else {
|
||||||
|
__ addsd(kScratchDoubleReg, i.InputOperand(0));
|
||||||
|
}
|
||||||
|
__ Cvttsd2siq(i.OutputRegister(), kScratchDoubleReg);
|
||||||
|
__ testq(i.OutputRegister(), i.OutputRegister());
|
||||||
|
// The only possible negative value here is 0x80000000000000000, which is
|
||||||
|
// used on x64 to indicate an integer overflow.
|
||||||
|
__ j(negative, &done);
|
||||||
|
// The input value is within uint64 range and the second conversion worked
|
||||||
|
// successfully, but we still have to undo the subtraction we did
|
||||||
|
// earlier.
|
||||||
|
__ movq(kScratchRegister, Immediate(1));
|
||||||
|
__ shlq(kScratchRegister, Immediate(63));
|
||||||
|
__ orq(i.OutputRegister(), kScratchRegister);
|
||||||
|
__ bind(&done);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case kSSEInt32ToFloat64:
|
case kSSEInt32ToFloat64:
|
||||||
if (instr->InputAt(0)->IsRegister()) {
|
if (instr->InputAt(0)->IsRegister()) {
|
||||||
__ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
|
__ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
|
||||||
|
@ -79,6 +79,7 @@ namespace compiler {
|
|||||||
V(SSEFloat64ToInt32) \
|
V(SSEFloat64ToInt32) \
|
||||||
V(SSEFloat64ToUint32) \
|
V(SSEFloat64ToUint32) \
|
||||||
V(SSEFloat64ToInt64) \
|
V(SSEFloat64ToInt64) \
|
||||||
|
V(SSEFloat64ToUint64) \
|
||||||
V(SSEInt32ToFloat64) \
|
V(SSEInt32ToFloat64) \
|
||||||
V(SSEInt64ToFloat32) \
|
V(SSEInt64ToFloat32) \
|
||||||
V(SSEInt64ToFloat64) \
|
V(SSEInt64ToFloat64) \
|
||||||
|
@ -840,6 +840,12 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
|
||||||
|
X64OperandGenerator g(this);
|
||||||
|
Emit(kSSEFloat64ToUint64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
|
||||||
X64OperandGenerator g(this);
|
X64OperandGenerator g(this);
|
||||||
Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||||
|
@ -5364,6 +5364,26 @@ TEST(RunChangeFloat64ToInt64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(RunTruncateFloat64ToUint64) {
|
||||||
|
BufferedRawMachineAssemblerTester<uint64_t> m(kMachFloat64);
|
||||||
|
m.Return(m.TruncateFloat64ToUint64(m.Parameter(0)));
|
||||||
|
|
||||||
|
FOR_UINT64_INPUTS(j) {
|
||||||
|
double input = static_cast<double>(*j);
|
||||||
|
|
||||||
|
if (input < 18446744073709551616.0) {
|
||||||
|
CHECK_EQ(static_cast<uint64_t>(input), m.Call(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FOR_FLOAT64_INPUTS(i) {
|
||||||
|
if (*i < 18446744073709551616.0 && *i >= 0) {
|
||||||
|
CHECK_EQ(static_cast<uint64_t>(*i), m.Call(*i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(RunRoundInt64ToFloat32) {
|
TEST(RunRoundInt64ToFloat32) {
|
||||||
BufferedRawMachineAssemblerTester<float> m(kMachInt64);
|
BufferedRawMachineAssemblerTester<float> m(kMachInt64);
|
||||||
m.Return(m.RoundInt64ToFloat32(m.Parameter(0)));
|
m.Return(m.RoundInt64ToFloat32(m.Parameter(0)));
|
||||||
|
Loading…
Reference in New Issue
Block a user