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