xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Integral.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
2406c3fb27SDimitry Andric #include "Primitives.h"
2506c3fb27SDimitry Andric 
26a7dea167SDimitry Andric namespace clang {
27a7dea167SDimitry Andric namespace interp {
28a7dea167SDimitry Andric 
29a7dea167SDimitry Andric using APInt = llvm::APInt;
30a7dea167SDimitry Andric using APSInt = llvm::APSInt;
31a7dea167SDimitry Andric 
325f757f3fSDimitry Andric template <bool Signed> class IntegralAP;
335f757f3fSDimitry Andric 
34a7dea167SDimitry Andric // Helper structure to select the representation.
35a7dea167SDimitry Andric template <unsigned Bits, bool Signed> struct Repr;
36a7dea167SDimitry Andric template <> struct Repr<8, false> { using Type = uint8_t; };
37a7dea167SDimitry Andric template <> struct Repr<16, false> { using Type = uint16_t; };
38a7dea167SDimitry Andric template <> struct Repr<32, false> { using Type = uint32_t; };
39a7dea167SDimitry Andric template <> struct Repr<64, false> { using Type = uint64_t; };
40a7dea167SDimitry Andric template <> struct Repr<8, true> { using Type = int8_t; };
41a7dea167SDimitry Andric template <> struct Repr<16, true> { using Type = int16_t; };
42a7dea167SDimitry Andric template <> struct Repr<32, true> { using Type = int32_t; };
43a7dea167SDimitry Andric template <> struct Repr<64, true> { using Type = int64_t; };
44a7dea167SDimitry Andric 
45a7dea167SDimitry Andric /// Wrapper around numeric types.
46a7dea167SDimitry Andric ///
47a7dea167SDimitry Andric /// These wrappers are required to shared an interface between APSint and
48a7dea167SDimitry Andric /// builtin primitive numeral types, while optimising for storage and
49a7dea167SDimitry Andric /// allowing methods operating on primitive type to compile to fast code.
50bdd1243dSDimitry Andric template <unsigned Bits, bool Signed> class Integral final {
51a7dea167SDimitry Andric private:
52a7dea167SDimitry Andric   template <unsigned OtherBits, bool OtherSigned> friend class Integral;
53a7dea167SDimitry Andric 
54a7dea167SDimitry Andric   // The primitive representing the integral.
55bdd1243dSDimitry Andric   using ReprT = typename Repr<Bits, Signed>::Type;
56bdd1243dSDimitry Andric   ReprT V;
57a7dea167SDimitry Andric 
58a7dea167SDimitry Andric   /// Primitive representing limits.
59bdd1243dSDimitry Andric   static const auto Min = std::numeric_limits<ReprT>::min();
60bdd1243dSDimitry Andric   static const auto Max = std::numeric_limits<ReprT>::max();
61a7dea167SDimitry Andric 
62a7dea167SDimitry Andric   /// Construct an integral from anything that is convertible to storage.
63a7dea167SDimitry Andric   template <typename T> explicit Integral(T V) : V(V) {}
64a7dea167SDimitry Andric 
65a7dea167SDimitry Andric public:
665f757f3fSDimitry Andric   using AsUnsigned = Integral<Bits, false>;
675f757f3fSDimitry Andric 
68a7dea167SDimitry Andric   /// Zero-initializes an integral.
69a7dea167SDimitry Andric   Integral() : V(0) {}
70a7dea167SDimitry Andric 
71a7dea167SDimitry Andric   /// Constructs an integral from another integral.
72a7dea167SDimitry Andric   template <unsigned SrcBits, bool SrcSign>
73a7dea167SDimitry Andric   explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
74a7dea167SDimitry Andric 
75a7dea167SDimitry Andric   /// Construct an integral from a value based on signedness.
76a7dea167SDimitry Andric   explicit Integral(const APSInt &V)
77a7dea167SDimitry Andric       : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
78a7dea167SDimitry Andric 
79a7dea167SDimitry Andric   bool operator<(Integral RHS) const { return V < RHS.V; }
80a7dea167SDimitry Andric   bool operator>(Integral RHS) const { return V > RHS.V; }
81a7dea167SDimitry Andric   bool operator<=(Integral RHS) const { return V <= RHS.V; }
82a7dea167SDimitry Andric   bool operator>=(Integral RHS) const { return V >= RHS.V; }
83a7dea167SDimitry Andric   bool operator==(Integral RHS) const { return V == RHS.V; }
84a7dea167SDimitry Andric   bool operator!=(Integral RHS) const { return V != RHS.V; }
85a7dea167SDimitry Andric 
86a7dea167SDimitry Andric   bool operator>(unsigned RHS) const {
87a7dea167SDimitry Andric     return V >= 0 && static_cast<unsigned>(V) > RHS;
88a7dea167SDimitry Andric   }
89a7dea167SDimitry Andric 
90a7dea167SDimitry Andric   Integral operator-() const { return Integral(-V); }
915f757f3fSDimitry Andric   Integral operator-(const Integral &Other) const {
925f757f3fSDimitry Andric     return Integral(V - Other.V);
935f757f3fSDimitry Andric   }
94a7dea167SDimitry Andric   Integral operator~() const { return Integral(~V); }
95a7dea167SDimitry Andric 
96a7dea167SDimitry Andric   template <unsigned DstBits, bool DstSign>
97a7dea167SDimitry Andric   explicit operator Integral<DstBits, DstSign>() const {
98a7dea167SDimitry Andric     return Integral<DstBits, DstSign>(V);
99a7dea167SDimitry Andric   }
100a7dea167SDimitry Andric 
101*0fca6ea1SDimitry Andric   template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
102*0fca6ea1SDimitry Andric   explicit operator Ty() const {
103*0fca6ea1SDimitry Andric     return V;
104*0fca6ea1SDimitry Andric   }
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 {
110bdd1243dSDimitry Andric     if constexpr (Signed)
111a7dea167SDimitry Andric       return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
112a7dea167SDimitry Andric     else
113a7dea167SDimitry Andric       return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
114a7dea167SDimitry Andric   }
115*0fca6ea1SDimitry Andric   APValue toAPValue(const ASTContext &) 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 
127bdd1243dSDimitry Andric   bool isMinusOne() const { return Signed && V == ReprT(-1); }
128a7dea167SDimitry Andric 
129a7dea167SDimitry Andric   constexpr static bool isSigned() { return Signed; }
130a7dea167SDimitry Andric 
131bdd1243dSDimitry Andric   bool isNegative() const { return V < ReprT(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 
1385f757f3fSDimitry Andric   std::string toDiagnosticString(const ASTContext &Ctx) const {
1395f757f3fSDimitry Andric     std::string NameStr;
1405f757f3fSDimitry Andric     llvm::raw_string_ostream OS(NameStr);
1415f757f3fSDimitry Andric     OS << V;
1425f757f3fSDimitry Andric     return NameStr;
1435f757f3fSDimitry Andric   }
1445f757f3fSDimitry Andric 
145bdd1243dSDimitry Andric   unsigned countLeadingZeros() const {
14606c3fb27SDimitry Andric     if constexpr (!Signed)
14706c3fb27SDimitry Andric       return llvm::countl_zero<ReprT>(V);
14806c3fb27SDimitry Andric     llvm_unreachable("Don't call countLeadingZeros() on signed types.");
149bdd1243dSDimitry Andric   }
150a7dea167SDimitry Andric 
151a7dea167SDimitry Andric   Integral truncate(unsigned TruncBits) const {
152a7dea167SDimitry Andric     if (TruncBits >= Bits)
153a7dea167SDimitry Andric       return *this;
154bdd1243dSDimitry Andric     const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
155bdd1243dSDimitry Andric     const ReprT SignBit = ReprT(1) << (TruncBits - 1);
156bdd1243dSDimitry Andric     const ReprT ExtMask = ~BitMask;
157a7dea167SDimitry Andric     return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
158a7dea167SDimitry Andric   }
159a7dea167SDimitry Andric 
160a7dea167SDimitry Andric   void print(llvm::raw_ostream &OS) const { OS << V; }
161a7dea167SDimitry Andric 
162a7dea167SDimitry Andric   static Integral min(unsigned NumBits) {
163a7dea167SDimitry Andric     return Integral(Min);
164a7dea167SDimitry Andric   }
165a7dea167SDimitry Andric   static Integral max(unsigned NumBits) {
166a7dea167SDimitry Andric     return Integral(Max);
167a7dea167SDimitry Andric   }
168a7dea167SDimitry Andric 
169bdd1243dSDimitry Andric   template <typename ValT> static Integral from(ValT Value) {
170bdd1243dSDimitry Andric     if constexpr (std::is_integral<ValT>::value)
171a7dea167SDimitry Andric       return Integral(Value);
172bdd1243dSDimitry Andric     else
173bdd1243dSDimitry Andric       return Integral::from(static_cast<Integral::ReprT>(Value));
174a7dea167SDimitry Andric   }
175a7dea167SDimitry Andric 
176a7dea167SDimitry Andric   template <unsigned SrcBits, bool SrcSign>
1775ffd83dbSDimitry Andric   static std::enable_if_t<SrcBits != 0, Integral>
178a7dea167SDimitry Andric   from(Integral<SrcBits, SrcSign> Value) {
179a7dea167SDimitry Andric     return Integral(Value.V);
180a7dea167SDimitry Andric   }
181a7dea167SDimitry Andric 
182a7dea167SDimitry Andric   static Integral zero() { return from(0); }
183a7dea167SDimitry Andric 
184a7dea167SDimitry Andric   template <typename T> static Integral from(T Value, unsigned NumBits) {
185a7dea167SDimitry Andric     return Integral(Value);
186a7dea167SDimitry Andric   }
187a7dea167SDimitry Andric 
188a7dea167SDimitry Andric   static bool inRange(int64_t Value, unsigned NumBits) {
189bdd1243dSDimitry Andric     return CheckRange<ReprT, Min, Max>(Value);
190a7dea167SDimitry Andric   }
191a7dea167SDimitry Andric 
192a7dea167SDimitry Andric   static bool increment(Integral A, Integral *R) {
193bdd1243dSDimitry Andric     return add(A, Integral(ReprT(1)), A.bitWidth(), R);
194a7dea167SDimitry Andric   }
195a7dea167SDimitry Andric 
196a7dea167SDimitry Andric   static bool decrement(Integral A, Integral *R) {
197bdd1243dSDimitry Andric     return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
198a7dea167SDimitry Andric   }
199a7dea167SDimitry Andric 
200a7dea167SDimitry Andric   static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
201a7dea167SDimitry Andric     return CheckAddUB(A.V, B.V, R->V);
202a7dea167SDimitry Andric   }
203a7dea167SDimitry Andric 
204a7dea167SDimitry Andric   static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
205a7dea167SDimitry Andric     return CheckSubUB(A.V, B.V, R->V);
206a7dea167SDimitry Andric   }
207a7dea167SDimitry Andric 
208a7dea167SDimitry Andric   static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
209a7dea167SDimitry Andric     return CheckMulUB(A.V, B.V, R->V);
210a7dea167SDimitry Andric   }
211a7dea167SDimitry Andric 
212bdd1243dSDimitry Andric   static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
213bdd1243dSDimitry Andric     *R = Integral(A.V % B.V);
214bdd1243dSDimitry Andric     return false;
215a7dea167SDimitry Andric   }
216a7dea167SDimitry Andric 
217bdd1243dSDimitry Andric   static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
218bdd1243dSDimitry Andric     *R = Integral(A.V / B.V);
219bdd1243dSDimitry Andric     return false;
220bdd1243dSDimitry Andric   }
221bdd1243dSDimitry Andric 
222bdd1243dSDimitry Andric   static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
223bdd1243dSDimitry Andric     *R = Integral(A.V & B.V);
224bdd1243dSDimitry Andric     return false;
225bdd1243dSDimitry Andric   }
226bdd1243dSDimitry Andric 
227bdd1243dSDimitry Andric   static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
228bdd1243dSDimitry Andric     *R = Integral(A.V | B.V);
229bdd1243dSDimitry Andric     return false;
230bdd1243dSDimitry Andric   }
231bdd1243dSDimitry Andric 
232bdd1243dSDimitry Andric   static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
233bdd1243dSDimitry Andric     *R = Integral(A.V ^ B.V);
234bdd1243dSDimitry Andric     return false;
235bdd1243dSDimitry Andric   }
236bdd1243dSDimitry Andric 
237bdd1243dSDimitry Andric   static bool neg(Integral A, Integral *R) {
23806c3fb27SDimitry Andric     if (Signed && A.isMin())
23906c3fb27SDimitry Andric       return true;
24006c3fb27SDimitry Andric 
241bdd1243dSDimitry Andric     *R = -A;
242bdd1243dSDimitry Andric     return false;
243bdd1243dSDimitry Andric   }
244bdd1243dSDimitry Andric 
245bdd1243dSDimitry Andric   static bool comp(Integral A, Integral *R) {
246bdd1243dSDimitry Andric     *R = Integral(~A.V);
247bdd1243dSDimitry Andric     return false;
248bdd1243dSDimitry Andric   }
249bdd1243dSDimitry Andric 
25006c3fb27SDimitry Andric   template <unsigned RHSBits, bool RHSSign>
25106c3fb27SDimitry Andric   static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
25206c3fb27SDimitry Andric                         unsigned OpBits, Integral *R) {
25306c3fb27SDimitry Andric     *R = Integral::from(A.V << B.V, OpBits);
25406c3fb27SDimitry Andric   }
25506c3fb27SDimitry Andric 
25606c3fb27SDimitry Andric   template <unsigned RHSBits, bool RHSSign>
25706c3fb27SDimitry Andric   static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
25806c3fb27SDimitry Andric                          unsigned OpBits, Integral *R) {
25906c3fb27SDimitry Andric     *R = Integral::from(A.V >> B.V, OpBits);
26006c3fb27SDimitry Andric   }
26106c3fb27SDimitry Andric 
262bdd1243dSDimitry Andric private:
263bdd1243dSDimitry Andric   template <typename T> static bool CheckAddUB(T A, T B, T &R) {
264bdd1243dSDimitry Andric     if constexpr (std::is_signed_v<T>) {
265bdd1243dSDimitry Andric       return llvm::AddOverflow<T>(A, B, R);
266bdd1243dSDimitry Andric     } else {
267a7dea167SDimitry Andric       R = A + B;
268a7dea167SDimitry Andric       return false;
269a7dea167SDimitry Andric     }
270a7dea167SDimitry Andric   }
271a7dea167SDimitry Andric 
272bdd1243dSDimitry Andric   template <typename T> static bool CheckSubUB(T A, T B, T &R) {
273bdd1243dSDimitry Andric     if constexpr (std::is_signed_v<T>) {
274bdd1243dSDimitry Andric       return llvm::SubOverflow<T>(A, B, R);
275bdd1243dSDimitry Andric     } else {
276a7dea167SDimitry Andric       R = A - B;
277a7dea167SDimitry Andric       return false;
278a7dea167SDimitry Andric     }
279a7dea167SDimitry Andric   }
280a7dea167SDimitry Andric 
281bdd1243dSDimitry Andric   template <typename T> static bool CheckMulUB(T A, T B, T &R) {
282bdd1243dSDimitry Andric     if constexpr (std::is_signed_v<T>) {
283bdd1243dSDimitry Andric       return llvm::MulOverflow<T>(A, B, R);
284bdd1243dSDimitry Andric     } else {
285a7dea167SDimitry Andric       R = A * B;
286a7dea167SDimitry Andric       return false;
287a7dea167SDimitry Andric     }
288a7dea167SDimitry Andric   }
289bdd1243dSDimitry Andric   template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
290bdd1243dSDimitry Andric     if constexpr (std::is_signed_v<T>) {
291bdd1243dSDimitry Andric       return Min <= V && V <= Max;
292bdd1243dSDimitry Andric     } else {
293a7dea167SDimitry Andric       return V >= 0 && static_cast<uint64_t>(V) <= Max;
294a7dea167SDimitry Andric     }
295bdd1243dSDimitry Andric   }
296a7dea167SDimitry Andric };
297a7dea167SDimitry Andric 
298a7dea167SDimitry Andric template <unsigned Bits, bool Signed>
299a7dea167SDimitry Andric llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
300a7dea167SDimitry Andric   I.print(OS);
301a7dea167SDimitry Andric   return OS;
302a7dea167SDimitry Andric }
303a7dea167SDimitry Andric 
304a7dea167SDimitry Andric } // namespace interp
305a7dea167SDimitry Andric } // namespace clang
306a7dea167SDimitry Andric 
307a7dea167SDimitry Andric #endif
308