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