From 51a3d65e259fc30662ecfdac9bf7ca0068fa7da6 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 2 May 2010 00:39:29 -0700 Subject: X86: Finally fix a division corner case. When doing an unsigned 64 bit division with a divisor that has its most significant bit set, the division code would spill a bit off of the end of a uint64_t trying to shift the dividend into position. This change adds code that handles that case specially by purposefully letting it spill and then going ahead assuming there was a 65th one bit. --- src/arch/x86/isa/microops/regop.isa | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index 0b1f9a96a..f3fc1fc59 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -612,15 +612,36 @@ let {{ //If we overshot, do nothing. This lets us unrool division loops a //little. if (remaining) { - //Shift in bits from the low order portion of the dividend - while(dividend < divisor && remaining) { - dividend = (dividend << 1) | bits(SrcReg1, remaining - 1); - quotient <<= 1; - remaining--; + if (divisor & (ULL(1) << 63)) { + while (remaining && !(dividend & (ULL(1) << 63))) { + dividend = (dividend << 1) | + bits(SrcReg1, remaining - 1); + quotient <<= 1; + remaining--; + } + if (dividend & (ULL(1) << 63)) { + if (dividend < divisor && remaining) { + dividend = (dividend << 1) | + bits(SrcReg1, remaining - 1); + quotient <<= 1; + remaining--; + } + quotient++; + dividend -= divisor; + } + remainder = dividend; + } else { + //Shift in bits from the low order portion of the dividend + while (dividend < divisor && remaining) { + dividend = (dividend << 1) | + bits(SrcReg1, remaining - 1); + quotient <<= 1; + remaining--; + } + remainder = dividend; + //Do the division. + divide(dividend, divisor, quotient, remainder); } - remainder = dividend; - //Do the division. - divide(dividend, divisor, quotient, remainder); } //Keep track of how many bits there are still to pull in. DestReg = merge(DestReg, remaining, dataSize); -- cgit v1.2.3