diff options
author | John McCall <rjmccall@apple.com> | 2009-12-24 12:16:56 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-12-24 12:16:56 +0000 |
commit | 003a09c68daa4934b3fe94ba03c7f50f8786310a (patch) | |
tree | 4e0b829ff278bda8a8f080a8e42788a6927ab24d /lib/Support | |
parent | 00e65de9d83f846af732e3ace3f48d43d67b13d1 (diff) | |
download | external_llvm-003a09c68daa4934b3fe94ba03c7f50f8786310a.zip external_llvm-003a09c68daa4934b3fe94ba03c7f50f8786310a.tar.gz external_llvm-003a09c68daa4934b3fe94ba03c7f50f8786310a.tar.bz2 |
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
Diffstat (limited to 'lib/Support')
-rw-r--r-- | lib/Support/APFloat.cpp | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 4426a36..5f748a2 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -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. |