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