Commit 68cc0be2 authored by ahaas's avatar ahaas Committed by Commit bot

[turbofan] Implemented the TruncateFloat32ToUint64 TurboFan operator.

The TruncateFloat32ToUint64 operator converts a float32 to an uint64 using
round-to-zero rounding mode. If the input value is outside uint64 range, then
the result depends on the architecture. I provide an implementation for x64 and
arm64.

R=titzer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#32379}
parent c88d7cd1
......@@ -1028,6 +1028,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Float64ToInt64:
__ Fcvtzs(i.OutputRegister64(), i.InputDoubleRegister(0));
break;
case kArm64Float32ToUint64:
__ Fcvtzu(i.OutputRegister64(), i.InputFloat32Register(0));
break;
case kArm64Float64ToUint64:
__ Fcvtzu(i.OutputRegister64(), i.InputDoubleRegister(0));
break;
......
......@@ -114,6 +114,7 @@ namespace compiler {
V(Arm64Float64ToUint32) \
V(Arm64Float32ToInt64) \
V(Arm64Float64ToInt64) \
V(Arm64Float32ToUint64) \
V(Arm64Float64ToUint64) \
V(Arm64Int32ToFloat64) \
V(Arm64Int64ToFloat32) \
......
......@@ -1247,6 +1247,11 @@ void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
VisitRR(this, kArm64Float32ToUint64, node);
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
VisitRR(this, kArm64Float64ToUint64, node);
}
......
......@@ -851,6 +851,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord64(node), VisitTruncateFloat32ToInt64(node);
case IrOpcode::kTruncateFloat64ToInt64:
return MarkAsWord64(node), VisitTruncateFloat64ToInt64(node);
case IrOpcode::kTruncateFloat32ToUint64:
return MarkAsWord64(node), VisitTruncateFloat32ToUint64(node);
case IrOpcode::kTruncateFloat64ToUint64:
return MarkAsWord64(node), VisitTruncateFloat64ToUint64(node);
case IrOpcode::kChangeInt32ToInt64:
......@@ -1111,6 +1113,11 @@ void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
UNIMPLEMENTED();
}
......
......@@ -137,6 +137,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat32ToUint64, 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) \
......
......@@ -209,6 +209,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* ChangeFloat64ToUint32(); // narrowing
const Operator* TruncateFloat32ToInt64();
const Operator* TruncateFloat64ToInt64();
const Operator* TruncateFloat32ToUint64();
const Operator* TruncateFloat64ToUint64();
const Operator* ChangeInt32ToFloat64();
const Operator* ChangeInt32ToInt64();
......
......@@ -741,6 +741,11 @@ void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
VisitRR(this, kMips64TruncUlD, node);
}
......
......@@ -272,6 +272,7 @@
V(ChangeFloat64ToUint32) \
V(TruncateFloat32ToInt64) \
V(TruncateFloat64ToInt64) \
V(TruncateFloat32ToUint64) \
V(TruncateFloat64ToUint64) \
V(ChangeInt32ToFloat64) \
V(ChangeInt32ToInt64) \
......
......@@ -937,6 +937,11 @@ void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
VisitRR(this, kPPC_DoubleToUint64, node);
}
......
......@@ -444,6 +444,9 @@ class RawMachineAssembler {
Node* TruncateFloat64ToInt64(Node* a) {
return AddNode(machine()->TruncateFloat64ToInt64(), a);
}
Node* TruncateFloat32ToUint64(Node* a) {
return AddNode(machine()->TruncateFloat32ToUint64(), a);
}
Node* TruncateFloat64ToUint64(Node* a) {
return AddNode(machine()->TruncateFloat64ToUint64(), a);
}
......
......@@ -2112,6 +2112,11 @@ Type* Typer::Visitor::TypeTruncateFloat64ToInt64(Node* node) {
}
Type* Typer::Visitor::TypeTruncateFloat32ToUint64(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeTruncateFloat64ToUint64(Node* node) {
return Type::Internal();
}
......
......@@ -921,6 +921,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kTruncateFloat32ToInt64:
case IrOpcode::kTruncateFloat64ToInt64:
case IrOpcode::kTruncateFloat32ToUint64:
case IrOpcode::kTruncateFloat64ToUint64:
case IrOpcode::kFloat64ExtractLowWord32:
case IrOpcode::kFloat64ExtractHighWord32:
......
......@@ -1057,6 +1057,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
}
break;
case kSSEFloat32ToUint64: {
// There does not exist a Float32ToUint64 instruction, so we have to use
// the Float32ToInt64 instruction.
if (instr->InputAt(0)->IsDoubleRegister()) {
__ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
} else {
__ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
}
// Check if the result of the Float32ToInt64 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.0f);
if (instr->InputAt(0)->IsDoubleRegister()) {
__ addss(kScratchDoubleReg, i.InputDoubleRegister(0));
} else {
__ addss(kScratchDoubleReg, i.InputOperand(0));
}
__ Cvttss2siq(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 kSSEFloat64ToUint64: {
// There does not exist a Float64ToUint64 instruction, so we have to use
// the Float64ToInt64 instruction.
......
......@@ -81,6 +81,7 @@ namespace compiler {
V(SSEFloat64ToUint32) \
V(SSEFloat32ToInt64) \
V(SSEFloat64ToInt64) \
V(SSEFloat32ToUint64) \
V(SSEFloat64ToUint64) \
V(SSEInt32ToFloat64) \
V(SSEInt64ToFloat32) \
......
......@@ -846,6 +846,12 @@ void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat32ToUint64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat64ToUint64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
......
......@@ -5420,6 +5420,24 @@ TEST(RunTruncateFloat64ToInt64) {
}
TEST(RunTruncateFloat32ToUint64) {
BufferedRawMachineAssemblerTester<uint64_t> m(kMachFloat32);
m.Return(m.TruncateFloat32ToUint64(m.Parameter(0)));
FOR_UINT64_INPUTS(i) {
float input = static_cast<float>(*i);
if (input < 18446744073709551616.0) {
CHECK_EQ(static_cast<uint64_t>(input), m.Call(input));
}
}
FOR_FLOAT32_INPUTS(j) {
if (*j < 18446744073709551616.0 && *j >= 0) {
CHECK_EQ(static_cast<uint64_t>(*j), m.Call(*j));
}
}
}
TEST(RunTruncateFloat64ToUint64) {
BufferedRawMachineAssemblerTester<uint64_t> m(kMachFloat64);
m.Return(m.TruncateFloat64ToUint64(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