Substantially optimize APFloat::toString() by doing a single large divide to

cut the significand down to the desired precision *before* entering the
core divmod loop.  Makes the overall algorithm logarithmic in the exponent.

There's still a lot of room for improvement here, but this gets the
performance back down to acceptable-for-diagnostics levels, even for
long doubles.
negligible, even on long doubles.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@92130 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2009-12-24 12:16:56 +00:00
parent 00e65de9d8
commit 003a09c68d

View File

@ -3223,6 +3223,41 @@ namespace {
append(Buffer, N, Str);
}
/// Removes data from the given significand until it is no more
/// precise than is required for the desired precision.
void AdjustToPrecision(APInt &significand,
int &exp, unsigned FormatPrecision) {
unsigned bits = significand.getActiveBits();
// 196/59 is a very slight overestimate of lg_2(10).
unsigned bitsRequired = (FormatPrecision * 196 + 58) / 59;
if (bits <= bitsRequired) return;
unsigned tensRemovable = (bits - bitsRequired) * 59 / 196;
if (!tensRemovable) return;
exp += tensRemovable;
APInt divisor(significand.getBitWidth(), 1);
APInt powten(significand.getBitWidth(), 10);
while (true) {
if (tensRemovable & 1)
divisor *= powten;
tensRemovable >>= 1;
if (!tensRemovable) break;
powten *= powten;
}
significand = significand.udiv(divisor);
// Truncate the significand down to its active bit count, but
// don't try to drop below 32.
unsigned newPrecision = std::min(32U, significand.getActiveBits());
significand.trunc(newPrecision);
}
void AdjustToPrecision(SmallVectorImpl<char> &buffer,
int &exp, unsigned FormatPrecision) {
unsigned N = buffer.size();
@ -3343,6 +3378,8 @@ void APFloat::toString(SmallVectorImpl<char> &Str,
}
}
AdjustToPrecision(significand, exp, FormatPrecision);
llvm::SmallVector<char, 256> buffer;
// Fill the buffer.