Commit 2baad44f authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[x64] Move float-to-uint64 conversions to TurboAssembler

Consolidate nearly identical implementations and move them to
TurboAssembler, such that they can be reused for Liftoff.

R=neis@chromium.org

Bug: v8:6600
Change-Id: I197445404df033ac1a05f4aa88501263ae4b75f3
Reviewed-on: https://chromium-review.googlesource.com/1013561
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52634}
parent e3e0f117
......@@ -1545,89 +1545,27 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
break;
case kSSEFloat32ToUint64: {
Label done;
Label success;
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 0);
}
// There does not exist a Float32ToUint64 instruction, so we have to use
// the Float32ToInt64 instruction.
Label fail;
if (instr->OutputCount() > 1) __ Set(i.OutputRegister(1), 0);
if (instr->InputAt(0)->IsFPRegister()) {
__ Cvttss2siq(i.OutputRegister(), i.InputDoubleRegister(0));
__ Cvttss2uiq(i.OutputRegister(), i.InputDoubleRegister(0), &fail);
} else {
__ Cvttss2siq(i.OutputRegister(), i.InputOperand(0));
__ Cvttss2uiq(i.OutputRegister(), i.InputOperand(0), &fail);
}
// Check if the result of the Float32ToInt64 conversion is positive, we
// are already done.
__ testq(i.OutputRegister(), i.OutputRegister());
__ 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.
__ Move(kScratchDoubleReg, -9223372036854775808.0f);
if (instr->InputAt(0)->IsFPRegister()) {
__ 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.
__ Set(kScratchRegister, 0x8000000000000000);
__ orq(i.OutputRegister(), kScratchRegister);
__ bind(&success);
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 1);
}
__ bind(&done);
if (instr->OutputCount() > 1) __ Set(i.OutputRegister(1), 1);
__ bind(&fail);
break;
}
case kSSEFloat64ToUint64: {
Label done;
Label success;
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 0);
}
// There does not exist a Float64ToUint64 instruction, so we have to use
// the Float64ToInt64 instruction.
Label fail;
if (instr->OutputCount() > 1) __ Set(i.OutputRegister(1), 0);
if (instr->InputAt(0)->IsFPRegister()) {
__ Cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
__ Cvttsd2uiq(i.OutputRegister(), i.InputDoubleRegister(0), &fail);
} else {
__ Cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
__ Cvttsd2uiq(i.OutputRegister(), i.InputOperand(0), &fail);
}
// Check if the result of the Float64ToInt64 conversion is positive, we
// are already done.
__ testq(i.OutputRegister(), i.OutputRegister());
__ 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.
__ Move(kScratchDoubleReg, -9223372036854775808.0);
if (instr->InputAt(0)->IsFPRegister()) {
__ 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.
__ Set(kScratchRegister, 0x8000000000000000);
__ orq(i.OutputRegister(), kScratchRegister);
__ bind(&success);
if (instr->OutputCount() > 1) {
__ Set(i.OutputRegister(1), 1);
}
__ bind(&done);
if (instr->OutputCount() > 1) __ Set(i.OutputRegister(1), 1);
__ bind(&fail);
break;
}
case kSSEInt32ToFloat64:
......
......@@ -830,6 +830,62 @@ void TurboAssembler::Cvttsd2siq(Register dst, Operand src) {
}
}
namespace {
template <typename OperandOrXMMRegister, bool is_double>
void ConvertFloatToUint64(TurboAssembler* tasm, Register dst,
OperandOrXMMRegister src, Label* fail) {
Label success;
// There does not exist a native float-to-uint instruction, so we have to use
// a float-to-int, and postprocess the result.
if (is_double) {
tasm->Cvttsd2siq(dst, src);
} else {
tasm->Cvttss2siq(dst, src);
}
// If the result of the conversion is positive, we are already done.
tasm->testq(dst, dst);
tasm->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^63
// and convert it again to see if it is within the uint64 range.
if (is_double) {
tasm->Move(kScratchDoubleReg, -9223372036854775808.0);
tasm->addsd(kScratchDoubleReg, src);
tasm->Cvttsd2siq(dst, kScratchDoubleReg);
} else {
tasm->Move(kScratchDoubleReg, -9223372036854775808.0f);
tasm->addss(kScratchDoubleReg, src);
tasm->Cvttss2siq(dst, kScratchDoubleReg);
}
tasm->testq(dst, dst);
// The only possible negative value here is 0x80000000000000000, which is
// used on x64 to indicate an integer overflow.
tasm->j(negative, fail ? fail : &success);
// The input value is within uint64 range and the second conversion worked
// successfully, but we still have to undo the subtraction we did
// earlier.
tasm->Set(kScratchRegister, 0x8000000000000000);
tasm->orq(dst, kScratchRegister);
tasm->bind(&success);
}
} // namespace
void TurboAssembler::Cvttsd2uiq(Register dst, Operand src, Label* success) {
ConvertFloatToUint64<Operand, true>(this, dst, src, success);
}
void TurboAssembler::Cvttsd2uiq(Register dst, XMMRegister src, Label* success) {
ConvertFloatToUint64<XMMRegister, true>(this, dst, src, success);
}
void TurboAssembler::Cvttss2uiq(Register dst, Operand src, Label* success) {
ConvertFloatToUint64<Operand, false>(this, dst, src, success);
}
void TurboAssembler::Cvttss2uiq(Register dst, XMMRegister src, Label* success) {
ConvertFloatToUint64<XMMRegister, false>(this, dst, src, success);
}
void MacroAssembler::Load(Register dst, Operand src, Representation r) {
DCHECK(!r.IsDouble());
if (r.IsInteger8()) {
......
......@@ -289,6 +289,10 @@ class TurboAssembler : public Assembler {
void Cvtlsi2ss(XMMRegister dst, Operand src);
void Cvtqui2ss(XMMRegister dst, Register src, Register tmp);
void Cvtqui2sd(XMMRegister dst, Register src, Register tmp);
void Cvttsd2uiq(Register dst, Operand src, Label* fail = nullptr);
void Cvttsd2uiq(Register dst, XMMRegister src, Label* fail = nullptr);
void Cvttss2uiq(Register dst, Operand src, Label* fail = nullptr);
void Cvttss2uiq(Register dst, XMMRegister src, Label* fail = nullptr);
// cvtsi2sd instruction only writes to the low 64-bit of dst register, which
// hinders register renaming and makes dependence chains longer. So we use
......
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