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