Commit 71348aa2 authored by ahaas's avatar ahaas Committed by Commit bot

[x64] Fixed a rounding error on x64 for the Uint64ToF64 conversion.

The least significant bit of the input value may affect the result of
the conversion through rounding. We OR the least significant with the
second least significant bit to preserve it over the SHR instruction.

R=titzer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#31969}
parent 6df9a1db
......@@ -1038,7 +1038,8 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
} else {
__ movq(kScratchRegister, i.InputOperand(0));
}
__ Cvtqui2sd(i.OutputDoubleRegister(), kScratchRegister);
__ Cvtqui2sd(i.OutputDoubleRegister(), kScratchRegister,
i.TempRegister(0));
break;
case kSSEUint32ToFloat64:
if (instr->InputAt(0)->IsRegister()) {
......
......@@ -973,7 +973,9 @@ void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) {
void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEUint64ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
InstructionOperand temps[] = {g.TempRegister()};
Emit(kSSEUint64ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
arraysize(temps), temps);
}
......
......@@ -899,7 +899,7 @@ void MacroAssembler::Cvtqsi2sd(XMMRegister dst, const Operand& src) {
}
void MacroAssembler::Cvtqui2sd(XMMRegister dst, Register src) {
void MacroAssembler::Cvtqui2sd(XMMRegister dst, Register src, Register tmp) {
Label msb_set_src;
Label jmp_return;
testq(src, src);
......@@ -907,7 +907,11 @@ void MacroAssembler::Cvtqui2sd(XMMRegister dst, Register src) {
Cvtqsi2sd(dst, src);
jmp(&jmp_return, Label::kNear);
bind(&msb_set_src);
movq(tmp, src);
shrq(src, Immediate(1));
// Recover the least significant bit to avoid rounding errors.
andq(tmp, Immediate(1));
orq(src, tmp);
Cvtqsi2sd(dst, src);
addsd(dst, dst);
bind(&jmp_return);
......
......@@ -823,7 +823,7 @@ class MacroAssembler: public Assembler {
void Cvtqsi2sd(XMMRegister dst, Register src);
void Cvtqsi2sd(XMMRegister dst, const Operand& src);
void Cvtqui2sd(XMMRegister dst, Register src);
void Cvtqui2sd(XMMRegister dst, Register src, Register tmp);
void Cvtsd2si(Register dst, XMMRegister src);
......
......@@ -5384,7 +5384,159 @@ TEST(RunRoundInt64ToFloat64) {
TEST(RunRoundUint64ToFloat64) {
BufferedRawMachineAssemblerTester<double> m(kMachUint64);
m.Return(m.RoundUint64ToFloat64(m.Parameter(0)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(static_cast<double>(*i), m.Call(*i)); }
CHECK_EQ(bit_cast<double>(uint64_t(0x0000000000000000)),
m.Call(uint64_t(0x0000000000000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x3ff0000000000000)),
m.Call(uint64_t(0x0000000000000001)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41efffffffe00000)),
m.Call(uint64_t(0x00000000ffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41bb09788b000000)),
m.Call(uint64_t(0x000000001b09788b)));
CHECK_EQ(bit_cast<double>(uint64_t(0x419317f3a0000000)),
m.Call(uint64_t(0x0000000004c5fce8)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41e981bcb7e00000)),
m.Call(uint64_t(0x00000000cc0de5bf)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4000000000000000)),
m.Call(uint64_t(0x0000000000000002)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4008000000000000)),
m.Call(uint64_t(0x0000000000000003)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4010000000000000)),
m.Call(uint64_t(0x0000000000000004)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4014000000000000)),
m.Call(uint64_t(0x0000000000000005)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4020000000000000)),
m.Call(uint64_t(0x0000000000000008)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4022000000000000)),
m.Call(uint64_t(0x0000000000000009)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43f0000000000000)),
m.Call(uint64_t(0xffffffffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43f0000000000000)),
m.Call(uint64_t(0xfffffffffffffffe)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43f0000000000000)),
m.Call(uint64_t(0xfffffffffffffffd)));
CHECK_EQ(bit_cast<double>(uint64_t(0x0000000000000000)),
m.Call(uint64_t(0x0000000000000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41f0000000000000)),
m.Call(uint64_t(0x0000000100000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43efffffffe00000)),
m.Call(uint64_t(0xffffffff00000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43bb09788b000000)),
m.Call(uint64_t(0x1b09788b00000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x439317f3a0000000)),
m.Call(uint64_t(0x04c5fce800000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e981bcb7e00000)),
m.Call(uint64_t(0xcc0de5bf00000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4200000000000000)),
m.Call(uint64_t(0x0000000200000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4208000000000000)),
m.Call(uint64_t(0x0000000300000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4210000000000000)),
m.Call(uint64_t(0x0000000400000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4214000000000000)),
m.Call(uint64_t(0x0000000500000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4220000000000000)),
m.Call(uint64_t(0x0000000800000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4222000000000000)),
m.Call(uint64_t(0x0000000900000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43c39d3cc70c3c9c)),
m.Call(uint64_t(0x273a798e187937a3)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43ed9c75f06a92b4)),
m.Call(uint64_t(0xece3af835495a16b)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43a6cd1d98224467)),
m.Call(uint64_t(0x0b668ecc11223344)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4063c00000000000)),
m.Call(uint64_t(0x000000000000009e)));
CHECK_EQ(bit_cast<double>(uint64_t(0x4050c00000000000)),
m.Call(uint64_t(0x0000000000000043)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40e5ee6000000000)),
m.Call(uint64_t(0x000000000000af73)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40b16b0000000000)),
m.Call(uint64_t(0x000000000000116b)));
CHECK_EQ(bit_cast<double>(uint64_t(0x415963b300000000)),
m.Call(uint64_t(0x0000000000658ecc)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41459da600000000)),
m.Call(uint64_t(0x00000000002b3b4c)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41e10eeccaa00000)),
m.Call(uint64_t(0x0000000088776655)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41dc000000000000)),
m.Call(uint64_t(0x0000000070000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x419c800000000000)),
m.Call(uint64_t(0x0000000007200000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41dfffffffc00000)),
m.Call(uint64_t(0x000000007fffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41d5848dd8400000)),
m.Call(uint64_t(0x0000000056123761)));
CHECK_EQ(bit_cast<double>(uint64_t(0x41dfffffc0000000)),
m.Call(uint64_t(0x000000007fffff00)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43dd8711d87bbbbc)),
m.Call(uint64_t(0x761c4761eeeeeeee)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e00000001dddde)),
m.Call(uint64_t(0x80000000eeeeeeee)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e11111111bbbbc)),
m.Call(uint64_t(0x88888888dddddddd)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e40000001bbbbc)),
m.Call(uint64_t(0xa0000000dddddddd)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43ebbbbbbbb55555)),
m.Call(uint64_t(0xddddddddaaaaaaaa)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43ec000000155555)),
m.Call(uint64_t(0xe0000000aaaaaaaa)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43edddddddddddde)),
m.Call(uint64_t(0xeeeeeeeeeeeeeeee)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43efffffffbdddde)),
m.Call(uint64_t(0xfffffffdeeeeeeee)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43ee0000001bbbbc)),
m.Call(uint64_t(0xf0000000dddddddd)));
CHECK_EQ(bit_cast<double>(uint64_t(0x435ffffff7777777)),
m.Call(uint64_t(0x007fffffdddddddd)));
CHECK_EQ(bit_cast<double>(uint64_t(0x434fffffd5555555)),
m.Call(uint64_t(0x003fffffaaaaaaaa)));
CHECK_EQ(bit_cast<double>(uint64_t(0x433fffffaaaaaaaa)),
m.Call(uint64_t(0x001fffffaaaaaaaa)));
CHECK_EQ(bit_cast<double>(uint64_t(0x412ffffe00000000)),
m.Call(uint64_t(0x00000000000fffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x411ffffc00000000)),
m.Call(uint64_t(0x000000000007ffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x410ffff800000000)),
m.Call(uint64_t(0x000000000003ffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40fffff000000000)),
m.Call(uint64_t(0x000000000001ffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40efffe000000000)),
m.Call(uint64_t(0x000000000000ffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40dfffc000000000)),
m.Call(uint64_t(0x0000000000007fff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40cfff8000000000)),
m.Call(uint64_t(0x0000000000003fff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40bfff0000000000)),
m.Call(uint64_t(0x0000000000001fff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x40affe0000000000)),
m.Call(uint64_t(0x0000000000000fff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x409ffc0000000000)),
m.Call(uint64_t(0x00000000000007ff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x408ff80000000000)),
m.Call(uint64_t(0x00000000000003ff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x407ff00000000000)),
m.Call(uint64_t(0x00000000000001ff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x42cfffffffffff80)),
m.Call(uint64_t(0x00003fffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x42bfffffffffff00)),
m.Call(uint64_t(0x00001fffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x42affffffffffe00)),
m.Call(uint64_t(0x00000fffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x429ffffffffffc00)),
m.Call(uint64_t(0x000007ffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x428ffffffffff800)),
m.Call(uint64_t(0x000003ffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x427ffffffffff000)),
m.Call(uint64_t(0x000001ffffffffff)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e0000010000000)),
m.Call(uint64_t(0x8000008000000000)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e0000010000000)),
m.Call(uint64_t(0x8000008000000001)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e0000000000000)),
m.Call(uint64_t(0x8000000000000400)));
CHECK_EQ(bit_cast<double>(uint64_t(0x43e0000000000001)),
m.Call(uint64_t(0x8000000000000401)));
}
......
......@@ -159,7 +159,9 @@ class ValueHelper {
0x00003fff, 0x00001fff, 0x00000fff,
0x000007ff, 0x000003ff, 0x000001ff,
0x00003fffffffffff, 0x00001fffffffffff, 0x00000fffffffffff,
0x000007ffffffffff, 0x000003ffffffffff, 0x000001ffffffffff};
0x000007ffffffffff, 0x000003ffffffffff, 0x000001ffffffffff,
0x8000008000000000, 0x8000008000000001, 0x8000000000000400,
0x8000000000000401};
return std::vector<uint64_t>(&kValues[0], &kValues[arraysize(kValues)]);
}
......
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