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
21namespace llvm {
22
23/// An arbitrary precision integer that knows its signedness.
24class [[nodiscard]] APSInt : public APInt {
25 bool IsUnsigned = false;
26
27public:
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)
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
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
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.
63 bool isStrictlyPositive() const { return isNonNegative() && !isZero(); }
64
65 APSInt &operator=(APInt RHS) {
66 // Retain our current sign.
67 APInt::operator=(that: 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.
78 bool isSigned() const { return !IsUnsigned; }
79 bool isUnsigned() const { return IsUnsigned; }
80 void setIsUnsigned(bool Val) { IsUnsigned = 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, Signed: isSigned());
86 }
87 using APInt::toString;
88
89 /// If this int is representable using an int64_t.
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(N: 64) : isIntN(N: 63);
96 }
97
98 /// Get the correctly-extended \c int64_t value.
99 int64_t getExtValue() const {
100 assert(isRepresentableByInt64() && "Too many bits for int64_t");
101 return isSigned() ? getSExtValue() : getZExtValue();
102 }
103
104 std::optional<int64_t> tryExtValue() const {
105 return isRepresentableByInt64() ? std::optional<int64_t>(getExtValue())
106 : std::nullopt;
107 }
108
109 APSInt trunc(uint32_t width) const {
110 return APSInt(APInt::trunc(width), IsUnsigned);
111 }
112
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
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(shiftAmt: Amt), true) : APSInt(ashr(ShiftAmt: Amt), false);
154 }
155 APSInt &operator>>=(unsigned Amt) {
156 if (IsUnsigned)
157 lshrInPlace(ShiftAmt: Amt);
158 else
159 ashrInPlace(ShiftAmt: Amt);
160 return *this;
161 }
162 APSInt relativeShr(unsigned Amt) const {
163 return IsUnsigned ? APSInt(relativeLShr(RelativeShift: Amt), true)
164 : APSInt(relativeAShr(RelativeShift: 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(I1: *this, I2: get(X: RHS)) == 0;
191 }
192 bool operator!=(int64_t RHS) const {
193 return compareValues(I1: *this, I2: get(X: RHS)) != 0;
194 }
195 bool operator<=(int64_t RHS) const {
196 return compareValues(I1: *this, I2: get(X: RHS)) <= 0;
197 }
198 bool operator>=(int64_t RHS) const {
199 return compareValues(I1: *this, I2: get(X: RHS)) >= 0;
200 }
201 bool operator<(int64_t RHS) const {
202 return compareValues(I1: *this, I2: get(X: RHS)) < 0;
203 }
204 bool operator>(int64_t RHS) const {
205 return compareValues(I1: *this, I2: get(X: 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 }
218 APSInt relativeShl(unsigned Amt) const {
219 return IsUnsigned ? APSInt(relativeLShl(RelativeShift: Amt), true)
220 : APSInt(relativeAShl(RelativeShift: 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.
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.
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.
320 static bool isSameValue(const APSInt &I1, const APSInt &I2) {
321 return !compareValues(I1, I2);
322 }
323
324 /// Compare underlying values of two numbers.
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(RHS: I2) : I1.compareSigned(RHS: I2);
328
329 // Check for a bit-width mismatch.
330 if (I1.getBitWidth() > I2.getBitWidth())
331 return compareValues(I1, I2: I2.extend(width: I1.getBitWidth()));
332 if (I2.getBitWidth() > I1.getBitWidth())
333 return compareValues(I1: I1.extend(width: 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(RHS: I2);
348 }
349
350 static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); }
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
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; }
363inline bool operator>(int64_t V1, const APSInt &V2) { return V2 < V1; }
364
365inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) {
366 I.print(OS, isSigned: I.isSigned());
367 return OS;
368}
369
370/// Provide DenseMapInfo for APSInt, using the DenseMapInfo for APInt.
371template <> 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