Integral.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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 final {
  50. private:
  51. template <unsigned OtherBits, bool OtherSigned> friend class Integral;
  52. // The primitive representing the integral.
  53. using ReprT = typename Repr<Bits, Signed>::Type;
  54. ReprT V;
  55. /// Primitive representing limits.
  56. static const auto Min = std::numeric_limits<ReprT>::min();
  57. static const auto Max = std::numeric_limits<ReprT>::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 constexpr (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 == ReprT(-1); }
  104. constexpr static bool isSigned() { return Signed; }
  105. bool isNegative() const { return V < ReprT(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 {
  111. return llvm::countLeadingZeros<ReprT>(V);
  112. }
  113. Integral truncate(unsigned TruncBits) const {
  114. if (TruncBits >= Bits)
  115. return *this;
  116. const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
  117. const ReprT SignBit = ReprT(1) << (TruncBits - 1);
  118. const ReprT ExtMask = ~BitMask;
  119. return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
  120. }
  121. void print(llvm::raw_ostream &OS) const { OS << V; }
  122. static Integral min(unsigned NumBits) {
  123. return Integral(Min);
  124. }
  125. static Integral max(unsigned NumBits) {
  126. return Integral(Max);
  127. }
  128. template <typename ValT> static Integral from(ValT Value) {
  129. if constexpr (std::is_integral<ValT>::value)
  130. return Integral(Value);
  131. else
  132. return Integral::from(static_cast<Integral::ReprT>(Value));
  133. }
  134. template <unsigned SrcBits, bool SrcSign>
  135. static std::enable_if_t<SrcBits != 0, Integral>
  136. from(Integral<SrcBits, SrcSign> Value) {
  137. return Integral(Value.V);
  138. }
  139. template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
  140. if constexpr (SrcSign)
  141. return Integral(Value.V.getSExtValue());
  142. else
  143. return Integral(Value.V.getZExtValue());
  144. }
  145. static Integral zero() { return from(0); }
  146. template <typename T> static Integral from(T Value, unsigned NumBits) {
  147. return Integral(Value);
  148. }
  149. static bool inRange(int64_t Value, unsigned NumBits) {
  150. return CheckRange<ReprT, Min, Max>(Value);
  151. }
  152. static bool increment(Integral A, Integral *R) {
  153. return add(A, Integral(ReprT(1)), A.bitWidth(), R);
  154. }
  155. static bool decrement(Integral A, Integral *R) {
  156. return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
  157. }
  158. static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
  159. return CheckAddUB(A.V, B.V, R->V);
  160. }
  161. static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
  162. return CheckSubUB(A.V, B.V, R->V);
  163. }
  164. static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
  165. return CheckMulUB(A.V, B.V, R->V);
  166. }
  167. static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
  168. *R = Integral(A.V % B.V);
  169. return false;
  170. }
  171. static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
  172. *R = Integral(A.V / B.V);
  173. return false;
  174. }
  175. static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
  176. *R = Integral(A.V & B.V);
  177. return false;
  178. }
  179. static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
  180. *R = Integral(A.V | B.V);
  181. return false;
  182. }
  183. static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
  184. *R = Integral(A.V ^ B.V);
  185. return false;
  186. }
  187. static bool neg(Integral A, Integral *R) {
  188. *R = -A;
  189. return false;
  190. }
  191. static bool comp(Integral A, Integral *R) {
  192. *R = Integral(~A.V);
  193. return false;
  194. }
  195. private:
  196. template <typename T> static bool CheckAddUB(T A, T B, T &R) {
  197. if constexpr (std::is_signed_v<T>) {
  198. return llvm::AddOverflow<T>(A, B, R);
  199. } else {
  200. R = A + B;
  201. return false;
  202. }
  203. }
  204. template <typename T> static bool CheckSubUB(T A, T B, T &R) {
  205. if constexpr (std::is_signed_v<T>) {
  206. return llvm::SubOverflow<T>(A, B, R);
  207. } else {
  208. R = A - B;
  209. return false;
  210. }
  211. }
  212. template <typename T> static bool CheckMulUB(T A, T B, T &R) {
  213. if constexpr (std::is_signed_v<T>) {
  214. return llvm::MulOverflow<T>(A, B, R);
  215. } else {
  216. R = A * B;
  217. return false;
  218. }
  219. }
  220. template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
  221. if constexpr (std::is_signed_v<T>) {
  222. return Min <= V && V <= Max;
  223. } else {
  224. return V >= 0 && static_cast<uint64_t>(V) <= Max;
  225. }
  226. }
  227. };
  228. template <unsigned Bits, bool Signed>
  229. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
  230. I.print(OS);
  231. return OS;
  232. }
  233. } // namespace interp
  234. } // namespace clang
  235. #endif