1 //==- lib/Support/ScaledNumber.cpp - Support for scaled numbers -*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Implementation of some scaled number algorithms.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Support/ScaledNumber.h"
14 #include "llvm/ADT/APFloat.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/raw_ostream.h"
20 using namespace llvm::ScaledNumbers
;
22 std::pair
<uint64_t, int16_t> ScaledNumbers::multiply64(uint64_t LHS
,
24 // Separate into two 32-bit digits (U.L).
25 auto getU
= [](uint64_t N
) { return N
>> 32; };
26 auto getL
= [](uint64_t N
) { return N
& UINT32_MAX
; };
27 uint64_t UL
= getU(LHS
), LL
= getL(LHS
), UR
= getU(RHS
), LR
= getL(RHS
);
29 // Compute cross products.
30 uint64_t P1
= UL
* UR
, P2
= UL
* LR
, P3
= LL
* UR
, P4
= LL
* LR
;
32 // Sum into two 64-bit digits.
33 uint64_t Upper
= P1
, Lower
= P4
;
34 auto addWithCarry
= [&](uint64_t N
) {
35 uint64_t NewLower
= Lower
+ (getL(N
) << 32);
36 Upper
+= getU(N
) + (NewLower
< Lower
);
42 // Check whether the upper digit is empty.
44 return std::make_pair(Lower
, 0);
46 // Shift as little as possible to maximize precision.
47 unsigned LeadingZeros
= countLeadingZeros(Upper
);
48 int Shift
= 64 - LeadingZeros
;
50 Upper
= Upper
<< LeadingZeros
| Lower
>> Shift
;
51 return getRounded(Upper
, Shift
,
52 Shift
&& (Lower
& UINT64_C(1) << (Shift
- 1)));
55 static uint64_t getHalf(uint64_t N
) { return (N
>> 1) + (N
& 1); }
57 std::pair
<uint32_t, int16_t> ScaledNumbers::divide32(uint32_t Dividend
,
59 assert(Dividend
&& "expected non-zero dividend");
60 assert(Divisor
&& "expected non-zero divisor");
62 // Use 64-bit math and canonicalize the dividend to gain precision.
63 uint64_t Dividend64
= Dividend
;
65 if (int Zeros
= countLeadingZeros(Dividend64
)) {
69 uint64_t Quotient
= Dividend64
/ Divisor
;
70 uint64_t Remainder
= Dividend64
% Divisor
;
72 // If Quotient needs to be shifted, leave the rounding to getAdjusted().
73 if (Quotient
> UINT32_MAX
)
74 return getAdjusted
<uint32_t>(Quotient
, Shift
);
76 // Round based on the value of the next bit.
77 return getRounded
<uint32_t>(Quotient
, Shift
, Remainder
>= getHalf(Divisor
));
80 std::pair
<uint64_t, int16_t> ScaledNumbers::divide64(uint64_t Dividend
,
82 assert(Dividend
&& "expected non-zero dividend");
83 assert(Divisor
&& "expected non-zero divisor");
85 // Minimize size of divisor.
87 if (int Zeros
= countTrailingZeros(Divisor
)) {
92 // Check for powers of two.
94 return std::make_pair(Dividend
, Shift
);
96 // Maximize size of dividend.
97 if (int Zeros
= countLeadingZeros(Dividend
)) {
102 // Start with the result of a divide.
103 uint64_t Quotient
= Dividend
/ Divisor
;
106 // Continue building the quotient with long division.
107 while (!(Quotient
>> 63) && Dividend
) {
108 // Shift Dividend and check for overflow.
109 bool IsOverflow
= Dividend
>> 63;
113 // Get the next bit of Quotient.
115 if (IsOverflow
|| Divisor
<= Dividend
) {
121 return getRounded(Quotient
, Shift
, Dividend
>= getHalf(Divisor
));
124 int ScaledNumbers::compareImpl(uint64_t L
, uint64_t R
, int ScaleDiff
) {
125 assert(ScaleDiff
>= 0 && "wrong argument order");
126 assert(ScaleDiff
< 64 && "numbers too far apart");
128 uint64_t L_adjusted
= L
>> ScaleDiff
;
134 return L
> L_adjusted
<< ScaleDiff
? 1 : 0;
137 static void appendDigit(std::string
&Str
, unsigned D
) {
142 static void appendNumber(std::string
&Str
, uint64_t N
) {
144 appendDigit(Str
, N
% 10);
149 static bool doesRoundUp(char Digit
) {
162 static std::string
toStringAPFloat(uint64_t D
, int E
, unsigned Precision
) {
163 assert(E
>= ScaledNumbers::MinScale
);
164 assert(E
<= ScaledNumbers::MaxScale
);
166 // Find a new E, but don't let it increase past MaxScale.
167 int LeadingZeros
= ScaledNumberBase::countLeadingZeros64(D
);
168 int NewE
= std::min(ScaledNumbers::MaxScale
, E
+ 63 - LeadingZeros
);
169 int Shift
= 63 - (NewE
- E
);
170 assert(Shift
<= LeadingZeros
);
171 assert(Shift
== LeadingZeros
|| NewE
== ScaledNumbers::MaxScale
);
172 assert(Shift
>= 0 && Shift
< 64 && "undefined behavior");
176 // Check for a denormal.
177 unsigned AdjustedE
= E
+ 16383;
179 assert(E
== ScaledNumbers::MaxScale
);
183 // Build the float and print it.
184 uint64_t RawBits
[2] = {D
, AdjustedE
};
185 APFloat
Float(APFloat::x87DoubleExtended(), APInt(80, RawBits
));
186 SmallVector
<char, 24> Chars
;
187 Float
.toString(Chars
, Precision
, 0);
188 return std::string(Chars
.begin(), Chars
.end());
191 static std::string
stripTrailingZeros(const std::string
&Float
) {
192 size_t NonZero
= Float
.find_last_not_of('0');
193 assert(NonZero
!= std::string::npos
&& "no . in floating point string");
195 if (Float
[NonZero
] == '.')
198 return Float
.substr(0, NonZero
+ 1);
201 std::string
ScaledNumberBase::toString(uint64_t D
, int16_t E
, int Width
,
202 unsigned Precision
) {
206 // Canonicalize exponent and digits.
214 if (int Shift
= std::min(int16_t(countLeadingZeros64(D
)), E
)) {
221 } else if (E
> -64) {
223 Below0
= D
<< (64 + E
);
224 } else if (E
== -64) {
225 // Special case: shift by 64 bits is undefined behavior.
227 } else if (E
> -120) {
228 Below0
= D
>> (-E
- 64);
229 Extra
= D
<< (128 + E
);
230 ExtraShift
= -64 - E
;
233 // Fall back on APFloat for very small and very large numbers.
234 if (!Above0
&& !Below0
)
235 return toStringAPFloat(D
, E
, Precision
);
237 // Append the digits before the decimal.
239 size_t DigitsOut
= 0;
241 appendNumber(Str
, Above0
);
242 DigitsOut
= Str
.size();
245 std::reverse(Str
.begin(), Str
.end());
247 // Return early if there's nothing after the decimal.
251 // Append the decimal and beyond.
253 uint64_t Error
= UINT64_C(1) << (64 - Width
);
255 // We need to shift Below0 to the right to make space for calculating
256 // digits. Save the precision we're losing in Extra.
257 Extra
= (Below0
& 0xf) << 56 | (Extra
>> 8);
260 size_t AfterDot
= Str
.size();
270 Below0
+= (Extra
>> 60);
271 Extra
= Extra
& (UINT64_MAX
>> 4);
272 appendDigit(Str
, Below0
>> 60);
273 Below0
= Below0
& (UINT64_MAX
>> 4);
274 if (DigitsOut
|| Str
.back() != '0')
277 } while (Error
&& (Below0
<< 4 | Extra
>> 60) >= Error
/ 2 &&
278 (!Precision
|| DigitsOut
<= Precision
|| SinceDot
< 2));
280 // Return early for maximum precision.
281 if (!Precision
|| DigitsOut
<= Precision
)
282 return stripTrailingZeros(Str
);
284 // Find where to truncate.
286 std::max(Str
.size() - (DigitsOut
- Precision
), AfterDot
+ 1);
288 // Check if there's anything to truncate.
289 if (Truncate
>= Str
.size())
290 return stripTrailingZeros(Str
);
292 bool Carry
= doesRoundUp(Str
[Truncate
]);
294 return stripTrailingZeros(Str
.substr(0, Truncate
));
296 // Round with the first truncated digit.
297 for (std::string::reverse_iterator
I(Str
.begin() + Truncate
), E
= Str
.rend();
311 // Add "1" in front if we still need to carry.
312 return stripTrailingZeros(std::string(Carry
, '1') + Str
.substr(0, Truncate
));
315 raw_ostream
&ScaledNumberBase::print(raw_ostream
&OS
, uint64_t D
, int16_t E
,
316 int Width
, unsigned Precision
) {
317 return OS
<< toString(D
, E
, Width
, Precision
);
320 void ScaledNumberBase::dump(uint64_t D
, int16_t E
, int Width
) {
321 print(dbgs(), D
, E
, Width
, 0) << "[" << Width
<< ":" << D
<< "*2^" << E