aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Support
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2009-12-24 12:16:56 +0000
committerJohn McCall <rjmccall@apple.com>2009-12-24 12:16:56 +0000
commit003a09c68daa4934b3fe94ba03c7f50f8786310a (patch)
tree4e0b829ff278bda8a8f080a8e42788a6927ab24d /lib/Support
parent00e65de9d83f846af732e3ace3f48d43d67b13d1 (diff)
downloadexternal_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.cpp37
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.