X86: Finally fix a division corner case.
authorGabe Black <gblack@eecs.umich.edu>
Sun, 2 May 2010 07:39:29 +0000 (00:39 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Sun, 2 May 2010 07:39:29 +0000 (00:39 -0700)
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

index 0b1f9a96a6bb6f6ed2448b2ca4efaa5aea30a7b8..f3fc1fc59489931fba3c980637961175c95537a3 100644 (file)
@@ -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);