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