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