[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}
This commit is contained in:
ahaas 2015-11-12 11:35:47 -08:00 committed by Commit bot
parent 6df9a1db8c
commit 71348aa2a0
6 changed files with 167 additions and 6 deletions

View File

@ -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()) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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)));
}

View File

@ -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)]);
}