xref: /llvm-project/clang/lib/AST/ByteCode/Integral.h (revision 2503a6659621e27e6b4c5946c3acff7a5b9dadca)
1a07aba5dSTimm Baeder //===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder //
9a07aba5dSTimm Baeder // Defines the VM types and helpers operating on types.
10a07aba5dSTimm Baeder //
11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
12a07aba5dSTimm Baeder 
13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H
14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_INTEGRAL_H
15a07aba5dSTimm Baeder 
16a07aba5dSTimm Baeder #include "clang/AST/APValue.h"
17a07aba5dSTimm Baeder #include "clang/AST/ComparisonCategories.h"
18a07aba5dSTimm Baeder #include "llvm/ADT/APSInt.h"
19a07aba5dSTimm Baeder #include "llvm/Support/MathExtras.h"
20a07aba5dSTimm Baeder #include "llvm/Support/raw_ostream.h"
21a07aba5dSTimm Baeder #include <cstddef>
22a07aba5dSTimm Baeder #include <cstdint>
23a07aba5dSTimm Baeder 
24a07aba5dSTimm Baeder #include "Primitives.h"
25a07aba5dSTimm Baeder 
26a07aba5dSTimm Baeder namespace clang {
27a07aba5dSTimm Baeder namespace interp {
28a07aba5dSTimm Baeder 
29a07aba5dSTimm Baeder using APInt = llvm::APInt;
30a07aba5dSTimm Baeder using APSInt = llvm::APSInt;
31a07aba5dSTimm Baeder 
32a07aba5dSTimm Baeder template <bool Signed> class IntegralAP;
33a07aba5dSTimm Baeder 
34a07aba5dSTimm Baeder // Helper structure to select the representation.
35a07aba5dSTimm Baeder template <unsigned Bits, bool Signed> struct Repr;
36a07aba5dSTimm Baeder template <> struct Repr<8, false> {
37a07aba5dSTimm Baeder   using Type = uint8_t;
38a07aba5dSTimm Baeder };
39a07aba5dSTimm Baeder template <> struct Repr<16, false> {
40a07aba5dSTimm Baeder   using Type = uint16_t;
41a07aba5dSTimm Baeder };
42a07aba5dSTimm Baeder template <> struct Repr<32, false> {
43a07aba5dSTimm Baeder   using Type = uint32_t;
44a07aba5dSTimm Baeder };
45a07aba5dSTimm Baeder template <> struct Repr<64, false> {
46a07aba5dSTimm Baeder   using Type = uint64_t;
47a07aba5dSTimm Baeder };
48a07aba5dSTimm Baeder template <> struct Repr<8, true> {
49a07aba5dSTimm Baeder   using Type = int8_t;
50a07aba5dSTimm Baeder };
51a07aba5dSTimm Baeder template <> struct Repr<16, true> {
52a07aba5dSTimm Baeder   using Type = int16_t;
53a07aba5dSTimm Baeder };
54a07aba5dSTimm Baeder template <> struct Repr<32, true> {
55a07aba5dSTimm Baeder   using Type = int32_t;
56a07aba5dSTimm Baeder };
57a07aba5dSTimm Baeder template <> struct Repr<64, true> {
58a07aba5dSTimm Baeder   using Type = int64_t;
59a07aba5dSTimm Baeder };
60a07aba5dSTimm Baeder 
61a07aba5dSTimm Baeder /// Wrapper around numeric types.
62a07aba5dSTimm Baeder ///
63a07aba5dSTimm Baeder /// These wrappers are required to shared an interface between APSint and
64a07aba5dSTimm Baeder /// builtin primitive numeral types, while optimising for storage and
65a07aba5dSTimm Baeder /// allowing methods operating on primitive type to compile to fast code.
66a07aba5dSTimm Baeder template <unsigned Bits, bool Signed> class Integral final {
67a07aba5dSTimm Baeder private:
68a07aba5dSTimm Baeder   template <unsigned OtherBits, bool OtherSigned> friend class Integral;
69a07aba5dSTimm Baeder 
70a07aba5dSTimm Baeder   // The primitive representing the integral.
71a07aba5dSTimm Baeder   using ReprT = typename Repr<Bits, Signed>::Type;
72a07aba5dSTimm Baeder   ReprT V;
73ef2a104cSTimm Baeder   static_assert(std::is_trivially_copyable_v<ReprT>);
74a07aba5dSTimm Baeder 
75a07aba5dSTimm Baeder   /// Primitive representing limits.
76a07aba5dSTimm Baeder   static const auto Min = std::numeric_limits<ReprT>::min();
77a07aba5dSTimm Baeder   static const auto Max = std::numeric_limits<ReprT>::max();
78a07aba5dSTimm Baeder 
79a07aba5dSTimm Baeder   /// Construct an integral from anything that is convertible to storage.
80a07aba5dSTimm Baeder   template <typename T> explicit Integral(T V) : V(V) {}
81a07aba5dSTimm Baeder 
82a07aba5dSTimm Baeder public:
83a07aba5dSTimm Baeder   using AsUnsigned = Integral<Bits, false>;
84a07aba5dSTimm Baeder 
85a07aba5dSTimm Baeder   /// Zero-initializes an integral.
86a07aba5dSTimm Baeder   Integral() : V(0) {}
87a07aba5dSTimm Baeder 
88a07aba5dSTimm Baeder   /// Constructs an integral from another integral.
89a07aba5dSTimm Baeder   template <unsigned SrcBits, bool SrcSign>
90a07aba5dSTimm Baeder   explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
91a07aba5dSTimm Baeder 
92a07aba5dSTimm Baeder   /// Construct an integral from a value based on signedness.
93a07aba5dSTimm Baeder   explicit Integral(const APSInt &V)
94a07aba5dSTimm Baeder       : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
95a07aba5dSTimm Baeder 
96a07aba5dSTimm Baeder   bool operator<(Integral RHS) const { return V < RHS.V; }
97a07aba5dSTimm Baeder   bool operator>(Integral RHS) const { return V > RHS.V; }
98a07aba5dSTimm Baeder   bool operator<=(Integral RHS) const { return V <= RHS.V; }
99a07aba5dSTimm Baeder   bool operator>=(Integral RHS) const { return V >= RHS.V; }
100a07aba5dSTimm Baeder   bool operator==(Integral RHS) const { return V == RHS.V; }
101a07aba5dSTimm Baeder   bool operator!=(Integral RHS) const { return V != RHS.V; }
102a07aba5dSTimm Baeder 
103a07aba5dSTimm Baeder   bool operator>(unsigned RHS) const {
104a07aba5dSTimm Baeder     return V >= 0 && static_cast<unsigned>(V) > RHS;
105a07aba5dSTimm Baeder   }
106a07aba5dSTimm Baeder 
107a07aba5dSTimm Baeder   Integral operator-() const { return Integral(-V); }
108a07aba5dSTimm Baeder   Integral operator-(const Integral &Other) const {
109a07aba5dSTimm Baeder     return Integral(V - Other.V);
110a07aba5dSTimm Baeder   }
111a07aba5dSTimm Baeder   Integral operator~() const { return Integral(~V); }
112a07aba5dSTimm Baeder 
113a07aba5dSTimm Baeder   template <unsigned DstBits, bool DstSign>
114a07aba5dSTimm Baeder   explicit operator Integral<DstBits, DstSign>() const {
115a07aba5dSTimm Baeder     return Integral<DstBits, DstSign>(V);
116a07aba5dSTimm Baeder   }
117a07aba5dSTimm Baeder 
118a07aba5dSTimm Baeder   template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
119a07aba5dSTimm Baeder   explicit operator Ty() const {
120a07aba5dSTimm Baeder     return V;
121a07aba5dSTimm Baeder   }
122a07aba5dSTimm Baeder 
123a07aba5dSTimm Baeder   APSInt toAPSInt() const {
124a07aba5dSTimm Baeder     return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
125a07aba5dSTimm Baeder   }
126c1dcf75aSTimm Baeder   APSInt toAPSInt(unsigned BitWidth) const {
127c1dcf75aSTimm Baeder     return APSInt(toAPInt(BitWidth), !Signed);
128c1dcf75aSTimm Baeder   }
1295b4071c7STimm Baeder   APInt toAPInt(unsigned BitWidth) const {
130a07aba5dSTimm Baeder     if constexpr (Signed)
1315b4071c7STimm Baeder       return APInt(Bits, static_cast<uint64_t>(V), Signed)
1325b4071c7STimm Baeder           .sextOrTrunc(BitWidth);
133a07aba5dSTimm Baeder     else
1345b4071c7STimm Baeder       return APInt(Bits, static_cast<uint64_t>(V), Signed)
1355b4071c7STimm Baeder           .zextOrTrunc(BitWidth);
136a07aba5dSTimm Baeder   }
137a07aba5dSTimm Baeder   APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
138a07aba5dSTimm Baeder 
139a07aba5dSTimm Baeder   Integral<Bits, false> toUnsigned() const {
140a07aba5dSTimm Baeder     return Integral<Bits, false>(*this);
141a07aba5dSTimm Baeder   }
142a07aba5dSTimm Baeder 
143a07aba5dSTimm Baeder   constexpr static unsigned bitWidth() { return Bits; }
144a07aba5dSTimm Baeder 
145a07aba5dSTimm Baeder   bool isZero() const { return !V; }
146a07aba5dSTimm Baeder 
147a07aba5dSTimm Baeder   bool isMin() const { return *this == min(bitWidth()); }
148a07aba5dSTimm Baeder 
149a07aba5dSTimm Baeder   bool isMinusOne() const { return Signed && V == ReprT(-1); }
150a07aba5dSTimm Baeder 
151a07aba5dSTimm Baeder   constexpr static bool isSigned() { return Signed; }
152a07aba5dSTimm Baeder 
153a07aba5dSTimm Baeder   bool isNegative() const { return V < ReprT(0); }
154a07aba5dSTimm Baeder   bool isPositive() const { return !isNegative(); }
155a07aba5dSTimm Baeder 
156a07aba5dSTimm Baeder   ComparisonCategoryResult compare(const Integral &RHS) const {
157a07aba5dSTimm Baeder     return Compare(V, RHS.V);
158a07aba5dSTimm Baeder   }
159a07aba5dSTimm Baeder 
160ef2a104cSTimm Baeder   void bitcastToMemory(std::byte *Dest) const {
161ef2a104cSTimm Baeder     std::memcpy(Dest, &V, sizeof(V));
162ef2a104cSTimm Baeder   }
163ef2a104cSTimm Baeder 
164ef2a104cSTimm Baeder   static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
165ef2a104cSTimm Baeder     assert(BitWidth == sizeof(ReprT) * 8);
166ef2a104cSTimm Baeder     ReprT V;
167ef2a104cSTimm Baeder 
168ef2a104cSTimm Baeder     std::memcpy(&V, Src, sizeof(ReprT));
169ef2a104cSTimm Baeder     return Integral(V);
170ef2a104cSTimm Baeder   }
171ef2a104cSTimm Baeder 
172a07aba5dSTimm Baeder   std::string toDiagnosticString(const ASTContext &Ctx) const {
173a07aba5dSTimm Baeder     std::string NameStr;
174a07aba5dSTimm Baeder     llvm::raw_string_ostream OS(NameStr);
175a07aba5dSTimm Baeder     OS << V;
176a07aba5dSTimm Baeder     return NameStr;
177a07aba5dSTimm Baeder   }
178a07aba5dSTimm Baeder 
179a07aba5dSTimm Baeder   unsigned countLeadingZeros() const {
180a07aba5dSTimm Baeder     if constexpr (!Signed)
181a07aba5dSTimm Baeder       return llvm::countl_zero<ReprT>(V);
182*2503a665STimm Bäder     if (isPositive())
183*2503a665STimm Bäder       return llvm::countl_zero<typename AsUnsigned::ReprT>(
184*2503a665STimm Bäder           static_cast<typename AsUnsigned::ReprT>(V));
185*2503a665STimm Bäder     llvm_unreachable("Don't call countLeadingZeros() on negative values.");
186a07aba5dSTimm Baeder   }
187a07aba5dSTimm Baeder 
188a07aba5dSTimm Baeder   Integral truncate(unsigned TruncBits) const {
18912ca72baSTimm Bäder     assert(TruncBits >= 1);
190a07aba5dSTimm Baeder     if (TruncBits >= Bits)
191a07aba5dSTimm Baeder       return *this;
192a07aba5dSTimm Baeder     const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
193a07aba5dSTimm Baeder     const ReprT SignBit = ReprT(1) << (TruncBits - 1);
194a07aba5dSTimm Baeder     const ReprT ExtMask = ~BitMask;
195a07aba5dSTimm Baeder     return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
196a07aba5dSTimm Baeder   }
197a07aba5dSTimm Baeder 
198a07aba5dSTimm Baeder   void print(llvm::raw_ostream &OS) const { OS << V; }
199a07aba5dSTimm Baeder 
200a07aba5dSTimm Baeder   static Integral min(unsigned NumBits) { return Integral(Min); }
201a07aba5dSTimm Baeder   static Integral max(unsigned NumBits) { return Integral(Max); }
202a07aba5dSTimm Baeder 
203a07aba5dSTimm Baeder   template <typename ValT> static Integral from(ValT Value) {
204a07aba5dSTimm Baeder     if constexpr (std::is_integral<ValT>::value)
205a07aba5dSTimm Baeder       return Integral(Value);
206a07aba5dSTimm Baeder     else
207a07aba5dSTimm Baeder       return Integral::from(static_cast<Integral::ReprT>(Value));
208a07aba5dSTimm Baeder   }
209a07aba5dSTimm Baeder 
210a07aba5dSTimm Baeder   template <unsigned SrcBits, bool SrcSign>
211a07aba5dSTimm Baeder   static std::enable_if_t<SrcBits != 0, Integral>
212a07aba5dSTimm Baeder   from(Integral<SrcBits, SrcSign> Value) {
213a07aba5dSTimm Baeder     return Integral(Value.V);
214a07aba5dSTimm Baeder   }
215a07aba5dSTimm Baeder 
216*2503a665STimm Bäder   static Integral zero(unsigned BitWidth = 0) { return from(0); }
217a07aba5dSTimm Baeder 
218a07aba5dSTimm Baeder   template <typename T> static Integral from(T Value, unsigned NumBits) {
219a07aba5dSTimm Baeder     return Integral(Value);
220a07aba5dSTimm Baeder   }
221a07aba5dSTimm Baeder 
222a07aba5dSTimm Baeder   static bool inRange(int64_t Value, unsigned NumBits) {
223a07aba5dSTimm Baeder     return CheckRange<ReprT, Min, Max>(Value);
224a07aba5dSTimm Baeder   }
225a07aba5dSTimm Baeder 
226a07aba5dSTimm Baeder   static bool increment(Integral A, Integral *R) {
227a07aba5dSTimm Baeder     return add(A, Integral(ReprT(1)), A.bitWidth(), R);
228a07aba5dSTimm Baeder   }
229a07aba5dSTimm Baeder 
230a07aba5dSTimm Baeder   static bool decrement(Integral A, Integral *R) {
231a07aba5dSTimm Baeder     return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
232a07aba5dSTimm Baeder   }
233a07aba5dSTimm Baeder 
234a07aba5dSTimm Baeder   static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
235a07aba5dSTimm Baeder     return CheckAddUB(A.V, B.V, R->V);
236a07aba5dSTimm Baeder   }
237a07aba5dSTimm Baeder 
238a07aba5dSTimm Baeder   static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
239a07aba5dSTimm Baeder     return CheckSubUB(A.V, B.V, R->V);
240a07aba5dSTimm Baeder   }
241a07aba5dSTimm Baeder 
242a07aba5dSTimm Baeder   static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
243a07aba5dSTimm Baeder     return CheckMulUB(A.V, B.V, R->V);
244a07aba5dSTimm Baeder   }
245a07aba5dSTimm Baeder 
246a07aba5dSTimm Baeder   static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
247a07aba5dSTimm Baeder     *R = Integral(A.V % B.V);
248a07aba5dSTimm Baeder     return false;
249a07aba5dSTimm Baeder   }
250a07aba5dSTimm Baeder 
251a07aba5dSTimm Baeder   static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
252a07aba5dSTimm Baeder     *R = Integral(A.V / B.V);
253a07aba5dSTimm Baeder     return false;
254a07aba5dSTimm Baeder   }
255a07aba5dSTimm Baeder 
256a07aba5dSTimm Baeder   static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
257a07aba5dSTimm Baeder     *R = Integral(A.V & B.V);
258a07aba5dSTimm Baeder     return false;
259a07aba5dSTimm Baeder   }
260a07aba5dSTimm Baeder 
261a07aba5dSTimm Baeder   static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
262a07aba5dSTimm Baeder     *R = Integral(A.V | B.V);
263a07aba5dSTimm Baeder     return false;
264a07aba5dSTimm Baeder   }
265a07aba5dSTimm Baeder 
266a07aba5dSTimm Baeder   static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
267a07aba5dSTimm Baeder     *R = Integral(A.V ^ B.V);
268a07aba5dSTimm Baeder     return false;
269a07aba5dSTimm Baeder   }
270a07aba5dSTimm Baeder 
271a07aba5dSTimm Baeder   static bool neg(Integral A, Integral *R) {
272a07aba5dSTimm Baeder     if (Signed && A.isMin())
273a07aba5dSTimm Baeder       return true;
274a07aba5dSTimm Baeder 
275a07aba5dSTimm Baeder     *R = -A;
276a07aba5dSTimm Baeder     return false;
277a07aba5dSTimm Baeder   }
278a07aba5dSTimm Baeder 
279a07aba5dSTimm Baeder   static bool comp(Integral A, Integral *R) {
280a07aba5dSTimm Baeder     *R = Integral(~A.V);
281a07aba5dSTimm Baeder     return false;
282a07aba5dSTimm Baeder   }
283a07aba5dSTimm Baeder 
284a07aba5dSTimm Baeder   template <unsigned RHSBits, bool RHSSign>
285a07aba5dSTimm Baeder   static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
286a07aba5dSTimm Baeder                         unsigned OpBits, Integral *R) {
287a07aba5dSTimm Baeder     *R = Integral::from(A.V << B.V, OpBits);
288a07aba5dSTimm Baeder   }
289a07aba5dSTimm Baeder 
290a07aba5dSTimm Baeder   template <unsigned RHSBits, bool RHSSign>
291a07aba5dSTimm Baeder   static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
292a07aba5dSTimm Baeder                          unsigned OpBits, Integral *R) {
293a07aba5dSTimm Baeder     *R = Integral::from(A.V >> B.V, OpBits);
294a07aba5dSTimm Baeder   }
295a07aba5dSTimm Baeder 
296a07aba5dSTimm Baeder private:
297a07aba5dSTimm Baeder   template <typename T> static bool CheckAddUB(T A, T B, T &R) {
298a07aba5dSTimm Baeder     if constexpr (std::is_signed_v<T>) {
299a07aba5dSTimm Baeder       return llvm::AddOverflow<T>(A, B, R);
300a07aba5dSTimm Baeder     } else {
301a07aba5dSTimm Baeder       R = A + B;
302a07aba5dSTimm Baeder       return false;
303a07aba5dSTimm Baeder     }
304a07aba5dSTimm Baeder   }
305a07aba5dSTimm Baeder 
306a07aba5dSTimm Baeder   template <typename T> static bool CheckSubUB(T A, T B, T &R) {
307a07aba5dSTimm Baeder     if constexpr (std::is_signed_v<T>) {
308a07aba5dSTimm Baeder       return llvm::SubOverflow<T>(A, B, R);
309a07aba5dSTimm Baeder     } else {
310a07aba5dSTimm Baeder       R = A - B;
311a07aba5dSTimm Baeder       return false;
312a07aba5dSTimm Baeder     }
313a07aba5dSTimm Baeder   }
314a07aba5dSTimm Baeder 
315a07aba5dSTimm Baeder   template <typename T> static bool CheckMulUB(T A, T B, T &R) {
316a07aba5dSTimm Baeder     if constexpr (std::is_signed_v<T>) {
317a07aba5dSTimm Baeder       return llvm::MulOverflow<T>(A, B, R);
318a07aba5dSTimm Baeder     } else {
319a07aba5dSTimm Baeder       R = A * B;
320a07aba5dSTimm Baeder       return false;
321a07aba5dSTimm Baeder     }
322a07aba5dSTimm Baeder   }
323a07aba5dSTimm Baeder   template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
324a07aba5dSTimm Baeder     if constexpr (std::is_signed_v<T>) {
325a07aba5dSTimm Baeder       return Min <= V && V <= Max;
326a07aba5dSTimm Baeder     } else {
327a07aba5dSTimm Baeder       return V >= 0 && static_cast<uint64_t>(V) <= Max;
328a07aba5dSTimm Baeder     }
329a07aba5dSTimm Baeder   }
330a07aba5dSTimm Baeder };
331a07aba5dSTimm Baeder 
332a07aba5dSTimm Baeder template <unsigned Bits, bool Signed>
333a07aba5dSTimm Baeder llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
334a07aba5dSTimm Baeder   I.print(OS);
335a07aba5dSTimm Baeder   return OS;
336a07aba5dSTimm Baeder }
337a07aba5dSTimm Baeder 
338a07aba5dSTimm Baeder } // namespace interp
339a07aba5dSTimm Baeder } // namespace clang
340a07aba5dSTimm Baeder 
341a07aba5dSTimm Baeder #endif
342