[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:
ahaas 2015-11-19 12:42:03 -08:00 committed by Commit bot
parent adec263860
commit f6e689cebb
16 changed files with 102 additions and 1 deletions

View File

@ -1000,6 +1000,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Float64ToInt64:
__ Fcvtzs(i.OutputRegister64(), i.InputDoubleRegister(0));
break;
case kArm64Float64ToUint64:
__ Fcvtzu(i.OutputRegister64(), i.InputDoubleRegister(0));
break;
case kArm64Int32ToFloat64:
__ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
break;

View File

@ -109,6 +109,7 @@ namespace compiler {
V(Arm64Float64ToInt32) \
V(Arm64Float64ToUint32) \
V(Arm64Float64ToInt64) \
V(Arm64Float64ToUint64) \
V(Arm64Int32ToFloat64) \
V(Arm64Int64ToFloat32) \
V(Arm64Int64ToFloat64) \

View File

@ -1242,6 +1242,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
VisitRR(this, kArm64Float64ToUint64, node);
}
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
VisitRR(this, kArm64Sxtw, node);
}

View File

@ -815,6 +815,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitChangeFloat64ToUint32(node);
case IrOpcode::kChangeFloat64ToInt64:
return MarkAsWord64(node), VisitChangeFloat64ToInt64(node);
case IrOpcode::kTruncateFloat64ToUint64:
return MarkAsWord64(node), VisitTruncateFloat64ToUint64(node);
case IrOpcode::kChangeInt32ToInt64:
return MarkAsWord64(node), VisitChangeInt32ToInt64(node);
case IrOpcode::kChangeUint32ToUint64:
@ -1060,6 +1062,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
UNIMPLEMENTED();
}

View File

@ -136,6 +136,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \
V(ChangeFloat64ToUint32, 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(RoundInt64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
V(RoundInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \

View File

@ -203,6 +203,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* ChangeFloat64ToInt32(); // narrowing
const Operator* ChangeFloat64ToUint32(); // narrowing
const Operator* ChangeFloat64ToInt64(); // narrowing
const Operator* TruncateFloat64ToUint64();
const Operator* ChangeInt32ToFloat64();
const Operator* ChangeInt32ToInt64();
const Operator* ChangeUint32ToFloat64();

View File

@ -712,6 +712,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),

View File

@ -268,6 +268,7 @@
V(ChangeFloat64ToInt32) \
V(ChangeFloat64ToUint32) \
V(ChangeFloat64ToInt64) \
V(TruncateFloat64ToUint64) \
V(ChangeInt32ToFloat64) \
V(ChangeInt32ToInt64) \
V(ChangeUint32ToFloat64) \

View File

@ -932,6 +932,11 @@ void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
// TODO(mbrandy): inspect input to see if nop is appropriate.
VisitRR(this, kPPC_ExtendSignWord32, node);

View File

@ -446,6 +446,9 @@ class RawMachineAssembler {
Node* ChangeFloat64ToInt64(Node* a) {
return AddNode(machine()->ChangeFloat64ToInt64(), a);
}
Node* TruncateFloat64ToUint64(Node* a) {
return AddNode(machine()->TruncateFloat64ToUint64(), a);
}
Node* ChangeInt32ToInt64(Node* a) {
return AddNode(machine()->ChangeInt32ToInt64(), a);
}

View File

@ -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) {
return Type::Intersect(Type::Signed32(), Type::UntaggedFloat64(), zone());
}

View File

@ -902,7 +902,6 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kBitcastFloat64ToInt64:
case IrOpcode::kBitcastInt32ToFloat32:
case IrOpcode::kBitcastInt64ToFloat64:
case IrOpcode::kChangeFloat64ToInt64:
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
case IrOpcode::kChangeInt32ToFloat64:
@ -910,6 +909,8 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kChangeFloat64ToInt64:
case IrOpcode::kTruncateFloat64ToUint64:
case IrOpcode::kFloat64ExtractLowWord32:
case IrOpcode::kFloat64ExtractHighWord32:
case IrOpcode::kFloat64InsertLowWord32:

View File

@ -1027,6 +1027,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
}
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:
if (instr->InputAt(0)->IsRegister()) {
__ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));

View File

@ -79,6 +79,7 @@ namespace compiler {
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEFloat64ToInt64) \
V(SSEFloat64ToUint64) \
V(SSEInt32ToFloat64) \
V(SSEInt64ToFloat32) \
V(SSEInt64ToFloat64) \

View File

@ -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) {
X64OperandGenerator g(this);
Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));

View File

@ -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) {
BufferedRawMachineAssemblerTester<float> m(kMachInt64);
m.Return(m.RoundInt64ToFloat32(m.Parameter(0)));