1//===-- llvm/ADT/APSInt.h - Arbitrary Precision Signed Int -----*- 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/// \file
10/// This file implements the APSInt class, which is a simple class that
11/// represents an arbitrary sized integer that knows its signedness.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_APSINT_H
16#define LLVM_ADT_APSINT_H
17
18#include "llvm/ADT/APInt.h"
19
20namespace llvm {
21
22/// An arbitrary precision integer that knows its signedness.
23class [[nodiscard]] APSInt : public APInt {
24  bool IsUnsigned = false;
25
26public:
27  /// Default constructor that creates an uninitialized APInt.
28  explicit APSInt() = default;
29
30  /// Create an APSInt with the specified width, default to unsigned.
31  explicit APSInt(uint32_t BitWidth, bool isUnsigned = true)
32      : APInt(BitWidth, 0), IsUnsigned(isUnsigned) {}
33
34  explicit APSInt(APInt I, bool isUnsigned = true)
35      : APInt(std::move(I)), IsUnsigned(isUnsigned) {}
36
37  /// Construct an APSInt from a string representation.
38  ///
39  /// This constructor interprets the string \p Str using the radix of 10.
40  /// The interpretation stops at the end of the string. The bit width of the
41  /// constructed APSInt is determined automatically.
42  ///
43  /// \param Str the string to be interpreted.
44  explicit APSInt(StringRef Str);
45
46  /// Determine sign of this APSInt.
47  ///
48  /// \returns true if this APSInt is negative, false otherwise
49  bool isNegative() const { return isSigned() && APInt::isNegative(); }
50
51  /// Determine if this APSInt Value is non-negative (>= 0)
52  ///
53  /// \returns true if this APSInt is non-negative, false otherwise
54  bool isNonNegative() const { return !isNegative(); }
55
56  /// Determine if this APSInt Value is positive.
57  ///
58  /// This tests if the value of this APSInt is positive (> 0). Note
59  /// that 0 is not a positive value.
60  ///
61  /// \returns true if this APSInt is positive.
62  bool isStrictlyPositive() const { return isNonNegative() && !isZero(); }
63
64  APSInt &operator=(APInt RHS) {
65    // Retain our current sign.
66    APInt::operator=(std::move(RHS));
67    return *this;
68  }
69
70  APSInt &operator=(uint64_t RHS) {
71    // Retain our current sign.
72    APInt::operator=(RHS);
73    return *this;
74  }
75
76  // Query sign information.
77  bool isSigned() const { return !IsUnsigned; }
78  bool isUnsigned() const { return IsUnsigned; }
79  void setIsUnsigned(bool Val) { IsUnsigned = Val; }
80  void setIsSigned(bool Val) { IsUnsigned = !Val; }
81
82  /// Append this APSInt to the specified SmallString.
83  void toString(SmallVectorImpl<char> &Str, unsigned Radix = 10) const {
84    APInt::toString(Str, Radix, isSigned());
85  }
86  using APInt::toString;
87
88  /// If this int is representable using an int64_t.
89  bool isRepresentableByInt64() const {
90    // For unsigned values with 64 active bits, they technically fit into a
91    // int64_t, but the user may get negative numbers and has to manually cast
92    // them to unsigned. Let's not bet the user has the sanity to do that and
93    // not give them a vague value at the first place.
94    return isSigned() ? isSignedIntN(64) : isIntN(63);
95  }
96
97  /// Get the correctly-extended \c int64_t value.
98  int64_t getExtValue() const {
99    assert(isRepresentableByInt64() && "Too many bits for int64_t");
100    return isSigned() ? getSExtValue() : getZExtValue();
101  }
102
103  std::optional<int64_t> tryExtValue() const {
104    return isRepresentableByInt64() ? std::optional<int64_t>(getExtValue())
105                                    : std::nullopt;
106  }
107
108  APSInt trunc(uint32_t width) const {
109    return APSInt(APInt::trunc(width), IsUnsigned);
110  }
111
112  APSInt extend(uint32_t width) const {
113    if (IsUnsigned)
114      return APSInt(zext(width), IsUnsigned);
115    else
116      return APSInt(sext(width), IsUnsigned);
117  }
118
119  APSInt extOrTrunc(uint32_t width) const {
120    if (IsUnsigned)
121      return APSInt(zextOrTrunc(width), IsUnsigned);
122    else
123      return APSInt(sextOrTrunc(width), IsUnsigned);
124  }
125
126  const APSInt &operator%=(const APSInt &RHS) {
127    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
128    if (IsUnsigned)
129      *this = urem(RHS);
130    else
131      *this = srem(RHS);
132    return *this;
133  }
134  const APSInt &operator/=(const APSInt &RHS) {
135    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
136    if (IsUnsigned)
137      *this = udiv(RHS);
138    else
139      *this = sdiv(RHS);
140    return *this;
141  }
142  APSInt operator%(const APSInt &RHS) const {
143    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
144    return IsUnsigned ? APSInt(urem(RHS), true) : APSInt(srem(RHS), false);
145  }
146  APSInt operator/(const APSInt &RHS) const {
147    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
148    return IsUnsigned ? APSInt(udiv(RHS), true) : APSInt(sdiv(RHS), false);
149  }
150
151  APSInt operator>>(unsigned Amt) const {
152    return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false);
153  }
154  APSInt &operator>>=(unsigned Amt) {
155    if (IsUnsigned)
156      lshrInPlace(Amt);
157    else
158      ashrInPlace(Amt);
159    return *this;
160  }
161  APSInt relativeShr(unsigned Amt) const {
162    return IsUnsigned ? APSInt(relativeLShr(Amt), true)
163                      : APSInt(relativeAShr(Amt), false);
164  }
165
166  inline bool operator<(const APSInt &RHS) const {
167    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
168    return IsUnsigned ? ult(RHS) : slt(RHS);
169  }
170  inline bool operator>(const APSInt &RHS) const {
171    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
172    return IsUnsigned ? ugt(RHS) : sgt(RHS);
173  }
174  inline bool operator<=(const APSInt &RHS) const {
175    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
176    return IsUnsigned ? ule(RHS) : sle(RHS);
177  }
178  inline bool operator>=(const APSInt &RHS) const {
179    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
180    return IsUnsigned ? uge(RHS) : sge(RHS);
181  }
182  inline bool operator==(const APSInt &RHS) const {
183    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
184    return eq(RHS);
185  }
186  inline bool operator!=(const APSInt &RHS) const { return !((*this) == RHS); }
187
188  bool operator==(int64_t RHS) const {
189    return compareValues(*this, get(RHS)) == 0;
190  }
191  bool operator!=(int64_t RHS) const {
192    return compareValues(*this, get(RHS)) != 0;
193  }
194  bool operator<=(int64_t RHS) const {
195    return compareValues(*this, get(RHS)) <= 0;
196  }
197  bool operator>=(int64_t RHS) const {
198    return compareValues(*this, get(RHS)) >= 0;
199  }
200  bool operator<(int64_t RHS) const {
201    return compareValues(*this, get(RHS)) < 0;
202  }
203  bool operator>(int64_t RHS) const {
204    return compareValues(*this, get(RHS)) > 0;
205  }
206
207  // The remaining operators just wrap the logic of APInt, but retain the
208  // signedness information.
209
210  APSInt operator<<(unsigned Bits) const {
211    return APSInt(static_cast<const APInt &>(*this) << Bits, IsUnsigned);
212  }
213  APSInt &operator<<=(unsigned Amt) {
214    static_cast<APInt &>(*this) <<= Amt;
215    return *this;
216  }
217  APSInt relativeShl(unsigned Amt) const {
218    return IsUnsigned ? APSInt(relativeLShl(Amt), true)
219                      : APSInt(relativeAShl(Amt), false);
220  }
221
222  APSInt &operator++() {
223    ++(static_cast<APInt &>(*this));
224    return *this;
225  }
226  APSInt &operator--() {
227    --(static_cast<APInt &>(*this));
228    return *this;
229  }
230  APSInt operator++(int) {
231    return APSInt(++static_cast<APInt &>(*this), IsUnsigned);
232  }
233  APSInt operator--(int) {
234    return APSInt(--static_cast<APInt &>(*this), IsUnsigned);
235  }
236  APSInt operator-() const {
237    return APSInt(-static_cast<const APInt &>(*this), IsUnsigned);
238  }
239  APSInt &operator+=(const APSInt &RHS) {
240    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
241    static_cast<APInt &>(*this) += RHS;
242    return *this;
243  }
244  APSInt &operator-=(const APSInt &RHS) {
245    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
246    static_cast<APInt &>(*this) -= RHS;
247    return *this;
248  }
249  APSInt &operator*=(const APSInt &RHS) {
250    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
251    static_cast<APInt &>(*this) *= RHS;
252    return *this;
253  }
254  APSInt &operator&=(const APSInt &RHS) {
255    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
256    static_cast<APInt &>(*this) &= RHS;
257    return *this;
258  }
259  APSInt &operator|=(const APSInt &RHS) {
260    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
261    static_cast<APInt &>(*this) |= RHS;
262    return *this;
263  }
264  APSInt &operator^=(const APSInt &RHS) {
265    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
266    static_cast<APInt &>(*this) ^= RHS;
267    return *this;
268  }
269
270  APSInt operator&(const APSInt &RHS) const {
271    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
272    return APSInt(static_cast<const APInt &>(*this) & RHS, IsUnsigned);
273  }
274
275  APSInt operator|(const APSInt &RHS) const {
276    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
277    return APSInt(static_cast<const APInt &>(*this) | RHS, IsUnsigned);
278  }
279
280  APSInt operator^(const APSInt &RHS) const {
281    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
282    return APSInt(static_cast<const APInt &>(*this) ^ RHS, IsUnsigned);
283  }
284
285  APSInt operator*(const APSInt &RHS) const {
286    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
287    return APSInt(static_cast<const APInt &>(*this) * RHS, IsUnsigned);
288  }
289  APSInt operator+(const APSInt &RHS) const {
290    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
291    return APSInt(static_cast<const APInt &>(*this) + RHS, IsUnsigned);
292  }
293  APSInt operator-(const APSInt &RHS) const {
294    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
295    return APSInt(static_cast<const APInt &>(*this) - RHS, IsUnsigned);
296  }
297  APSInt operator~() const {
298    return APSInt(~static_cast<const APInt &>(*this), IsUnsigned);
299  }
300
301  /// Return the APSInt representing the maximum integer value with the given
302  /// bit width and signedness.
303  static APSInt getMaxValue(uint32_t numBits, bool Unsigned) {
304    return APSInt(Unsigned ? APInt::getMaxValue(numBits)
305                           : APInt::getSignedMaxValue(numBits),
306                  Unsigned);
307  }
308
309  /// Return the APSInt representing the minimum integer value with the given
310  /// bit width and signedness.
311  static APSInt getMinValue(uint32_t numBits, bool Unsigned) {
312    return APSInt(Unsigned ? APInt::getMinValue(numBits)
313                           : APInt::getSignedMinValue(numBits),
314                  Unsigned);
315  }
316
317  /// Determine if two APSInts have the same value, zero- or
318  /// sign-extending as needed.
319  static bool isSameValue(const APSInt &I1, const APSInt &I2) {
320    return !compareValues(I1, I2);
321  }
322
323  /// Compare underlying values of two numbers.
324  static int compareValues(const APSInt &I1, const APSInt &I2) {
325    if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
326      return I1.IsUnsigned ? I1.compare(I2) : I1.compareSigned(I2);
327
328    // Check for a bit-width mismatch.
329    if (I1.getBitWidth() > I2.getBitWidth())
330      return compareValues(I1, I2.extend(I1.getBitWidth()));
331    if (I2.getBitWidth() > I1.getBitWidth())
332      return compareValues(I1.extend(I2.getBitWidth()), I2);
333
334    // We have a signedness mismatch. Check for negative values and do an
335    // unsigned compare if both are positive.
336    if (I1.isSigned()) {
337      assert(!I2.isSigned() && "Expected signed mismatch");
338      if (I1.isNegative())
339        return -1;
340    } else {
341      assert(I2.isSigned() && "Expected signed mismatch");
342      if (I2.isNegative())
343        return 1;
344    }
345
346    return I1.compare(I2);
347  }
348
349  static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); }
350  static APSInt getUnsigned(uint64_t X) { return APSInt(APInt(64, X), true); }
351
352  /// Used to insert APSInt objects, or objects that contain APSInt objects,
353  /// into FoldingSets.
354  void Profile(FoldingSetNodeID &ID) const;
355};
356
357inline bool operator==(int64_t V1, const APSInt &V2) { return V2 == V1; }
358inline bool operator!=(int64_t V1, const APSInt &V2) { return V2 != V1; }
359inline bool operator<=(int64_t V1, const APSInt &V2) { return V2 >= V1; }
360inline bool operator>=(int64_t V1, const APSInt &V2) { return V2 <= V1; }
361inline bool operator<(int64_t V1, const APSInt &V2) { return V2 > V1; }
362inline bool operator>(int64_t V1, const APSInt &V2) { return V2 < V1; }
363
364inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) {
365  I.print(OS, I.isSigned());
366  return OS;
367}
368
369/// Provide DenseMapInfo for APSInt, using the DenseMapInfo for APInt.
370template <> struct DenseMapInfo<APSInt, void> {
371  static inline APSInt getEmptyKey() {
372    return APSInt(DenseMapInfo<APInt, void>::getEmptyKey());
373  }
374
375  static inline APSInt getTombstoneKey() {
376    return APSInt(DenseMapInfo<APInt, void>::getTombstoneKey());
377  }
378
379  static unsigned getHashValue(const APSInt &Key) {
380    return DenseMapInfo<APInt, void>::getHashValue(Key);
381  }
382
383  static bool isEqual(const APSInt &LHS, const APSInt &RHS) {
384    return LHS.getBitWidth() == RHS.getBitWidth() &&
385           LHS.isUnsigned() == RHS.isUnsigned() && LHS == RHS;
386  }
387};
388
389} // end namespace llvm
390
391#endif
392