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.
This commit is contained in:
parent
90820ddf02
commit
51a3d65e25
1 changed files with 29 additions and 8 deletions
|
@ -612,9 +612,29 @@ let {{
|
||||||
//If we overshot, do nothing. This lets us unrool division loops a
|
//If we overshot, do nothing. This lets us unrool division loops a
|
||||||
//little.
|
//little.
|
||||||
if (remaining) {
|
if (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
|
//Shift in bits from the low order portion of the dividend
|
||||||
while (dividend < divisor && remaining) {
|
while (dividend < divisor && remaining) {
|
||||||
dividend = (dividend << 1) | bits(SrcReg1, remaining - 1);
|
dividend = (dividend << 1) |
|
||||||
|
bits(SrcReg1, remaining - 1);
|
||||||
quotient <<= 1;
|
quotient <<= 1;
|
||||||
remaining--;
|
remaining--;
|
||||||
}
|
}
|
||||||
|
@ -622,6 +642,7 @@ let {{
|
||||||
//Do the division.
|
//Do the division.
|
||||||
divide(dividend, divisor, quotient, remainder);
|
divide(dividend, divisor, quotient, remainder);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//Keep track of how many bits there are still to pull in.
|
//Keep track of how many bits there are still to pull in.
|
||||||
DestReg = merge(DestReg, remaining, dataSize);
|
DestReg = merge(DestReg, remaining, dataSize);
|
||||||
//Record the final results
|
//Record the final results
|
||||||
|
|
Loading…
Reference in a new issue