1//===-- llvm/ADT/APSInt.h - Arbitrary Precision Signed Int -----*- C++ -*--===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
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
22class APSInt : public APInt {
23  bool IsUnsigned;
24public:
25  /// Default constructor that creates an uninitialized APInt.
26  explicit APSInt() : IsUnsigned(false) {}
27
28  /// APSInt ctor - Create an APSInt with the specified width, default to
29  /// unsigned.
30  explicit APSInt(uint32_t BitWidth, bool isUnsigned = true)
31   : APInt(BitWidth, 0), IsUnsigned(isUnsigned) {}
32
33  explicit APSInt(APInt I, bool isUnsigned = true)
34   : APInt(std::move(I)), IsUnsigned(isUnsigned) {}
35
36  APSInt &operator=(APInt RHS) {
37    // Retain our current sign.
38    APInt::operator=(std::move(RHS));
39    return *this;
40  }
41
42  APSInt &operator=(uint64_t RHS) {
43    // Retain our current sign.
44    APInt::operator=(RHS);
45    return *this;
46  }
47
48  // Query sign information.
49  bool isSigned() const { return !IsUnsigned; }
50  bool isUnsigned() const { return IsUnsigned; }
51  void setIsUnsigned(bool Val) { IsUnsigned = Val; }
52  void setIsSigned(bool Val) { IsUnsigned = !Val; }
53
54  /// toString - Append this APSInt to the specified SmallString.
55  void toString(SmallVectorImpl<char> &Str, unsigned Radix = 10) const {
56    APInt::toString(Str, Radix, isSigned());
57  }
58  /// toString - Converts an APInt to a std::string.  This is an inefficient
59  /// method; you should prefer passing in a SmallString instead.
60  std::string toString(unsigned Radix) const {
61    return APInt::toString(Radix, isSigned());
62  }
63  using APInt::toString;
64
65  APSInt LLVM_ATTRIBUTE_UNUSED_RESULT trunc(uint32_t width) const {
66    return APSInt(APInt::trunc(width), IsUnsigned);
67  }
68
69  APSInt LLVM_ATTRIBUTE_UNUSED_RESULT extend(uint32_t width) const {
70    if (IsUnsigned)
71      return APSInt(zext(width), IsUnsigned);
72    else
73      return APSInt(sext(width), IsUnsigned);
74  }
75
76  APSInt LLVM_ATTRIBUTE_UNUSED_RESULT extOrTrunc(uint32_t width) const {
77      if (IsUnsigned)
78        return APSInt(zextOrTrunc(width), IsUnsigned);
79      else
80        return APSInt(sextOrTrunc(width), IsUnsigned);
81  }
82
83  const APSInt &operator%=(const APSInt &RHS) {
84    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
85    if (IsUnsigned)
86      *this = urem(RHS);
87    else
88      *this = srem(RHS);
89    return *this;
90  }
91  const APSInt &operator/=(const APSInt &RHS) {
92    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
93    if (IsUnsigned)
94      *this = udiv(RHS);
95    else
96      *this = sdiv(RHS);
97    return *this;
98  }
99  APSInt operator%(const APSInt &RHS) const {
100    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
101    return IsUnsigned ? APSInt(urem(RHS), true) : APSInt(srem(RHS), false);
102  }
103  APSInt operator/(const APSInt &RHS) const {
104    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
105    return IsUnsigned ? APSInt(udiv(RHS), true) : APSInt(sdiv(RHS), false);
106  }
107
108  APSInt operator>>(unsigned Amt) const {
109    return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false);
110  }
111  APSInt& operator>>=(unsigned Amt) {
112    *this = *this >> Amt;
113    return *this;
114  }
115
116  inline bool operator<(const APSInt& RHS) const {
117    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
118    return IsUnsigned ? ult(RHS) : slt(RHS);
119  }
120  inline bool operator>(const APSInt& RHS) const {
121    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
122    return IsUnsigned ? ugt(RHS) : sgt(RHS);
123  }
124  inline bool operator<=(const APSInt& RHS) const {
125    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
126    return IsUnsigned ? ule(RHS) : sle(RHS);
127  }
128  inline bool operator>=(const APSInt& RHS) const {
129    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
130    return IsUnsigned ? uge(RHS) : sge(RHS);
131  }
132  inline bool operator==(const APSInt& RHS) const {
133    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
134    return eq(RHS);
135  }
136  inline bool operator==(int64_t RHS) const {
137    return isSameValue(*this, APSInt(APInt(64, RHS), true));
138  }
139  inline bool operator!=(const APSInt& RHS) const {
140    return !((*this) == RHS);
141  }
142  inline bool operator!=(int64_t RHS) const {
143    return !((*this) == RHS);
144  }
145
146  // The remaining operators just wrap the logic of APInt, but retain the
147  // signedness information.
148
149  APSInt operator<<(unsigned Bits) const {
150    return APSInt(static_cast<const APInt&>(*this) << Bits, IsUnsigned);
151  }
152  APSInt& operator<<=(unsigned Amt) {
153    *this = *this << Amt;
154    return *this;
155  }
156
157  APSInt& operator++() {
158    ++(static_cast<APInt&>(*this));
159    return *this;
160  }
161  APSInt& operator--() {
162    --(static_cast<APInt&>(*this));
163    return *this;
164  }
165  APSInt operator++(int) {
166    return APSInt(++static_cast<APInt&>(*this), IsUnsigned);
167  }
168  APSInt operator--(int) {
169    return APSInt(--static_cast<APInt&>(*this), IsUnsigned);
170  }
171  APSInt operator-() const {
172    return APSInt(-static_cast<const APInt&>(*this), IsUnsigned);
173  }
174  APSInt& operator+=(const APSInt& RHS) {
175    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
176    static_cast<APInt&>(*this) += RHS;
177    return *this;
178  }
179  APSInt& operator-=(const APSInt& RHS) {
180    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
181    static_cast<APInt&>(*this) -= RHS;
182    return *this;
183  }
184  APSInt& operator*=(const APSInt& RHS) {
185    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
186    static_cast<APInt&>(*this) *= RHS;
187    return *this;
188  }
189  APSInt& operator&=(const APSInt& RHS) {
190    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
191    static_cast<APInt&>(*this) &= RHS;
192    return *this;
193  }
194  APSInt& operator|=(const APSInt& RHS) {
195    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
196    static_cast<APInt&>(*this) |= RHS;
197    return *this;
198  }
199  APSInt& operator^=(const APSInt& RHS) {
200    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
201    static_cast<APInt&>(*this) ^= RHS;
202    return *this;
203  }
204
205  APSInt operator&(const APSInt& RHS) const {
206    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
207    return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned);
208  }
209  APSInt LLVM_ATTRIBUTE_UNUSED_RESULT And(const APSInt& RHS) const {
210    return this->operator&(RHS);
211  }
212
213  APSInt operator|(const APSInt& RHS) const {
214    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
215    return APSInt(static_cast<const APInt&>(*this) | RHS, IsUnsigned);
216  }
217  APSInt LLVM_ATTRIBUTE_UNUSED_RESULT Or(const APSInt& RHS) const {
218    return this->operator|(RHS);
219  }
220
221
222  APSInt operator^(const APSInt& RHS) const {
223    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
224    return APSInt(static_cast<const APInt&>(*this) ^ RHS, IsUnsigned);
225  }
226  APSInt LLVM_ATTRIBUTE_UNUSED_RESULT Xor(const APSInt& RHS) const {
227    return this->operator^(RHS);
228  }
229
230  APSInt operator*(const APSInt& RHS) const {
231    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
232    return APSInt(static_cast<const APInt&>(*this) * RHS, IsUnsigned);
233  }
234  APSInt operator+(const APSInt& RHS) const {
235    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
236    return APSInt(static_cast<const APInt&>(*this) + RHS, IsUnsigned);
237  }
238  APSInt operator-(const APSInt& RHS) const {
239    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
240    return APSInt(static_cast<const APInt&>(*this) - RHS, IsUnsigned);
241  }
242  APSInt operator~() const {
243    return APSInt(~static_cast<const APInt&>(*this), IsUnsigned);
244  }
245
246  /// getMaxValue - Return the APSInt representing the maximum integer value
247  ///  with the given bit width and signedness.
248  static APSInt getMaxValue(uint32_t numBits, bool Unsigned) {
249    return APSInt(Unsigned ? APInt::getMaxValue(numBits)
250                           : APInt::getSignedMaxValue(numBits), Unsigned);
251  }
252
253  /// getMinValue - Return the APSInt representing the minimum integer value
254  ///  with the given bit width and signedness.
255  static APSInt getMinValue(uint32_t numBits, bool Unsigned) {
256    return APSInt(Unsigned ? APInt::getMinValue(numBits)
257                           : APInt::getSignedMinValue(numBits), Unsigned);
258  }
259
260  /// \brief Determine if two APSInts have the same value, zero- or
261  /// sign-extending as needed.
262  static bool isSameValue(const APSInt &I1, const APSInt &I2) {
263    if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
264      return I1 == I2;
265
266    // Check for a bit-width mismatch.
267    if (I1.getBitWidth() > I2.getBitWidth())
268      return isSameValue(I1, I2.extend(I1.getBitWidth()));
269    else if (I2.getBitWidth() > I1.getBitWidth())
270      return isSameValue(I1.extend(I2.getBitWidth()), I2);
271
272    // We have a signedness mismatch. Turn the signed value into an unsigned
273    // value.
274    if (I1.isSigned()) {
275      if (I1.isNegative())
276        return false;
277
278      return APSInt(I1, true) == I2;
279    }
280
281    if (I2.isNegative())
282      return false;
283
284    return I1 == APSInt(I2, true);
285  }
286
287  /// Profile - Used to insert APSInt objects, or objects that contain APSInt
288  ///  objects, into FoldingSets.
289  void Profile(FoldingSetNodeID& ID) const;
290};
291
292inline bool operator==(int64_t V1, const APSInt& V2) {
293  return V2 == V1;
294}
295inline bool operator!=(int64_t V1, const APSInt& V2) {
296  return V2 != V1;
297}
298
299inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) {
300  I.print(OS, I.isSigned());
301  return OS;
302}
303
304} // end namespace llvm
305
306#endif
307