summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2010-05-02 00:39:29 -0700
committerGabe Black <gblack@eecs.umich.edu>2010-05-02 00:39:29 -0700
commit51a3d65e259fc30662ecfdac9bf7ca0068fa7da6 (patch)
tree0e209989d9e24aad2a49250db71ad2c127e6a3b4
parent90820ddf022aab7820297318555402b4bc41ed04 (diff)
downloadgem5-51a3d65e259fc30662ecfdac9bf7ca0068fa7da6.tar.xz
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.
-rw-r--r--src/arch/x86/isa/microops/regop.isa37
1 files 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);