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

[turbofan] Change TruncateFloat64ToUint64 to TryTruncateFloatToUint64.

This operator now provides a second output which indicates whether the conversion from float64 to uint64 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 and arm64. @v8-mips-ports and @v8-ppc-ports, can you please take care of the mips64 and ppc64 implementation of the second output?

R=titzer@chromium.org, v8-arm-ports@googlegroups.com

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

Cr-Commit-Position: refs/heads/master@{#32705}
parent 8e771d9b
......@@ -1054,6 +1054,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break;
case kArm64Float64ToUint64:
__ Fcvtzu(i.OutputRegister64(), i.InputDoubleRegister(0));
if (i.OutputCount() > 1) {
__ Fcmp(i.InputDoubleRegister(0), 0.0);
__ Ccmp(i.OutputRegister(0), -1, ZFlag, ge);
__ Cset(i.OutputRegister(1), ne);
}
break;
case kArm64Int32ToFloat64:
__ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
......
......@@ -1264,8 +1264,20 @@ void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
VisitRR(this, kArm64Float64ToUint64, node);
void InstructionSelector::VisitTryTruncateFloat64ToUint64(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(kArm64Float64ToUint64, output_count, outputs, 1, inputs);
}
......
......@@ -832,8 +832,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord64(node), VisitTryTruncateFloat64ToInt64(node);
case IrOpcode::kTruncateFloat32ToUint64:
return MarkAsWord64(node), VisitTruncateFloat32ToUint64(node);
case IrOpcode::kTruncateFloat64ToUint64:
return MarkAsWord64(node), VisitTruncateFloat64ToUint64(node);
case IrOpcode::kTryTruncateFloat64ToUint64:
return MarkAsWord64(node), VisitTryTruncateFloat64ToUint64(node);
case IrOpcode::kChangeInt32ToInt64:
return MarkAsWord64(node), VisitChangeInt32ToInt64(node);
case IrOpcode::kChangeUint32ToUint64:
......@@ -1097,7 +1097,7 @@ void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
UNIMPLEMENTED();
}
......@@ -1209,6 +1209,7 @@ void InstructionSelector::VisitProjection(Node* node) {
case IrOpcode::kInt32AddWithOverflow:
case IrOpcode::kInt32SubWithOverflow:
case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTryTruncateFloat64ToUint64:
if (ProjectionIndexOf(node->op()) == 0u) {
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
} else {
......
......@@ -138,7 +138,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(TruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 1) \
V(TryTruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 2) \
V(TruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 1) \
V(TryTruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 2) \
V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
V(RoundInt64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
V(RoundInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \
......
......@@ -210,7 +210,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* TruncateFloat32ToInt64();
const Operator* TryTruncateFloat64ToInt64();
const Operator* TruncateFloat32ToUint64();
const Operator* TruncateFloat64ToUint64();
const Operator* TryTruncateFloat64ToUint64();
const Operator* ChangeInt32ToFloat64();
const Operator* ChangeInt32ToInt64();
const Operator* ChangeUint32ToFloat64();
......
......@@ -1126,8 +1126,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
}
case kMips64TruncUlD: {
FPURegister scratch = kScratchDoubleReg;
Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
// TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function.
__ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
__ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch,
result);
break;
}
case kMips64BitcastDL:
......
......@@ -876,8 +876,20 @@ void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
VisitRR(this, kMips64TruncUlD, node);
void InstructionSelector::VisitTryTruncateFloat64ToUint64(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);
}
Emit(kMips64TruncUlD, output_count, outputs, 1, inputs);
}
......
......@@ -269,7 +269,7 @@
V(TruncateFloat32ToInt64) \
V(TryTruncateFloat64ToInt64) \
V(TruncateFloat32ToUint64) \
V(TruncateFloat64ToUint64) \
V(TryTruncateFloat64ToUint64) \
V(ChangeInt32ToFloat64) \
V(ChangeInt32ToInt64) \
V(ChangeUint32ToFloat64) \
......
......@@ -946,7 +946,11 @@ void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
if (NodeProperties::FindProjection(node, 1)) {
// TODO(ppc): implement the second return value.
UNIMPLEMENTED();
}
VisitRR(this, kPPC_DoubleToUint64, node);
}
......
......@@ -442,7 +442,12 @@ class RawMachineAssembler {
return AddNode(machine()->TruncateFloat32ToUint64(), a);
}
Node* TruncateFloat64ToUint64(Node* a) {
return AddNode(machine()->TruncateFloat64ToUint64(), a);
// TODO(ahaas): Remove this function as soon as it is not used anymore in
// WebAssembly.
return AddNode(machine()->TryTruncateFloat64ToUint64(), a);
}
Node* TryTruncateFloat64ToUint64(Node* a) {
return AddNode(machine()->TryTruncateFloat64ToUint64(), a);
}
Node* ChangeInt32ToInt64(Node* a) {
return AddNode(machine()->ChangeInt32ToInt64(), a);
......
......@@ -2136,7 +2136,7 @@ Type* Typer::Visitor::TypeTruncateFloat32ToUint64(Node* node) {
}
Type* Typer::Visitor::TypeTruncateFloat64ToUint64(Node* node) {
Type* Typer::Visitor::TypeTryTruncateFloat64ToUint64(Node* node) {
return Type::Internal();
}
......
......@@ -920,7 +920,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kTruncateFloat32ToInt64:
case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTruncateFloat32ToUint64:
case IrOpcode::kTruncateFloat64ToUint64:
case IrOpcode::kTryTruncateFloat64ToUint64:
case IrOpcode::kFloat64ExtractLowWord32:
case IrOpcode::kFloat64ExtractHighWord32:
case IrOpcode::kFloat64InsertLowWord32:
......
......@@ -1106,11 +1106,15 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
} else {
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
}
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 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);
Label success;
__ j(positive, &success);
// 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.
......@@ -1128,9 +1132,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
// 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));
__ Set(kScratchRegister, 0x8000000000000000);
__ orq(i.OutputRegister(), kScratchRegister);
__ bind(&success);
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 1);
}
__ bind(&done);
break;
}
......
......@@ -862,9 +862,19 @@ void InstructionSelector::VisitTruncateFloat32ToUint64(Node* node) {
}
void InstructionSelector::VisitTruncateFloat64ToUint64(Node* node) {
void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat64ToUint64, 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(kSSEFloat64ToUint64, output_count, outputs, 1, inputs);
}
......@@ -1464,8 +1474,6 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
case IrOpcode::kInt32SubWithOverflow:
cont.OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop(this, node, kX64Sub32, &cont);
case IrOpcode::kTryTruncateFloat64ToInt64:
return VisitTryTruncateFloat64ToInt64(result);
default:
break;
}
......
......@@ -1631,8 +1631,8 @@ void MacroAssembler::Trunc_uw_d(FPURegister fd,
}
void MacroAssembler::Trunc_ul_d(FPURegister fd, FPURegister fs,
FPURegister scratch) {
Trunc_ul_d(fs, t8, scratch);
FPURegister scratch, Register result) {
Trunc_ul_d(fs, t8, scratch, result);
dmtc1(t8, fd);
}
......@@ -1698,9 +1698,14 @@ void MacroAssembler::Trunc_uw_d(FPURegister fd,
void MacroAssembler::Trunc_ul_d(FPURegister fd, Register rs,
FPURegister scratch) {
FPURegister scratch, Register result) {
DCHECK(!fd.is(scratch));
DCHECK(!rs.is(at));
DCHECK(!AreAliased(rs, result, at));
if (result.is_valid()) {
mov(result, zero_reg);
Move(kDoubleRegZero, 0.0);
}
// Load 2^63 into scratch as its double representation.
li(at, 0x43e0000000000000);
......@@ -1708,8 +1713,9 @@ void MacroAssembler::Trunc_ul_d(FPURegister fd, Register rs,
// Test if scratch > fd.
// If fd < 2^63 we can convert it normally.
Label simple_convert, done;
BranchF(&simple_convert, NULL, lt, fd, scratch);
// If fd is unordered the conversion fails.
Label simple_convert, done, fail;
BranchF(&simple_convert, &fail, lt, fd, scratch);
// First we subtract 2^63 from fd, then trunc it to rs
// and add 2^63 to rs.
......@@ -1725,6 +1731,13 @@ void MacroAssembler::Trunc_ul_d(FPURegister fd, Register rs,
dmfc1(rs, scratch);
bind(&done);
if (result.is_valid()) {
// Conversion is failed if the result is negative or unordered.
BranchF(&fail, &fail, lt, scratch, kDoubleRegZero);
li(result, Operand(1));
}
bind(&fail);
}
......
......@@ -837,8 +837,10 @@ class MacroAssembler: public Assembler {
void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch);
// Convert double to unsigned long.
void Trunc_ul_d(FPURegister fd, FPURegister fs, FPURegister scratch);
void Trunc_ul_d(FPURegister fd, Register rs, FPURegister scratch);
void Trunc_ul_d(FPURegister fd, FPURegister fs, FPURegister scratch,
Register result = no_reg);
void Trunc_ul_d(FPURegister fd, Register rs, FPURegister scratch,
Register result = no_reg);
// Convert single to unsigned long.
void Trunc_ul_s(FPURegister fd, FPURegister fs, FPURegister scratch);
......
......@@ -5427,7 +5427,7 @@ TEST(RunTryTruncateFloat64ToInt64WithCheck) {
FOR_FLOAT64_INPUTS(i) {
if (*i < 9223372036854775808.0 && *i > -9223372036854775809.0) {
// Conversions within this range
// Conversions within this range should succeed.
CHECK_EQ(static_cast<int64_t>(*i), m.Call(*i));
CHECK_NE(0, success);
} else {
......@@ -5456,7 +5456,7 @@ TEST(RunTruncateFloat32ToUint64) {
}
TEST(RunTruncateFloat64ToUint64) {
TEST(RunTryTruncateFloat64ToUint64WithoutCheck) {
BufferedRawMachineAssemblerTester<uint64_t> m(kMachFloat64);
m.Return(m.TruncateFloat64ToUint64(m.Parameter(0)));
......@@ -5467,10 +5467,26 @@ TEST(RunTruncateFloat64ToUint64) {
CHECK_EQ(static_cast<uint64_t>(input), m.Call(input));
}
}
}
TEST(RunTryTruncateFloat64ToUint64WithCheck) {
int64_t success = 0;
BufferedRawMachineAssemblerTester<int64_t> m(kMachFloat64);
Node* trunc = m.TryTruncateFloat64ToUint64(m.Parameter(0));
Node* val = m.Projection(0, trunc);
Node* check = m.Projection(1, trunc);
m.StoreToPointer(&success, kMachInt64, check);
m.Return(val);
FOR_FLOAT64_INPUTS(i) {
if (*i < 18446744073709551616.0 && *i >= 0) {
// Conversions within this range should succeed.
CHECK_EQ(static_cast<uint64_t>(*i), m.Call(*i));
CHECK_NE(0, success);
} else {
m.Call(*i);
CHECK_EQ(0, success);
}
}
}
......
......@@ -99,13 +99,40 @@ class ValueHelper {
static std::vector<double> float64_vector() {
static const double nan = std::numeric_limits<double>::quiet_NaN();
static const double values[] = {
0.125, 0.25, 0.375, 0.5, 1.25, -1.75, 2, 5.125, 6.25, 0.0, -0.0,
982983.25, 888, 2147483647.0, -999.75, 3.1e7, -2e66, 3e-88,
-2147483648.0, V8_INFINITY, -V8_INFINITY, -nan, nan, 2147483647.375,
2147483647.75, 2147483648.0, 2147483648.25, 2147483649.25,
-2147483647.0, -2147483647.125, -2147483647.875, -2147483648.25,
-2147483649.5};
static const double values[] = {0.125,
0.25,
0.375,
0.5,
1.25,
-1.75,
2,
5.125,
6.25,
0.0,
-0.0,
982983.25,
888,
2147483647.0,
-999.75,
3.1e7,
-2e66,
2e66,
3e-88,
-2147483648.0,
V8_INFINITY,
-V8_INFINITY,
-nan,
nan,
2147483647.375,
2147483647.75,
2147483648.0,
2147483648.25,
2147483649.25,
-2147483647.0,
-2147483647.125,
-2147483647.875,
-2147483648.25,
-2147483649.5};
return std::vector<double>(&values[0], &values[arraysize(values)]);
}
......
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