Integral.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //===--- Integral.h - Wrapper for numeric types for the VM ------*- 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. // Defines the VM types and helpers operating on types.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H
  13. #define LLVM_CLANG_AST_INTERP_INTEGRAL_H
  14. #include "clang/AST/ComparisonCategories.h"
  15. #include "clang/AST/APValue.h"
  16. #include "llvm/ADT/APSInt.h"
  17. #include "llvm/Support/MathExtras.h"
  18. #include "llvm/Support/raw_ostream.h"
  19. #include <cstddef>
  20. #include <cstdint>
  21. namespace clang {
  22. namespace interp {
  23. using APInt = llvm::APInt;
  24. using APSInt = llvm::APSInt;
  25. /// Helper to compare two comparable types.
  26. template <typename T>
  27. ComparisonCategoryResult Compare(const T &X, const T &Y) {
  28. if (X < Y)
  29. return ComparisonCategoryResult::Less;
  30. if (X > Y)
  31. return ComparisonCategoryResult::Greater;
  32. return ComparisonCategoryResult::Equal;
  33. }
  34. // Helper structure to select the representation.
  35. template <unsigned Bits, bool Signed> struct Repr;
  36. template <> struct Repr<8, false> { using Type = uint8_t; };
  37. template <> struct Repr<16, false> { using Type = uint16_t; };
  38. template <> struct Repr<32, false> { using Type = uint32_t; };
  39. template <> struct Repr<64, false> { using Type = uint64_t; };
  40. template <> struct Repr<8, true> { using Type = int8_t; };
  41. template <> struct Repr<16, true> { using Type = int16_t; };
  42. template <> struct Repr<32, true> { using Type = int32_t; };
  43. template <> struct Repr<64, true> { using Type = int64_t; };
  44. /// Wrapper around numeric types.
  45. ///
  46. /// These wrappers are required to shared an interface between APSint and
  47. /// builtin primitive numeral types, while optimising for storage and
  48. /// allowing methods operating on primitive type to compile to fast code.
  49. template <unsigned Bits, bool Signed> class Integral {
  50. private:
  51. template <unsigned OtherBits, bool OtherSigned> friend class Integral;
  52. // The primitive representing the integral.
  53. using T = typename Repr<Bits, Signed>::Type;
  54. T V;
  55. /// Primitive representing limits.
  56. static const auto Min = std::numeric_limits<T>::min();
  57. static const auto Max = std::numeric_limits<T>::max();
  58. /// Construct an integral from anything that is convertible to storage.
  59. template <typename T> explicit Integral(T V) : V(V) {}
  60. public:
  61. /// Zero-initializes an integral.
  62. Integral() : V(0) {}
  63. /// Constructs an integral from another integral.
  64. template <unsigned SrcBits, bool SrcSign>
  65. explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
  66. /// Construct an integral from a value based on signedness.
  67. explicit Integral(const APSInt &V)
  68. : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
  69. bool operator<(Integral RHS) const { return V < RHS.V; }
  70. bool operator>(Integral RHS) const { return V > RHS.V; }
  71. bool operator<=(Integral RHS) const { return V <= RHS.V; }
  72. bool operator>=(Integral RHS) const { return V >= RHS.V; }
  73. bool operator==(Integral RHS) const { return V == RHS.V; }
  74. bool operator!=(Integral RHS) const { return V != RHS.V; }
  75. bool operator>(unsigned RHS) const {
  76. return V >= 0 && static_cast<unsigned>(V) > RHS;
  77. }
  78. Integral operator-() const { return Integral(-V); }
  79. Integral operator~() const { return Integral(~V); }
  80. template <unsigned DstBits, bool DstSign>
  81. explicit operator Integral<DstBits, DstSign>() const {
  82. return Integral<DstBits, DstSign>(V);
  83. }
  84. explicit operator unsigned() const { return V; }
  85. explicit operator int64_t() const { return V; }
  86. explicit operator uint64_t() const { return V; }
  87. APSInt toAPSInt() const {
  88. return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
  89. }
  90. APSInt toAPSInt(unsigned NumBits) const {
  91. if (Signed)
  92. return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
  93. else
  94. return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
  95. }
  96. APValue toAPValue() const { return APValue(toAPSInt()); }
  97. Integral<Bits, false> toUnsigned() const {
  98. return Integral<Bits, false>(*this);
  99. }
  100. constexpr static unsigned bitWidth() { return Bits; }
  101. bool isZero() const { return !V; }
  102. bool isMin() const { return *this == min(bitWidth()); }
  103. bool isMinusOne() const { return Signed && V == T(-1); }
  104. constexpr static bool isSigned() { return Signed; }
  105. bool isNegative() const { return V < T(0); }
  106. bool isPositive() const { return !isNegative(); }
  107. ComparisonCategoryResult compare(const Integral &RHS) const {
  108. return Compare(V, RHS.V);
  109. }
  110. unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); }
  111. Integral truncate(unsigned TruncBits) const {
  112. if (TruncBits >= Bits)
  113. return *this;
  114. const T BitMask = (T(1) << T(TruncBits)) - 1;
  115. const T SignBit = T(1) << (TruncBits - 1);
  116. const T ExtMask = ~BitMask;
  117. return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
  118. }
  119. void print(llvm::raw_ostream &OS) const { OS << V; }
  120. static Integral min(unsigned NumBits) {
  121. return Integral(Min);
  122. }
  123. static Integral max(unsigned NumBits) {
  124. return Integral(Max);
  125. }
  126. template <typename T>
  127. static std::enable_if_t<std::is_integral<T>::value, Integral> from(T Value) {
  128. return Integral(Value);
  129. }
  130. template <unsigned SrcBits, bool SrcSign>
  131. static std::enable_if_t<SrcBits != 0, Integral>
  132. from(Integral<SrcBits, SrcSign> Value) {
  133. return Integral(Value.V);
  134. }
  135. template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
  136. if (SrcSign)
  137. return Integral(Value.V.getSExtValue());
  138. else
  139. return Integral(Value.V.getZExtValue());
  140. }
  141. static Integral zero() { return from(0); }
  142. template <typename T> static Integral from(T Value, unsigned NumBits) {
  143. return Integral(Value);
  144. }
  145. static bool inRange(int64_t Value, unsigned NumBits) {
  146. return CheckRange<T, Min, Max>(Value);
  147. }
  148. static bool increment(Integral A, Integral *R) {
  149. return add(A, Integral(T(1)), A.bitWidth(), R);
  150. }
  151. static bool decrement(Integral A, Integral *R) {
  152. return sub(A, Integral(T(1)), A.bitWidth(), R);
  153. }
  154. static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
  155. return CheckAddUB(A.V, B.V, R->V);
  156. }
  157. static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
  158. return CheckSubUB(A.V, B.V, R->V);
  159. }
  160. static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
  161. return CheckMulUB(A.V, B.V, R->V);
  162. }
  163. private:
  164. template <typename T>
  165. static std::enable_if_t<std::is_signed<T>::value, bool> CheckAddUB(T A, T B,
  166. T &R) {
  167. return llvm::AddOverflow<T>(A, B, R);
  168. }
  169. template <typename T>
  170. static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckAddUB(T A, T B,
  171. T &R) {
  172. R = A + B;
  173. return false;
  174. }
  175. template <typename T>
  176. static std::enable_if_t<std::is_signed<T>::value, bool> CheckSubUB(T A, T B,
  177. T &R) {
  178. return llvm::SubOverflow<T>(A, B, R);
  179. }
  180. template <typename T>
  181. static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckSubUB(T A, T B,
  182. T &R) {
  183. R = A - B;
  184. return false;
  185. }
  186. template <typename T>
  187. static std::enable_if_t<std::is_signed<T>::value, bool> CheckMulUB(T A, T B,
  188. T &R) {
  189. return llvm::MulOverflow<T>(A, B, R);
  190. }
  191. template <typename T>
  192. static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckMulUB(T A, T B,
  193. T &R) {
  194. R = A * B;
  195. return false;
  196. }
  197. template <typename T, T Min, T Max>
  198. static std::enable_if_t<std::is_signed<T>::value, bool>
  199. CheckRange(int64_t V) {
  200. return Min <= V && V <= Max;
  201. }
  202. template <typename T, T Min, T Max>
  203. static std::enable_if_t<std::is_unsigned<T>::value, bool>
  204. CheckRange(int64_t V) {
  205. return V >= 0 && static_cast<uint64_t>(V) <= Max;
  206. }
  207. };
  208. template <unsigned Bits, bool Signed>
  209. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
  210. I.print(OS);
  211. return OS;
  212. }
  213. } // namespace interp
  214. } // namespace clang
  215. #endif