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 LLVM_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) 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=(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, isSigned()); 85 } 86 using APInt::toString; 87 88 /// Get the correctly-extended \c int64_t value. 89 int64_t getExtValue() const { 90 assert(getMinSignedBits() <= 64 && "Too many bits for int64_t"); 91 return isSigned() ? getSExtValue() : getZExtValue(); 92 } 93 94 APSInt trunc(uint32_t width) const { 95 return APSInt(APInt::trunc(width), IsUnsigned); 96 } 97 98 APSInt extend(uint32_t width) const { 99 if (IsUnsigned) 100 return APSInt(zext(width), IsUnsigned); 101 else 102 return APSInt(sext(width), IsUnsigned); 103 } 104 105 APSInt extOrTrunc(uint32_t width) const { 106 if (IsUnsigned) 107 return APSInt(zextOrTrunc(width), IsUnsigned); 108 else 109 return APSInt(sextOrTrunc(width), IsUnsigned); 110 } 111 112 const APSInt &operator%=(const APSInt &RHS) { 113 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 114 if (IsUnsigned) 115 *this = urem(RHS); 116 else 117 *this = srem(RHS); 118 return *this; 119 } 120 const APSInt &operator/=(const APSInt &RHS) { 121 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 122 if (IsUnsigned) 123 *this = udiv(RHS); 124 else 125 *this = sdiv(RHS); 126 return *this; 127 } 128 APSInt operator%(const APSInt &RHS) const { 129 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 130 return IsUnsigned ? APSInt(urem(RHS), true) : APSInt(srem(RHS), false); 131 } 132 APSInt operator/(const APSInt &RHS) const { 133 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 134 return IsUnsigned ? APSInt(udiv(RHS), true) : APSInt(sdiv(RHS), false); 135 } 136 137 APSInt operator>>(unsigned Amt) const { 138 return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false); 139 } 140 APSInt& operator>>=(unsigned Amt) { 141 if (IsUnsigned) 142 lshrInPlace(Amt); 143 else 144 ashrInPlace(Amt); 145 return *this; 146 } 147 148 inline bool operator<(const APSInt& RHS) const { 149 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 150 return IsUnsigned ? ult(RHS) : slt(RHS); 151 } 152 inline bool operator>(const APSInt& RHS) const { 153 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 154 return IsUnsigned ? ugt(RHS) : sgt(RHS); 155 } 156 inline bool operator<=(const APSInt& RHS) const { 157 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 158 return IsUnsigned ? ule(RHS) : sle(RHS); 159 } 160 inline bool operator>=(const APSInt& RHS) const { 161 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 162 return IsUnsigned ? uge(RHS) : sge(RHS); 163 } 164 inline bool operator==(const APSInt& RHS) const { 165 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 166 return eq(RHS); 167 } 168 inline bool operator!=(const APSInt& RHS) const { 169 return !((*this) == RHS); 170 } 171 172 bool operator==(int64_t RHS) const { 173 return compareValues(*this, get(RHS)) == 0; 174 } 175 bool operator!=(int64_t RHS) const { 176 return compareValues(*this, get(RHS)) != 0; 177 } 178 bool operator<=(int64_t RHS) const { 179 return compareValues(*this, get(RHS)) <= 0; 180 } 181 bool operator>=(int64_t RHS) const { 182 return compareValues(*this, get(RHS)) >= 0; 183 } 184 bool operator<(int64_t RHS) const { 185 return compareValues(*this, get(RHS)) < 0; 186 } 187 bool operator>(int64_t RHS) const { 188 return compareValues(*this, get(RHS)) > 0; 189 } 190 191 // The remaining operators just wrap the logic of APInt, but retain the 192 // signedness information. 193 194 APSInt operator<<(unsigned Bits) const { 195 return APSInt(static_cast<const APInt&>(*this) << Bits, IsUnsigned); 196 } 197 APSInt& operator<<=(unsigned Amt) { 198 static_cast<APInt&>(*this) <<= Amt; 199 return *this; 200 } 201 202 APSInt& operator++() { 203 ++(static_cast<APInt&>(*this)); 204 return *this; 205 } 206 APSInt& operator--() { 207 --(static_cast<APInt&>(*this)); 208 return *this; 209 } 210 APSInt operator++(int) { 211 return APSInt(++static_cast<APInt&>(*this), IsUnsigned); 212 } 213 APSInt operator--(int) { 214 return APSInt(--static_cast<APInt&>(*this), IsUnsigned); 215 } 216 APSInt operator-() const { 217 return APSInt(-static_cast<const APInt&>(*this), IsUnsigned); 218 } 219 APSInt& operator+=(const APSInt& RHS) { 220 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 221 static_cast<APInt&>(*this) += RHS; 222 return *this; 223 } 224 APSInt& operator-=(const APSInt& RHS) { 225 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 226 static_cast<APInt&>(*this) -= RHS; 227 return *this; 228 } 229 APSInt& operator*=(const APSInt& RHS) { 230 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 231 static_cast<APInt&>(*this) *= RHS; 232 return *this; 233 } 234 APSInt& operator&=(const APSInt& RHS) { 235 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 236 static_cast<APInt&>(*this) &= RHS; 237 return *this; 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 250 APSInt operator&(const APSInt& RHS) const { 251 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 252 return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned); 253 } 254 255 APSInt operator|(const APSInt& RHS) const { 256 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 257 return APSInt(static_cast<const APInt&>(*this) | RHS, IsUnsigned); 258 } 259 260 APSInt operator^(const APSInt &RHS) const { 261 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 262 return APSInt(static_cast<const APInt&>(*this) ^ RHS, IsUnsigned); 263 } 264 265 APSInt operator*(const APSInt& RHS) const { 266 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 267 return APSInt(static_cast<const APInt&>(*this) * RHS, IsUnsigned); 268 } 269 APSInt operator+(const APSInt& RHS) const { 270 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 271 return APSInt(static_cast<const APInt&>(*this) + RHS, IsUnsigned); 272 } 273 APSInt operator-(const APSInt& RHS) const { 274 assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); 275 return APSInt(static_cast<const APInt&>(*this) - RHS, IsUnsigned); 276 } 277 APSInt operator~() const { 278 return APSInt(~static_cast<const APInt&>(*this), IsUnsigned); 279 } 280 281 /// Return the APSInt representing the maximum integer value with the given 282 /// bit width and signedness. 283 static APSInt getMaxValue(uint32_t numBits, bool Unsigned) { 284 return APSInt(Unsigned ? APInt::getMaxValue(numBits) 285 : APInt::getSignedMaxValue(numBits), Unsigned); 286 } 287 288 /// Return the APSInt representing the minimum integer value with the given 289 /// bit width and signedness. 290 static APSInt getMinValue(uint32_t numBits, bool Unsigned) { 291 return APSInt(Unsigned ? APInt::getMinValue(numBits) 292 : APInt::getSignedMinValue(numBits), Unsigned); 293 } 294 295 /// Determine if two APSInts have the same value, zero- or 296 /// sign-extending as needed. 297 static bool isSameValue(const APSInt &I1, const APSInt &I2) { 298 return !compareValues(I1, I2); 299 } 300 301 /// Compare underlying values of two numbers. 302 static int compareValues(const APSInt &I1, const APSInt &I2) { 303 if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned()) 304 return I1.IsUnsigned ? I1.compare(I2) : I1.compareSigned(I2); 305 306 // Check for a bit-width mismatch. 307 if (I1.getBitWidth() > I2.getBitWidth()) 308 return compareValues(I1, I2.extend(I1.getBitWidth())); 309 if (I2.getBitWidth() > I1.getBitWidth()) 310 return compareValues(I1.extend(I2.getBitWidth()), I2); 311 312 // We have a signedness mismatch. Check for negative values and do an 313 // unsigned compare if both are positive. 314 if (I1.isSigned()) { 315 assert(!I2.isSigned() && "Expected signed mismatch"); 316 if (I1.isNegative()) 317 return -1; 318 } else { 319 assert(I2.isSigned() && "Expected signed mismatch"); 320 if (I2.isNegative()) 321 return 1; 322 } 323 324 return I1.compare(I2); 325 } 326 327 static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); } 328 static APSInt getUnsigned(uint64_t X) { return APSInt(APInt(64, X), true); } 329 330 /// Used to insert APSInt objects, or objects that contain APSInt objects, 331 /// into FoldingSets. 332 void Profile(FoldingSetNodeID& ID) const; 333 }; 334 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 inline bool operator>(int64_t V1, const APSInt &V2) { return V2 < V1; } 341 342 inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) { 343 I.print(OS, I.isSigned()); 344 return OS; 345 } 346 347 /// Provide DenseMapInfo for APSInt, using the DenseMapInfo for APInt. 348 template <> struct DenseMapInfo<APSInt, void> { 349 static inline APSInt getEmptyKey() { 350 return APSInt(DenseMapInfo<APInt, void>::getEmptyKey()); 351 } 352 353 static inline APSInt getTombstoneKey() { 354 return APSInt(DenseMapInfo<APInt, void>::getTombstoneKey()); 355 } 356 357 static unsigned getHashValue(const APSInt &Key) { 358 return DenseMapInfo<APInt, void>::getHashValue(Key); 359 } 360 361 static bool isEqual(const APSInt &LHS, const APSInt &RHS) { 362 return LHS.getBitWidth() == RHS.getBitWidth() && 363 LHS.isUnsigned() == RHS.isUnsigned() && LHS == RHS; 364 } 365 }; 366 367 } // end namespace llvm 368 369 #endif 370