Commit dffecf31 authored by ahaas's avatar ahaas Committed by Commit bot

[turbofan] Added the optional Float64RoundTiesEven operator to turbofan.

The TiesEven rounding mode rounds float64 numbers to the nearest
integer. If there are two nearest integers, then the number is rounded
to the even one.  This is the default rounding mode according to
IEEE~754.

I implemented the operator on ia32, x64, arm, arm64, mips, and mips64.

I think there is a bug in the current implementation of the ppc
simulator, which kept me from implementing the operator on ppc.
According to my understanding of the ppc instruction manual, the FRIN
instruction provides the right behavior for Float64RoundTiesEven. In the
simulator, however, FRIN provides a different semantics. If there are
two nearest integers, then the simulator returns the one which is
further away form 0.

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

Cr-Commit-Position: refs/heads/master@{#32005}
parent 1389b9f5
......@@ -779,6 +779,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArmVrintaF64:
__ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
break;
case kArmVrintnF64:
__ vrintn(i.OutputFloat64Register(), i.InputFloat64Register(0));
break;
case kArmVcvtF32F64: {
__ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
......
......@@ -69,6 +69,7 @@ namespace compiler {
V(ArmVrintpF64) \
V(ArmVrintzF64) \
V(ArmVrintaF64) \
V(ArmVrintnF64) \
V(ArmVcvtF32F64) \
V(ArmVcvtF64F32) \
V(ArmVcvtF64S32) \
......
......@@ -1135,6 +1135,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
VisitRR(this, kArmVrintnF64, node);
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......@@ -1563,7 +1568,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
flags |= MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundUp |
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesAway;
MachineOperatorBuilder::kFloat64RoundTiesAway |
MachineOperatorBuilder::kFloat64RoundTiesEven;
}
return flags;
}
......
......@@ -597,14 +597,17 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Float64RoundDown:
__ Frintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArm64Float64RoundUp:
__ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArm64Float64RoundTiesAway:
__ Frinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArm64Float64RoundTruncate:
__ Frintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArm64Float64RoundUp:
__ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
case kArm64Float64RoundTiesEven:
__ Frintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArm64Add:
__ Add(i.OutputRegister(), i.InputOrZeroRegister64(0),
......
......@@ -100,9 +100,10 @@ namespace compiler {
V(Arm64Float64Neg) \
V(Arm64Float64Sqrt) \
V(Arm64Float64RoundDown) \
V(Arm64Float64RoundUp) \
V(Arm64Float64RoundTiesAway) \
V(Arm64Float64RoundTruncate) \
V(Arm64Float64RoundUp) \
V(Arm64Float64RoundTiesEven) \
V(Arm64Float32ToFloat64) \
V(Arm64Float64ToFloat32) \
V(Arm64Float64ToInt32) \
......
......@@ -1478,6 +1478,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
VisitRR(this, kArm64Float64RoundTiesEven, node);
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......@@ -2049,6 +2054,7 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kFloat64RoundUp |
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesAway |
MachineOperatorBuilder::kFloat64RoundTiesEven |
MachineOperatorBuilder::kWord32ShiftIsSafe |
MachineOperatorBuilder::kInt32DivIsSafe |
MachineOperatorBuilder::kUint32DivIsSafe;
......
......@@ -871,6 +871,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......@@ -1281,7 +1286,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
if (CpuFeatures::IsSupported(SSE4_1)) {
flags |= MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundUp |
MachineOperatorBuilder::kFloat64RoundTruncate;
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesEven;
}
return flags;
}
......
......@@ -892,6 +892,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsFloat64(node), VisitFloat64RoundTruncate(node);
case IrOpcode::kFloat64RoundTiesAway:
return MarkAsFloat64(node), VisitFloat64RoundTiesAway(node);
case IrOpcode::kFloat64RoundTiesEven:
return MarkAsFloat64(node), VisitFloat64RoundTiesEven(node);
case IrOpcode::kFloat64ExtractLowWord32:
return MarkAsWord32(node), VisitFloat64ExtractLowWord32(node);
case IrOpcode::kFloat64ExtractHighWord32:
......
......@@ -186,7 +186,8 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(Float64RoundDown, Operator::kNoProperties, 1, 0, 1) \
V(Float64RoundUp, Operator::kNoProperties, 1, 0, 1) \
V(Float64RoundTruncate, Operator::kNoProperties, 1, 0, 1) \
V(Float64RoundTiesAway, Operator::kNoProperties, 1, 0, 1)
V(Float64RoundTiesAway, Operator::kNoProperties, 1, 0, 1) \
V(Float64RoundTiesEven, Operator::kNoProperties, 1, 0, 1)
#define MACHINE_TYPE_LIST(V) \
......
......@@ -119,18 +119,20 @@ class MachineOperatorBuilder final : public ZoneObject {
kFloat64RoundDown = 1u << 4,
kFloat64RoundUp = 1u << 5,
kFloat64RoundTruncate = 1u << 6,
kFloat64RoundTiesAway = 1u << 7,
kInt32DivIsSafe = 1u << 8,
kUint32DivIsSafe = 1u << 9,
kWord32ShiftIsSafe = 1u << 10,
kWord32Ctz = 1u << 11,
kWord64Ctz = 1u << 12,
kWord32Popcnt = 1u << 13,
kWord64Popcnt = 1u << 14,
kFloat64RoundTiesEven = 1u << 7,
kFloat64RoundTiesAway = 1u << 8,
kInt32DivIsSafe = 1u << 9,
kUint32DivIsSafe = 1u << 10,
kWord32ShiftIsSafe = 1u << 11,
kWord32Ctz = 1u << 12,
kWord64Ctz = 1u << 13,
kWord32Popcnt = 1u << 14,
kWord64Popcnt = 1u << 15,
kAllOptionalOps = kFloat32Max | kFloat32Min | kFloat64Max | kFloat64Min |
kFloat64RoundDown | kFloat64RoundUp |
kFloat64RoundTruncate | kFloat64RoundTiesAway |
kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt
kFloat64RoundTiesEven | kWord32Ctz | kWord64Ctz |
kWord32Popcnt | kWord64Popcnt
};
typedef base::Flags<Flag, unsigned> Flags;
......@@ -267,6 +269,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const OptionalOperator Float64RoundUp();
const OptionalOperator Float64RoundTruncate();
const OptionalOperator Float64RoundTiesAway();
const OptionalOperator Float64RoundTiesEven();
// Floating point bit representation.
const Operator* Float64ExtractLowWord32();
......
......@@ -601,6 +601,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
UNREACHABLE();
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......
......@@ -213,6 +213,13 @@ class OutOfLineCeil final : public OutOfLineRound {
};
class OutOfLineTiesEven final : public OutOfLineRound {
public:
OutOfLineTiesEven(CodeGenerator* gen, DoubleRegister result)
: OutOfLineRound(gen, result) {}
};
class OutOfLineRecordWrite final : public OutOfLineCode {
public:
OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
......@@ -861,6 +868,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
break;
}
case kMips64Float64RoundTiesEven: {
ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(round_l_d, TiesEven);
break;
}
case kMips64Float64Max: {
// (b < a) ? a : b
if (kArchVariant == kMips64r6) {
......
......@@ -69,6 +69,7 @@ namespace compiler {
V(Mips64Float64RoundDown) \
V(Mips64Float64RoundTruncate) \
V(Mips64Float64RoundUp) \
V(Mips64Float64RoundTiesEven) \
V(Mips64CvtSD) \
V(Mips64CvtDS) \
V(Mips64TruncWD) \
......
......@@ -817,6 +817,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
VisitRR(this, kMips64Float64RoundTiesEven, node);
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......@@ -1398,7 +1403,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kFloat32Max |
MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundUp |
MachineOperatorBuilder::kFloat64RoundTruncate;
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesEven;
}
} // namespace compiler
......
......@@ -301,6 +301,7 @@
V(Float64RoundUp) \
V(Float64RoundTruncate) \
V(Float64RoundTiesAway) \
V(Float64RoundTiesEven) \
V(Float64ExtractLowWord32) \
V(Float64ExtractHighWord32) \
V(Float64InsertLowWord32) \
......
......@@ -1133,6 +1133,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf);
......
......@@ -491,6 +491,9 @@ class RawMachineAssembler {
Node* Float64RoundTiesAway(Node* a) {
return AddNode(machine()->Float64RoundTiesAway().op(), a);
}
Node* Float64RoundTiesEven(Node* a) {
return AddNode(machine()->Float64RoundTiesEven().op(), a);
}
// Float64 bit operations.
Node* Float64ExtractLowWord32(Node* a) {
......
......@@ -2252,6 +2252,12 @@ Type* Typer::Visitor::TypeFloat64RoundTiesAway(Node* node) {
}
Type* Typer::Visitor::TypeFloat64RoundTiesEven(Node* node) {
// TODO(sigurds): We could have a tighter bound here.
return Type::Number();
}
Type* Typer::Visitor::TypeFloat64ExtractLowWord32(Node* node) {
return Type::Signed32();
}
......
......@@ -882,6 +882,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kFloat64RoundUp:
case IrOpcode::kFloat64RoundTruncate:
case IrOpcode::kFloat64RoundTiesAway:
case IrOpcode::kFloat64RoundTiesEven:
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
......
......@@ -1138,6 +1138,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......@@ -1668,7 +1673,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
if (CpuFeatures::IsSupported(SSE4_1)) {
flags |= MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundUp |
MachineOperatorBuilder::kFloat64RoundTruncate;
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesEven;
}
return flags;
}
......
......@@ -864,6 +864,11 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
}
void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
UNREACHABLE();
}
void InstructionSelector::EmitPrepareArguments(NodeVector* arguments,
const CallDescriptor* descriptor,
Node* node) {
......
......@@ -5176,6 +5176,15 @@ TEST(RunFloat64RoundUp) {
}
TEST(RunFloat64RoundTiesEven) {
BufferedRawMachineAssemblerTester<double> m(kMachFloat64);
if (!m.machine()->Float64RoundTiesEven().IsSupported()) return;
m.Return(m.Float64RoundTiesEven(m.Parameter(0)));
FOR_FLOAT64_INPUTS(i) { CheckDoubleEq(nearbyint(*i), m.Call(*i)); }
}
TEST(RunFloat64RoundTruncate) {
BufferedRawMachineAssemblerTester<double> m(kMachFloat64);
if (!m.machine()->Float64RoundTruncate().IsSupported()) return;
......
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