xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/APSInt.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
20 namespace llvm {
21 
22 /// An arbitrary precision integer that knows its signedness.
23 class [[nodiscard]] APSInt : public APInt {
24   bool IsUnsigned = false;
25 
26 public:
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)
APInt(std::move (I))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
isNegative()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
isNonNegative()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.
isStrictlyPositive()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.
isSigned()77   bool isSigned() const { return !IsUnsigned; }
isUnsigned()78   bool isUnsigned() const { return IsUnsigned; }
setIsUnsigned(bool Val)79   void setIsUnsigned(bool Val) { IsUnsigned = Val; }
setIsSigned(bool 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.
isRepresentableByInt64()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.
getExtValue()98   int64_t getExtValue() const {
99     assert(isRepresentableByInt64() && "Too many bits for int64_t");
100     return isSigned() ? getSExtValue() : getZExtValue();
101   }
102 
tryExtValue()103   std::optional<int64_t> tryExtValue() const {
104     return isRepresentableByInt64() ? std::optional<int64_t>(getExtValue())
105                                     : std::nullopt;
106   }
107 
trunc(uint32_t width)108   APSInt trunc(uint32_t width) const {
109     return APSInt(APInt::trunc(width), IsUnsigned);
110   }
111 
extend(uint32_t width)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 
extOrTrunc(uint32_t width)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   }
relativeShr(unsigned Amt)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   }
relativeShl(unsigned Amt)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.
getMaxValue(uint32_t numBits,bool Unsigned)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.
getMinValue(uint32_t numBits,bool Unsigned)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.
isSameValue(const APSInt & I1,const APSInt & I2)319   static bool isSameValue(const APSInt &I1, const APSInt &I2) {
320     return !compareValues(I1, I2);
321   }
322 
323   /// Compare underlying values of two numbers.
compareValues(const APSInt & I1,const APSInt & I2)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 
get(int64_t X)349   static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); }
getUnsigned(uint64_t X)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 
357 inline bool operator==(int64_t V1, const APSInt &V2) { return V2 == V1; }
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 
364 inline 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.
370 template <> 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