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=(that: 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, Signed: 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(N: 64) : isIntN(N: 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(shiftAmt: Amt), true) : APSInt(ashr(ShiftAmt: Amt), false);
153 }
154 APSInt &operator>>=(unsigned Amt) {
155 if (IsUnsigned)
156 lshrInPlace(ShiftAmt: Amt);
157 else
158 ashrInPlace(ShiftAmt: Amt);
159 return *this;
160 }
161 APSInt relativeShr(unsigned Amt) const {
162 return IsUnsigned ? APSInt(relativeLShr(RelativeShift: Amt), true)
163 : APSInt(relativeAShr(RelativeShift: 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(I1: *this, I2: get(X: RHS)) == 0;
190 }
191 bool operator!=(int64_t RHS) const {
192 return compareValues(I1: *this, I2: get(X: RHS)) != 0;
193 }
194 bool operator<=(int64_t RHS) const {
195 return compareValues(I1: *this, I2: get(X: RHS)) <= 0;
196 }
197 bool operator>=(int64_t RHS) const {
198 return compareValues(I1: *this, I2: get(X: RHS)) >= 0;
199 }
200 bool operator<(int64_t RHS) const {
201 return compareValues(I1: *this, I2: get(X: RHS)) < 0;
202 }
203 bool operator>(int64_t RHS) const {
204 return compareValues(I1: *this, I2: get(X: 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(RelativeShift: Amt), true)
219 : APSInt(relativeAShl(RelativeShift: 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(RHS: I2) : I1.compareSigned(RHS: I2);
327
328 // Check for a bit-width mismatch.
329 if (I1.getBitWidth() > I2.getBitWidth())
330 return compareValues(I1, I2: I2.extend(width: I1.getBitWidth()));
331 if (I2.getBitWidth() > I1.getBitWidth())
332 return compareValues(I1: I1.extend(width: 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(RHS: 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, isSigned: 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

source code of llvm/include/llvm/ADT/APSInt.h