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