mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-25 13:24:46 +00:00
Support: Write ScaledNumber::getQuotient() and getProduct()
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211409 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -216,97 +216,6 @@ void UnsignedFloatBase::dump(uint64_t D, int16_t E, int Width) {
|
||||
<< "]";
|
||||
}
|
||||
|
||||
static std::pair<uint64_t, int16_t>
|
||||
getRoundedFloat(uint64_t N, bool ShouldRound, int64_t Shift) {
|
||||
if (ShouldRound)
|
||||
if (!++N)
|
||||
// Rounding caused an overflow.
|
||||
return std::make_pair(UINT64_C(1), Shift + 64);
|
||||
return std::make_pair(N, Shift);
|
||||
}
|
||||
|
||||
std::pair<uint64_t, int16_t> UnsignedFloatBase::divide64(uint64_t Dividend,
|
||||
uint64_t Divisor) {
|
||||
// Input should be sanitized.
|
||||
assert(Divisor);
|
||||
assert(Dividend);
|
||||
|
||||
// Minimize size of divisor.
|
||||
int16_t Shift = 0;
|
||||
if (int Zeros = countTrailingZeros(Divisor)) {
|
||||
Shift -= Zeros;
|
||||
Divisor >>= Zeros;
|
||||
}
|
||||
|
||||
// Check for powers of two.
|
||||
if (Divisor == 1)
|
||||
return std::make_pair(Dividend, Shift);
|
||||
|
||||
// Maximize size of dividend.
|
||||
if (int Zeros = countLeadingZeros64(Dividend)) {
|
||||
Shift -= Zeros;
|
||||
Dividend <<= Zeros;
|
||||
}
|
||||
|
||||
// Start with the result of a divide.
|
||||
uint64_t Quotient = Dividend / Divisor;
|
||||
Dividend %= Divisor;
|
||||
|
||||
// Continue building the quotient with long division.
|
||||
//
|
||||
// TODO: continue with largers digits.
|
||||
while (!(Quotient >> 63) && Dividend) {
|
||||
// Shift Dividend, and check for overflow.
|
||||
bool IsOverflow = Dividend >> 63;
|
||||
Dividend <<= 1;
|
||||
--Shift;
|
||||
|
||||
// Divide.
|
||||
bool DoesDivide = IsOverflow || Divisor <= Dividend;
|
||||
Quotient = (Quotient << 1) | uint64_t(DoesDivide);
|
||||
Dividend -= DoesDivide ? Divisor : 0;
|
||||
}
|
||||
|
||||
// Round.
|
||||
if (Dividend >= getHalf(Divisor))
|
||||
if (!++Quotient)
|
||||
// Rounding caused an overflow in Quotient.
|
||||
return std::make_pair(UINT64_C(1), Shift + 64);
|
||||
|
||||
return getRoundedFloat(Quotient, Dividend >= getHalf(Divisor), Shift);
|
||||
}
|
||||
|
||||
std::pair<uint64_t, int16_t> UnsignedFloatBase::multiply64(uint64_t L,
|
||||
uint64_t R) {
|
||||
// Separate into two 32-bit digits (U.L).
|
||||
uint64_t UL = L >> 32, LL = L & UINT32_MAX, UR = R >> 32, LR = R & UINT32_MAX;
|
||||
|
||||
// Compute cross products.
|
||||
uint64_t P1 = UL * UR, P2 = UL * LR, P3 = LL * UR, P4 = LL * LR;
|
||||
|
||||
// Sum into two 64-bit digits.
|
||||
uint64_t Upper = P1, Lower = P4;
|
||||
auto addWithCarry = [&](uint64_t N) {
|
||||
uint64_t NewLower = Lower + (N << 32);
|
||||
Upper += (N >> 32) + (NewLower < Lower);
|
||||
Lower = NewLower;
|
||||
};
|
||||
addWithCarry(P2);
|
||||
addWithCarry(P3);
|
||||
|
||||
// Check whether the upper digit is empty.
|
||||
if (!Upper)
|
||||
return std::make_pair(Lower, 0);
|
||||
|
||||
// Shift as little as possible to maximize precision.
|
||||
unsigned LeadingZeros = countLeadingZeros64(Upper);
|
||||
int16_t Shift = 64 - LeadingZeros;
|
||||
if (LeadingZeros)
|
||||
Upper = Upper << LeadingZeros | Lower >> Shift;
|
||||
bool ShouldRound = Shift && (Lower & UINT64_C(1) << (Shift - 1));
|
||||
return getRoundedFloat(Upper, ShouldRound, Shift);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// BlockMass implementation.
|
||||
|
Reference in New Issue
Block a user