1 //===- DynamicAPInt.h - DynamicAPInt Class ----------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This is a simple class to represent arbitrary precision signed integers.
10 // Unlike APInt, one does not have to specify a fixed maximum size, and the
11 // integer can take on any arbitrary values. This is optimized for small-values
12 // by providing fast-paths for the cases when the value stored fits in 64-bits.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_ADT_DYNAMICAPINT_H
17 #define LLVM_ADT_DYNAMICAPINT_H
18
19 #include "llvm/ADT/APInt.h"
20 #include "llvm/ADT/SlowDynamicAPInt.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/MathExtras.h"
23 #include <numeric>
24
25 namespace llvm {
26
27 class raw_ostream;
28
29 /// This class provides support for dynamic arbitrary-precision arithmetic.
30 ///
31 /// Unlike APInt, this extends the precision as necessary to prevent overflows
32 /// and supports operations between objects with differing internal precisions.
33 ///
34 /// This is optimized for small-values by providing fast-paths for the cases
35 /// when the value stored fits in 64-bits. We annotate all fastpaths by using
36 /// the LLVM_LIKELY/LLVM_UNLIKELY annotations. Removing these would result in
37 /// a 1.2x performance slowdown.
38 ///
39 /// We always_inline all operations; removing these results in a 1.5x
40 /// performance slowdown.
41 ///
42 /// When isLarge returns true, a SlowMPInt is held in the union. If isSmall
43 /// returns true, the int64_t is held. We don't have a separate field for
44 /// indicating this, and instead "steal" memory from ValLarge when it is not in
45 /// use because we know that the memory layout of APInt is such that BitWidth
46 /// doesn't overlap with ValSmall (see static_assert_layout). Using std::variant
47 /// instead would lead to significantly worse performance.
48 class DynamicAPInt {
49 union {
50 int64_t ValSmall;
51 detail::SlowDynamicAPInt ValLarge;
52 };
53
initSmall(int64_t O)54 LLVM_ATTRIBUTE_ALWAYS_INLINE void initSmall(int64_t O) {
55 if (LLVM_UNLIKELY(isLarge()))
56 ValLarge.detail::SlowDynamicAPInt::~SlowDynamicAPInt();
57 ValSmall = O;
58 ValLarge.Val.BitWidth = 0;
59 }
60 LLVM_ATTRIBUTE_ALWAYS_INLINE void
initLarge(const detail::SlowDynamicAPInt & O)61 initLarge(const detail::SlowDynamicAPInt &O) {
62 if (LLVM_LIKELY(isSmall())) {
63 // The data in memory could be in an arbitrary state, not necessarily
64 // corresponding to any valid state of ValLarge; we cannot call any member
65 // functions, e.g. the assignment operator on it, as they may access the
66 // invalid internal state. We instead construct a new object using
67 // placement new.
68 new (&ValLarge) detail::SlowDynamicAPInt(O);
69 } else {
70 // In this case, we need to use the assignment operator, because if we use
71 // placement-new as above we would lose track of allocated memory
72 // and leak it.
73 ValLarge = O;
74 }
75 }
76
DynamicAPInt(const detail::SlowDynamicAPInt & Val)77 LLVM_ATTRIBUTE_ALWAYS_INLINE explicit DynamicAPInt(
78 const detail::SlowDynamicAPInt &Val)
79 : ValLarge(Val) {}
isSmall()80 LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr bool isSmall() const {
81 return ValLarge.Val.BitWidth == 0;
82 }
isLarge()83 LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr bool isLarge() const {
84 return !isSmall();
85 }
86 /// Get the stored value. For getSmall/Large,
87 /// the stored value should be small/large.
getSmall()88 LLVM_ATTRIBUTE_ALWAYS_INLINE int64_t getSmall() const {
89 assert(isSmall() &&
90 "getSmall should only be called when the value stored is small!");
91 return ValSmall;
92 }
getSmall()93 LLVM_ATTRIBUTE_ALWAYS_INLINE int64_t &getSmall() {
94 assert(isSmall() &&
95 "getSmall should only be called when the value stored is small!");
96 return ValSmall;
97 }
98 LLVM_ATTRIBUTE_ALWAYS_INLINE const detail::SlowDynamicAPInt &
getLarge()99 getLarge() const {
100 assert(isLarge() &&
101 "getLarge should only be called when the value stored is large!");
102 return ValLarge;
103 }
getLarge()104 LLVM_ATTRIBUTE_ALWAYS_INLINE detail::SlowDynamicAPInt &getLarge() {
105 assert(isLarge() &&
106 "getLarge should only be called when the value stored is large!");
107 return ValLarge;
108 }
SlowDynamicAPInt()109 explicit operator detail::SlowDynamicAPInt() const {
110 if (isSmall())
111 return detail::SlowDynamicAPInt(getSmall());
112 return getLarge();
113 }
114
115 public:
DynamicAPInt(int64_t Val)116 LLVM_ATTRIBUTE_ALWAYS_INLINE explicit DynamicAPInt(int64_t Val)
117 : ValSmall(Val) {
118 ValLarge.Val.BitWidth = 0;
119 }
DynamicAPInt(const APInt & Val)120 LLVM_ATTRIBUTE_ALWAYS_INLINE explicit DynamicAPInt(const APInt &Val) {
121 if (Val.getBitWidth() <= 64) {
122 ValSmall = Val.getSExtValue();
123 ValLarge.Val.BitWidth = 0;
124 } else {
125 new (&ValLarge) detail::SlowDynamicAPInt(Val);
126 }
127 }
DynamicAPInt()128 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt() : DynamicAPInt(0) {}
~DynamicAPInt()129 LLVM_ATTRIBUTE_ALWAYS_INLINE ~DynamicAPInt() {
130 if (LLVM_UNLIKELY(isLarge()))
131 ValLarge.detail::SlowDynamicAPInt::~SlowDynamicAPInt();
132 }
DynamicAPInt(const DynamicAPInt & O)133 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt(const DynamicAPInt &O)
134 : ValSmall(O.ValSmall) {
135 ValLarge.Val.BitWidth = 0;
136 if (LLVM_UNLIKELY(O.isLarge()))
137 initLarge(O.ValLarge);
138 }
139 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator=(const DynamicAPInt &O) {
140 if (LLVM_LIKELY(O.isSmall())) {
141 initSmall(O.ValSmall);
142 return *this;
143 }
144 initLarge(O.ValLarge);
145 return *this;
146 }
147 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator=(int X) {
148 initSmall(X);
149 return *this;
150 }
int64_t()151 LLVM_ATTRIBUTE_ALWAYS_INLINE explicit operator int64_t() const {
152 if (isSmall())
153 return getSmall();
154 return static_cast<int64_t>(getLarge());
155 }
156
157 bool operator==(const DynamicAPInt &O) const;
158 bool operator!=(const DynamicAPInt &O) const;
159 bool operator>(const DynamicAPInt &O) const;
160 bool operator<(const DynamicAPInt &O) const;
161 bool operator<=(const DynamicAPInt &O) const;
162 bool operator>=(const DynamicAPInt &O) const;
163 DynamicAPInt operator+(const DynamicAPInt &O) const;
164 DynamicAPInt operator-(const DynamicAPInt &O) const;
165 DynamicAPInt operator*(const DynamicAPInt &O) const;
166 DynamicAPInt operator/(const DynamicAPInt &O) const;
167 DynamicAPInt operator%(const DynamicAPInt &O) const;
168 DynamicAPInt &operator+=(const DynamicAPInt &O);
169 DynamicAPInt &operator-=(const DynamicAPInt &O);
170 DynamicAPInt &operator*=(const DynamicAPInt &O);
171 DynamicAPInt &operator/=(const DynamicAPInt &O);
172 DynamicAPInt &operator%=(const DynamicAPInt &O);
173 DynamicAPInt operator-() const;
174 DynamicAPInt &operator++();
175 DynamicAPInt &operator--();
176
177 // Divide by a number that is known to be positive.
178 // This is slightly more efficient because it saves an overflow check.
179 DynamicAPInt divByPositive(const DynamicAPInt &O) const;
180 DynamicAPInt &divByPositiveInPlace(const DynamicAPInt &O);
181
182 friend DynamicAPInt abs(const DynamicAPInt &X);
183 friend DynamicAPInt ceilDiv(const DynamicAPInt &LHS, const DynamicAPInt &RHS);
184 friend DynamicAPInt floorDiv(const DynamicAPInt &LHS,
185 const DynamicAPInt &RHS);
186 // The operands must be non-negative for gcd.
187 friend DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B);
188 friend DynamicAPInt lcm(const DynamicAPInt &A, const DynamicAPInt &B);
189 friend DynamicAPInt mod(const DynamicAPInt &LHS, const DynamicAPInt &RHS);
190
191 /// ---------------------------------------------------------------------------
192 /// Convenience operator overloads for int64_t.
193 /// ---------------------------------------------------------------------------
194 friend DynamicAPInt &operator+=(DynamicAPInt &A, int64_t B);
195 friend DynamicAPInt &operator-=(DynamicAPInt &A, int64_t B);
196 friend DynamicAPInt &operator*=(DynamicAPInt &A, int64_t B);
197 friend DynamicAPInt &operator/=(DynamicAPInt &A, int64_t B);
198 friend DynamicAPInt &operator%=(DynamicAPInt &A, int64_t B);
199
200 friend bool operator==(const DynamicAPInt &A, int64_t B);
201 friend bool operator!=(const DynamicAPInt &A, int64_t B);
202 friend bool operator>(const DynamicAPInt &A, int64_t B);
203 friend bool operator<(const DynamicAPInt &A, int64_t B);
204 friend bool operator<=(const DynamicAPInt &A, int64_t B);
205 friend bool operator>=(const DynamicAPInt &A, int64_t B);
206 friend DynamicAPInt operator+(const DynamicAPInt &A, int64_t B);
207 friend DynamicAPInt operator-(const DynamicAPInt &A, int64_t B);
208 friend DynamicAPInt operator*(const DynamicAPInt &A, int64_t B);
209 friend DynamicAPInt operator/(const DynamicAPInt &A, int64_t B);
210 friend DynamicAPInt operator%(const DynamicAPInt &A, int64_t B);
211
212 friend bool operator==(int64_t A, const DynamicAPInt &B);
213 friend bool operator!=(int64_t A, const DynamicAPInt &B);
214 friend bool operator>(int64_t A, const DynamicAPInt &B);
215 friend bool operator<(int64_t A, const DynamicAPInt &B);
216 friend bool operator<=(int64_t A, const DynamicAPInt &B);
217 friend bool operator>=(int64_t A, const DynamicAPInt &B);
218 friend DynamicAPInt operator+(int64_t A, const DynamicAPInt &B);
219 friend DynamicAPInt operator-(int64_t A, const DynamicAPInt &B);
220 friend DynamicAPInt operator*(int64_t A, const DynamicAPInt &B);
221 friend DynamicAPInt operator/(int64_t A, const DynamicAPInt &B);
222 friend DynamicAPInt operator%(int64_t A, const DynamicAPInt &B);
223
224 LLVM_ABI friend hash_code hash_value(const DynamicAPInt &x); // NOLINT
225
226 LLVM_ABI void static_assert_layout(); // NOLINT
227
228 LLVM_ABI raw_ostream &print(raw_ostream &OS) const;
229
230 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
231 LLVM_DUMP_METHOD void dump() const;
232 #endif
233 };
234
235 inline raw_ostream &operator<<(raw_ostream &OS, const DynamicAPInt &X) {
236 X.print(OS);
237 return OS;
238 }
239
240 /// Redeclarations of friend declaration above to
241 /// make it discoverable by lookups.
242 LLVM_ABI hash_code hash_value(const DynamicAPInt &X); // NOLINT
243
244 /// This just calls through to the operator int64_t, but it's useful when a
245 /// function pointer is required. (Although this is marked inline, it is still
246 /// possible to obtain and use a function pointer to this.)
int64fromDynamicAPInt(const DynamicAPInt & X)247 static inline int64_t int64fromDynamicAPInt(const DynamicAPInt &X) {
248 return int64_t(X);
249 }
dynamicAPIntFromInt64(int64_t X)250 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt dynamicAPIntFromInt64(int64_t X) {
251 return DynamicAPInt(X);
252 }
253
254 // The RHS is always expected to be positive, and the result
255 /// is always non-negative.
256 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt mod(const DynamicAPInt &LHS,
257 const DynamicAPInt &RHS);
258
259 /// We define the operations here in the header to facilitate inlining.
260
261 /// ---------------------------------------------------------------------------
262 /// Comparison operators.
263 /// ---------------------------------------------------------------------------
264 LLVM_ATTRIBUTE_ALWAYS_INLINE bool
265 DynamicAPInt::operator==(const DynamicAPInt &O) const {
266 if (LLVM_LIKELY(isSmall() && O.isSmall()))
267 return getSmall() == O.getSmall();
268 return detail::SlowDynamicAPInt(*this) == detail::SlowDynamicAPInt(O);
269 }
270 LLVM_ATTRIBUTE_ALWAYS_INLINE bool
271 DynamicAPInt::operator!=(const DynamicAPInt &O) const {
272 if (LLVM_LIKELY(isSmall() && O.isSmall()))
273 return getSmall() != O.getSmall();
274 return detail::SlowDynamicAPInt(*this) != detail::SlowDynamicAPInt(O);
275 }
276 LLVM_ATTRIBUTE_ALWAYS_INLINE bool
277 DynamicAPInt::operator>(const DynamicAPInt &O) const {
278 if (LLVM_LIKELY(isSmall() && O.isSmall()))
279 return getSmall() > O.getSmall();
280 return detail::SlowDynamicAPInt(*this) > detail::SlowDynamicAPInt(O);
281 }
282 LLVM_ATTRIBUTE_ALWAYS_INLINE bool
283 DynamicAPInt::operator<(const DynamicAPInt &O) const {
284 if (LLVM_LIKELY(isSmall() && O.isSmall()))
285 return getSmall() < O.getSmall();
286 return detail::SlowDynamicAPInt(*this) < detail::SlowDynamicAPInt(O);
287 }
288 LLVM_ATTRIBUTE_ALWAYS_INLINE bool
289 DynamicAPInt::operator<=(const DynamicAPInt &O) const {
290 if (LLVM_LIKELY(isSmall() && O.isSmall()))
291 return getSmall() <= O.getSmall();
292 return detail::SlowDynamicAPInt(*this) <= detail::SlowDynamicAPInt(O);
293 }
294 LLVM_ATTRIBUTE_ALWAYS_INLINE bool
295 DynamicAPInt::operator>=(const DynamicAPInt &O) const {
296 if (LLVM_LIKELY(isSmall() && O.isSmall()))
297 return getSmall() >= O.getSmall();
298 return detail::SlowDynamicAPInt(*this) >= detail::SlowDynamicAPInt(O);
299 }
300
301 /// ---------------------------------------------------------------------------
302 /// Arithmetic operators.
303 /// ---------------------------------------------------------------------------
304
305 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt
306 DynamicAPInt::operator+(const DynamicAPInt &O) const {
307 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
308 DynamicAPInt Result;
309 bool Overflow = AddOverflow(getSmall(), O.getSmall(), Result.getSmall());
310 if (LLVM_LIKELY(!Overflow))
311 return Result;
312 return DynamicAPInt(detail::SlowDynamicAPInt(*this) +
313 detail::SlowDynamicAPInt(O));
314 }
315 return DynamicAPInt(detail::SlowDynamicAPInt(*this) +
316 detail::SlowDynamicAPInt(O));
317 }
318 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt
319 DynamicAPInt::operator-(const DynamicAPInt &O) const {
320 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
321 DynamicAPInt Result;
322 bool Overflow = SubOverflow(getSmall(), O.getSmall(), Result.getSmall());
323 if (LLVM_LIKELY(!Overflow))
324 return Result;
325 return DynamicAPInt(detail::SlowDynamicAPInt(*this) -
326 detail::SlowDynamicAPInt(O));
327 }
328 return DynamicAPInt(detail::SlowDynamicAPInt(*this) -
329 detail::SlowDynamicAPInt(O));
330 }
331 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt
332 DynamicAPInt::operator*(const DynamicAPInt &O) const {
333 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
334 DynamicAPInt Result;
335 bool Overflow = MulOverflow(getSmall(), O.getSmall(), Result.getSmall());
336 if (LLVM_LIKELY(!Overflow))
337 return Result;
338 return DynamicAPInt(detail::SlowDynamicAPInt(*this) *
339 detail::SlowDynamicAPInt(O));
340 }
341 return DynamicAPInt(detail::SlowDynamicAPInt(*this) *
342 detail::SlowDynamicAPInt(O));
343 }
344
345 // Division overflows only occur when negating the minimal possible value.
346 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt
divByPositive(const DynamicAPInt & O)347 DynamicAPInt::divByPositive(const DynamicAPInt &O) const {
348 assert(O > 0);
349 if (LLVM_LIKELY(isSmall() && O.isSmall()))
350 return DynamicAPInt(getSmall() / O.getSmall());
351 return DynamicAPInt(detail::SlowDynamicAPInt(*this) /
352 detail::SlowDynamicAPInt(O));
353 }
354
355 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt
356 DynamicAPInt::operator/(const DynamicAPInt &O) const {
357 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
358 // Division overflows only occur when negating the minimal possible value.
359 if (LLVM_UNLIKELY(divideSignedWouldOverflow(getSmall(), O.getSmall())))
360 return -*this;
361 return DynamicAPInt(getSmall() / O.getSmall());
362 }
363 return DynamicAPInt(detail::SlowDynamicAPInt(*this) /
364 detail::SlowDynamicAPInt(O));
365 }
366
abs(const DynamicAPInt & X)367 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt abs(const DynamicAPInt &X) {
368 return DynamicAPInt(X >= 0 ? X : -X);
369 }
370 // Division overflows only occur when negating the minimal possible value.
ceilDiv(const DynamicAPInt & LHS,const DynamicAPInt & RHS)371 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt ceilDiv(const DynamicAPInt &LHS,
372 const DynamicAPInt &RHS) {
373 if (LLVM_LIKELY(LHS.isSmall() && RHS.isSmall())) {
374 if (LLVM_UNLIKELY(
375 divideSignedWouldOverflow(LHS.getSmall(), RHS.getSmall())))
376 return -LHS;
377 return DynamicAPInt(divideCeilSigned(LHS.getSmall(), RHS.getSmall()));
378 }
379 return DynamicAPInt(
380 ceilDiv(detail::SlowDynamicAPInt(LHS), detail::SlowDynamicAPInt(RHS)));
381 }
floorDiv(const DynamicAPInt & LHS,const DynamicAPInt & RHS)382 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt floorDiv(const DynamicAPInt &LHS,
383 const DynamicAPInt &RHS) {
384 if (LLVM_LIKELY(LHS.isSmall() && RHS.isSmall())) {
385 if (LLVM_UNLIKELY(
386 divideSignedWouldOverflow(LHS.getSmall(), RHS.getSmall())))
387 return -LHS;
388 return DynamicAPInt(divideFloorSigned(LHS.getSmall(), RHS.getSmall()));
389 }
390 return DynamicAPInt(
391 floorDiv(detail::SlowDynamicAPInt(LHS), detail::SlowDynamicAPInt(RHS)));
392 }
393 // The RHS is always expected to be positive, and the result
394 /// is always non-negative.
mod(const DynamicAPInt & LHS,const DynamicAPInt & RHS)395 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt mod(const DynamicAPInt &LHS,
396 const DynamicAPInt &RHS) {
397 if (LLVM_LIKELY(LHS.isSmall() && RHS.isSmall()))
398 return DynamicAPInt(mod(LHS.getSmall(), RHS.getSmall()));
399 return DynamicAPInt(
400 mod(detail::SlowDynamicAPInt(LHS), detail::SlowDynamicAPInt(RHS)));
401 }
402
gcd(const DynamicAPInt & A,const DynamicAPInt & B)403 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A,
404 const DynamicAPInt &B) {
405 assert(A >= 0 && B >= 0 && "operands must be non-negative!");
406 if (LLVM_LIKELY(A.isSmall() && B.isSmall()))
407 return DynamicAPInt(std::gcd(A.getSmall(), B.getSmall()));
408 return DynamicAPInt(
409 gcd(detail::SlowDynamicAPInt(A), detail::SlowDynamicAPInt(B)));
410 }
411
412 /// Returns the least common multiple of A and B.
lcm(const DynamicAPInt & A,const DynamicAPInt & B)413 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt lcm(const DynamicAPInt &A,
414 const DynamicAPInt &B) {
415 DynamicAPInt X = abs(A);
416 DynamicAPInt Y = abs(B);
417 return (X * Y) / gcd(X, Y);
418 }
419
420 /// This operation cannot overflow.
421 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt
422 DynamicAPInt::operator%(const DynamicAPInt &O) const {
423 if (LLVM_LIKELY(isSmall() && O.isSmall()))
424 return DynamicAPInt(getSmall() % O.getSmall());
425 return DynamicAPInt(detail::SlowDynamicAPInt(*this) %
426 detail::SlowDynamicAPInt(O));
427 }
428
429 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt DynamicAPInt::operator-() const {
430 if (LLVM_LIKELY(isSmall())) {
431 if (LLVM_LIKELY(getSmall() != std::numeric_limits<int64_t>::min()))
432 return DynamicAPInt(-getSmall());
433 return DynamicAPInt(-detail::SlowDynamicAPInt(*this));
434 }
435 return DynamicAPInt(-detail::SlowDynamicAPInt(*this));
436 }
437
438 /// ---------------------------------------------------------------------------
439 /// Assignment operators, preincrement, predecrement.
440 /// ---------------------------------------------------------------------------
441 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &
442 DynamicAPInt::operator+=(const DynamicAPInt &O) {
443 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
444 int64_t Result = getSmall();
445 bool Overflow = AddOverflow(getSmall(), O.getSmall(), Result);
446 if (LLVM_LIKELY(!Overflow)) {
447 getSmall() = Result;
448 return *this;
449 }
450 // Note: this return is not strictly required but
451 // removing it leads to a performance regression.
452 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) +
453 detail::SlowDynamicAPInt(O));
454 }
455 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) +
456 detail::SlowDynamicAPInt(O));
457 }
458 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &
459 DynamicAPInt::operator-=(const DynamicAPInt &O) {
460 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
461 int64_t Result = getSmall();
462 bool Overflow = SubOverflow(getSmall(), O.getSmall(), Result);
463 if (LLVM_LIKELY(!Overflow)) {
464 getSmall() = Result;
465 return *this;
466 }
467 // Note: this return is not strictly required but
468 // removing it leads to a performance regression.
469 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) -
470 detail::SlowDynamicAPInt(O));
471 }
472 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) -
473 detail::SlowDynamicAPInt(O));
474 }
475 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &
476 DynamicAPInt::operator*=(const DynamicAPInt &O) {
477 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
478 int64_t Result = getSmall();
479 bool Overflow = MulOverflow(getSmall(), O.getSmall(), Result);
480 if (LLVM_LIKELY(!Overflow)) {
481 getSmall() = Result;
482 return *this;
483 }
484 // Note: this return is not strictly required but
485 // removing it leads to a performance regression.
486 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) *
487 detail::SlowDynamicAPInt(O));
488 }
489 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) *
490 detail::SlowDynamicAPInt(O));
491 }
492 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &
493 DynamicAPInt::operator/=(const DynamicAPInt &O) {
494 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
495 // Division overflows only occur when negating the minimal possible value.
496 if (LLVM_UNLIKELY(divideSignedWouldOverflow(getSmall(), O.getSmall())))
497 return *this = -*this;
498 getSmall() /= O.getSmall();
499 return *this;
500 }
501 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) /
502 detail::SlowDynamicAPInt(O));
503 }
504
505 // Division overflows only occur when the divisor is -1.
506 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &
divByPositiveInPlace(const DynamicAPInt & O)507 DynamicAPInt::divByPositiveInPlace(const DynamicAPInt &O) {
508 assert(O > 0);
509 if (LLVM_LIKELY(isSmall() && O.isSmall())) {
510 getSmall() /= O.getSmall();
511 return *this;
512 }
513 return *this = DynamicAPInt(detail::SlowDynamicAPInt(*this) /
514 detail::SlowDynamicAPInt(O));
515 }
516
517 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &
518 DynamicAPInt::operator%=(const DynamicAPInt &O) {
519 return *this = *this % O;
520 }
521 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &DynamicAPInt::operator++() {
522 return *this += 1;
523 }
524 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &DynamicAPInt::operator--() {
525 return *this -= 1;
526 }
527
528 /// ----------------------------------------------------------------------------
529 /// Convenience operator overloads for int64_t.
530 /// ----------------------------------------------------------------------------
531 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator+=(DynamicAPInt &A,
532 int64_t B) {
533 return A = A + B;
534 }
535 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator-=(DynamicAPInt &A,
536 int64_t B) {
537 return A = A - B;
538 }
539 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator*=(DynamicAPInt &A,
540 int64_t B) {
541 return A = A * B;
542 }
543 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator/=(DynamicAPInt &A,
544 int64_t B) {
545 return A = A / B;
546 }
547 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt &operator%=(DynamicAPInt &A,
548 int64_t B) {
549 return A = A % B;
550 }
551 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator+(const DynamicAPInt &A,
552 int64_t B) {
553 return A + DynamicAPInt(B);
554 }
555 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator-(const DynamicAPInt &A,
556 int64_t B) {
557 return A - DynamicAPInt(B);
558 }
559 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator*(const DynamicAPInt &A,
560 int64_t B) {
561 return A * DynamicAPInt(B);
562 }
563 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator/(const DynamicAPInt &A,
564 int64_t B) {
565 return A / DynamicAPInt(B);
566 }
567 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator%(const DynamicAPInt &A,
568 int64_t B) {
569 return A % DynamicAPInt(B);
570 }
571 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator+(int64_t A,
572 const DynamicAPInt &B) {
573 return DynamicAPInt(A) + B;
574 }
575 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator-(int64_t A,
576 const DynamicAPInt &B) {
577 return DynamicAPInt(A) - B;
578 }
579 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator*(int64_t A,
580 const DynamicAPInt &B) {
581 return DynamicAPInt(A) * B;
582 }
583 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator/(int64_t A,
584 const DynamicAPInt &B) {
585 return DynamicAPInt(A) / B;
586 }
587 LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator%(int64_t A,
588 const DynamicAPInt &B) {
589 return DynamicAPInt(A) % B;
590 }
591
592 /// We provide special implementations of the comparison operators rather than
593 /// calling through as above, as this would result in a 1.2x slowdown.
594 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator==(const DynamicAPInt &A, int64_t B) {
595 if (LLVM_LIKELY(A.isSmall()))
596 return A.getSmall() == B;
597 return A.getLarge() == B;
598 }
599 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator!=(const DynamicAPInt &A, int64_t B) {
600 if (LLVM_LIKELY(A.isSmall()))
601 return A.getSmall() != B;
602 return A.getLarge() != B;
603 }
604 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator>(const DynamicAPInt &A, int64_t B) {
605 if (LLVM_LIKELY(A.isSmall()))
606 return A.getSmall() > B;
607 return A.getLarge() > B;
608 }
609 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator<(const DynamicAPInt &A, int64_t B) {
610 if (LLVM_LIKELY(A.isSmall()))
611 return A.getSmall() < B;
612 return A.getLarge() < B;
613 }
614 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator<=(const DynamicAPInt &A, int64_t B) {
615 if (LLVM_LIKELY(A.isSmall()))
616 return A.getSmall() <= B;
617 return A.getLarge() <= B;
618 }
619 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator>=(const DynamicAPInt &A, int64_t B) {
620 if (LLVM_LIKELY(A.isSmall()))
621 return A.getSmall() >= B;
622 return A.getLarge() >= B;
623 }
624 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator==(int64_t A, const DynamicAPInt &B) {
625 if (LLVM_LIKELY(B.isSmall()))
626 return A == B.getSmall();
627 return A == B.getLarge();
628 }
629 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator!=(int64_t A, const DynamicAPInt &B) {
630 if (LLVM_LIKELY(B.isSmall()))
631 return A != B.getSmall();
632 return A != B.getLarge();
633 }
634 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator>(int64_t A, const DynamicAPInt &B) {
635 if (LLVM_LIKELY(B.isSmall()))
636 return A > B.getSmall();
637 return A > B.getLarge();
638 }
639 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator<(int64_t A, const DynamicAPInt &B) {
640 if (LLVM_LIKELY(B.isSmall()))
641 return A < B.getSmall();
642 return A < B.getLarge();
643 }
644 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator<=(int64_t A, const DynamicAPInt &B) {
645 if (LLVM_LIKELY(B.isSmall()))
646 return A <= B.getSmall();
647 return A <= B.getLarge();
648 }
649 LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator>=(int64_t A, const DynamicAPInt &B) {
650 if (LLVM_LIKELY(B.isSmall()))
651 return A >= B.getSmall();
652 return A >= B.getLarge();
653 }
654 } // namespace llvm
655
656 #endif // LLVM_ADT_DYNAMICAPINT_H
657