1//===- DynamicAPInt.h - DynamicAPInt Class ----------------------*- 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// 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. 14//===----------------------------------------------------------------------===// 16#ifndef LLVM_ADT_DYNAMICAPINT_H 17#define LLVM_ADT_DYNAMICAPINT_H 27/// This class provides support for dynamic arbitrary-precision arithmetic. 29/// Unlike APInt, this extends the precision as necessary to prevent overflows 30/// and supports operations between objects with differing internal precisions. 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. 37/// We always_inline all operations; removing these results in a 1.5x 38/// performance slowdown. 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. 54ValLarge.detail::SlowDynamicAPInt::~SlowDynamicAPInt();
59 initLarge(
const detail::SlowDynamicAPInt &O) {
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 66new (&
ValLarge) detail::SlowDynamicAPInt(O);
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 76const detail::SlowDynamicAPInt &Val)
84 /// Get the stored value. For getSmall/Large, 85 /// the stored value should be small/large. 88"getSmall should only be called when the value stored is small!");
93"getSmall should only be called when the value stored is small!");
99"getLarge should only be called when the value stored is large!");
104"getLarge should only be called when the value stored is large!");
107explicitoperator detail::SlowDynamicAPInt()
const{
109return detail::SlowDynamicAPInt(getSmall());
121ValLarge.detail::SlowDynamicAPInt::~SlowDynamicAPInt();
127 initLarge(O.ValLarge);
131 initSmall(O.ValSmall);
134 initLarge(O.ValLarge);
144returnstatic_cast<int64_t
>(getLarge());
167// Divide by a number that is known to be positive. 168// This is slightly more efficient because it saves an overflow check. 176// The operands must be non-negative for gcd. 181 /// --------------------------------------------------------------------------- 182 /// Convenience operator overloads for int64_t. 183 /// --------------------------------------------------------------------------- 227/// Redeclarations of friend declaration above to 228/// make it discoverable by lookups. 229hash_code
hash_value(
const DynamicAPInt &
X);
// NOLINT 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.) 241// The RHS is always expected to be positive, and the result 242/// is always non-negative. 244const DynamicAPInt &
RHS);
246/// We define the operations here in the header to facilitate inlining. 248/// --------------------------------------------------------------------------- 249/// Comparison operators. 250/// --------------------------------------------------------------------------- 254return getSmall() == O.getSmall();
260return getSmall() != O.getSmall();
266return getSmall() > O.getSmall();
272return getSmall() < O.getSmall();
278return getSmall() <= O.getSmall();
284return getSmall() >= O.getSmall();
288/// --------------------------------------------------------------------------- 289/// Arithmetic operators. 290/// --------------------------------------------------------------------------- 296bool Overflow =
AddOverflow(getSmall(), O.getSmall(), Result.getSmall());
309bool Overflow =
SubOverflow(getSmall(), O.getSmall(), Result.getSmall());
322bool Overflow =
MulOverflow(getSmall(), O.getSmall(), Result.getSmall());
332// Division overflows only occur when negating the minimal possible value. 345// Division overflows only occur when negating the minimal possible value. 357// Division overflows only occur when negating the minimal possible value. 380// The RHS is always expected to be positive, and the result 381/// is always non-negative. 392assert(
A >= 0 &&
B >= 0 &&
"operands must be non-negative!");
399/// Returns the least common multiple of A and B. 407/// This operation cannot overflow. 418if (
LLVM_LIKELY(getSmall() != std::numeric_limits<int64_t>::min()))
425/// --------------------------------------------------------------------------- 426/// Assignment operators, preincrement, predecrement. 427/// --------------------------------------------------------------------------- 431 int64_t Result = getSmall();
432bool Overflow =
AddOverflow(getSmall(), O.getSmall(), Result);
437// Note: this return is not strictly required but 438// removing it leads to a performance regression. 448 int64_t Result = getSmall();
449bool Overflow =
SubOverflow(getSmall(), O.getSmall(), Result);
454// Note: this return is not strictly required but 455// removing it leads to a performance regression. 465 int64_t Result = getSmall();
466bool Overflow =
MulOverflow(getSmall(), O.getSmall(), Result);
471// Note: this return is not strictly required but 472// removing it leads to a performance regression. 482// Division overflows only occur when negating the minimal possible value. 484return *
this = -*
this;
485 getSmall() /= O.getSmall();
492// Division overflows only occur when the divisor is -1. 497 getSmall() /= O.getSmall();
506return *
this = *
this % O;
515/// ---------------------------------------------------------------------------- 516/// Convenience operator overloads for int64_t. 517/// ---------------------------------------------------------------------------- 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. 583returnA.getSmall() ==
B;
584returnA.getLarge() ==
B;
588returnA.getSmall() !=
B;
589returnA.getLarge() !=
B;
593returnA.getSmall() >
B;
594returnA.getLarge() >
B;
598returnA.getSmall() <
B;
599returnA.getLarge() <
B;
603returnA.getSmall() <=
B;
604returnA.getLarge() <=
B;
608returnA.getSmall() >=
B;
609returnA.getLarge() >=
B;
613returnA ==
B.getSmall();
614returnA ==
B.getLarge();
618returnA !=
B.getSmall();
619returnA !=
B.getLarge();
623returnA >
B.getSmall();
624returnA >
B.getLarge();
628returnA <
B.getSmall();
629returnA <
B.getLarge();
633returnA <=
B.getSmall();
634returnA <=
B.getLarge();
638returnA >=
B.getSmall();
639returnA >=
B.getLarge();
643#endif// LLVM_ADT_DYNAMICAPINT_H static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_UNLIKELY(EXPR)
#define LLVM_ATTRIBUTE_ALWAYS_INLINE
LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do so, mark a method "always...
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
#define LLVM_LIKELY(EXPR)
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This class provides support for dynamic arbitrary-precision arithmetic.
friend DynamicAPInt & operator%=(DynamicAPInt &A, int64_t B)
raw_ostream & print(raw_ostream &OS) const
friend bool operator>=(const DynamicAPInt &A, int64_t B)
friend bool operator>(const DynamicAPInt &A, int64_t B)
friend DynamicAPInt ceilDiv(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
friend bool operator!=(const DynamicAPInt &A, int64_t B)
DynamicAPInt & operator--()
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator=(const DynamicAPInt &O)
friend DynamicAPInt abs(const DynamicAPInt &X)
friend DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
friend DynamicAPInt lcm(const DynamicAPInt &A, const DynamicAPInt &B)
Returns the least common multiple of A and B.
friend DynamicAPInt operator+(const DynamicAPInt &A, int64_t B)
friend DynamicAPInt & operator+=(DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt()
friend DynamicAPInt operator/(const DynamicAPInt &A, int64_t B)
friend DynamicAPInt & operator*=(DynamicAPInt &A, int64_t B)
friend DynamicAPInt operator%(const DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator=(int X)
detail::SlowDynamicAPInt ValLarge
friend bool operator<(const DynamicAPInt &A, int64_t B)
void static_assert_layout()
DynamicAPInt divByPositive(const DynamicAPInt &O) const
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt(const DynamicAPInt &O)
friend DynamicAPInt & operator/=(DynamicAPInt &A, int64_t B)
DynamicAPInt operator-() const
LLVM_DUMP_METHOD void dump() const
friend hash_code hash_value(const DynamicAPInt &x)
Redeclarations of friend declaration above to make it discoverable by lookups.
DynamicAPInt & operator++()
friend bool operator<=(const DynamicAPInt &A, int64_t B)
friend DynamicAPInt mod(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
is always non-negative.
friend bool operator==(const DynamicAPInt &A, int64_t B)
We provide special implementations of the comparison operators rather than calling through as above,...
LLVM_ATTRIBUTE_ALWAYS_INLINE ~DynamicAPInt()
friend DynamicAPInt floorDiv(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
friend DynamicAPInt operator*(const DynamicAPInt &A, int64_t B)
friend DynamicAPInt & operator-=(DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt(int64_t Val)
DynamicAPInt & divByPositiveInPlace(const DynamicAPInt &O)
A simple class providing dynamic arbitrary-precision arithmetic.
An opaque object representing a hash code.
This class implements an extremely fast bulk output stream that can only output to a stream.
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
std::enable_if_t< std::is_signed_v< T >, T > MulOverflow(T X, T Y, T &Result)
Multiply two signed integers, computing the two's complement truncated result, returning true if an o...
constexpr bool divideSignedWouldOverflow(U Numerator, V Denominator)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt mod(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
is always non-negative.
hash_code hash_value(const FixedPointSemantics &Val)
APInt operator*(APInt a, uint64_t RHS)
APFloat abs(APFloat X)
Returns the absolute value of the argument.
constexpr T divideFloorSigned(U Numerator, V Denominator)
Returns the integer floor(Numerator / Denominator).
bool operator!=(uint64_t V1, const APInt &V2)
bool operator>=(int64_t V1, const APSInt &V2)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator+=(DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator-=(DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt floorDiv(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator%(const DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator*=(DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator/=(DynamicAPInt &A, int64_t B)
bool operator>(int64_t V1, const APSInt &V2)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt ceilDiv(const DynamicAPInt &LHS, const DynamicAPInt &RHS)
static int64_t int64fromDynamicAPInt(const DynamicAPInt &X)
This just calls through to the operator int64_t, but it's useful when a function pointer is required.
constexpr T divideCeilSigned(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt lcm(const DynamicAPInt &A, const DynamicAPInt &B)
Returns the least common multiple of A and B.
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt dynamicAPIntFromInt64(int64_t X)
std::enable_if_t< std::is_signed_v< T >, T > AddOverflow(T X, T Y, T &Result)
Add two signed integers, computing the two's complement truncated result, returning true if overflow ...
APInt operator+(APInt a, const APInt &b)
std::enable_if_t< std::is_signed_v< T >, T > SubOverflow(T X, T Y, T &Result)
Subtract two signed integers, computing the two's complement truncated result, returning true if an o...
bool operator<=(int64_t V1, const APSInt &V2)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator%=(DynamicAPInt &A, int64_t B)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt operator/(const DynamicAPInt &A, int64_t B)