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