xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/IntegralAP.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric //
9*5f757f3fSDimitry Andric // Defines the VM types and helpers operating on types.
10*5f757f3fSDimitry Andric //
11*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
12*5f757f3fSDimitry Andric 
13*5f757f3fSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
14*5f757f3fSDimitry Andric #define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
15*5f757f3fSDimitry Andric 
16*5f757f3fSDimitry Andric #include "clang/AST/APValue.h"
17*5f757f3fSDimitry Andric #include "clang/AST/ComparisonCategories.h"
18*5f757f3fSDimitry Andric #include "llvm/ADT/APSInt.h"
19*5f757f3fSDimitry Andric #include "llvm/Support/MathExtras.h"
20*5f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h"
21*5f757f3fSDimitry Andric #include <cstddef>
22*5f757f3fSDimitry Andric #include <cstdint>
23*5f757f3fSDimitry Andric 
24*5f757f3fSDimitry Andric #include "Primitives.h"
25*5f757f3fSDimitry Andric 
26*5f757f3fSDimitry Andric namespace clang {
27*5f757f3fSDimitry Andric namespace interp {
28*5f757f3fSDimitry Andric 
29*5f757f3fSDimitry Andric using APInt = llvm::APInt;
30*5f757f3fSDimitry Andric using APSInt = llvm::APSInt;
31*5f757f3fSDimitry Andric template <unsigned Bits, bool Signed> class Integral;
32*5f757f3fSDimitry Andric 
33*5f757f3fSDimitry Andric template <bool Signed> class IntegralAP final {
34*5f757f3fSDimitry Andric private:
35*5f757f3fSDimitry Andric   friend IntegralAP<!Signed>;
36*5f757f3fSDimitry Andric   APInt V;
37*5f757f3fSDimitry Andric 
38*5f757f3fSDimitry Andric   template <typename T, bool InputSigned>
39*5f757f3fSDimitry Andric   static T truncateCast(const APInt &V) {
40*5f757f3fSDimitry Andric     constexpr unsigned BitSize = sizeof(T) * 8;
41*5f757f3fSDimitry Andric     if (BitSize >= V.getBitWidth()) {
42*5f757f3fSDimitry Andric       APInt Extended;
43*5f757f3fSDimitry Andric       if constexpr (InputSigned)
44*5f757f3fSDimitry Andric         Extended = V.sext(BitSize);
45*5f757f3fSDimitry Andric       else
46*5f757f3fSDimitry Andric         Extended = V.zext(BitSize);
47*5f757f3fSDimitry Andric       return std::is_signed_v<T> ? Extended.getSExtValue()
48*5f757f3fSDimitry Andric                                  : Extended.getZExtValue();
49*5f757f3fSDimitry Andric     }
50*5f757f3fSDimitry Andric 
51*5f757f3fSDimitry Andric     return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue()
52*5f757f3fSDimitry Andric                                : V.trunc(BitSize).getZExtValue();
53*5f757f3fSDimitry Andric   }
54*5f757f3fSDimitry Andric 
55*5f757f3fSDimitry Andric public:
56*5f757f3fSDimitry Andric   using AsUnsigned = IntegralAP<false>;
57*5f757f3fSDimitry Andric 
58*5f757f3fSDimitry Andric   template <typename T>
59*5f757f3fSDimitry Andric   IntegralAP(T Value, unsigned BitWidth)
60*5f757f3fSDimitry Andric       : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {}
61*5f757f3fSDimitry Andric 
62*5f757f3fSDimitry Andric   IntegralAP(APInt V) : V(V) {}
63*5f757f3fSDimitry Andric   /// Arbitrary value for uninitialized variables.
64*5f757f3fSDimitry Andric   IntegralAP() : IntegralAP(-1, 1024) {}
65*5f757f3fSDimitry Andric 
66*5f757f3fSDimitry Andric   IntegralAP operator-() const { return IntegralAP(-V); }
67*5f757f3fSDimitry Andric   IntegralAP operator-(const IntegralAP &Other) const {
68*5f757f3fSDimitry Andric     return IntegralAP(V - Other.V);
69*5f757f3fSDimitry Andric   }
70*5f757f3fSDimitry Andric   bool operator>(const IntegralAP &RHS) const {
71*5f757f3fSDimitry Andric     if constexpr (Signed)
72*5f757f3fSDimitry Andric       return V.ugt(RHS.V);
73*5f757f3fSDimitry Andric     return V.sgt(RHS.V);
74*5f757f3fSDimitry Andric   }
75*5f757f3fSDimitry Andric   bool operator>=(IntegralAP RHS) const {
76*5f757f3fSDimitry Andric     if constexpr (Signed)
77*5f757f3fSDimitry Andric       return V.uge(RHS.V);
78*5f757f3fSDimitry Andric     return V.sge(RHS.V);
79*5f757f3fSDimitry Andric   }
80*5f757f3fSDimitry Andric   bool operator<(IntegralAP RHS) const {
81*5f757f3fSDimitry Andric     if constexpr (Signed)
82*5f757f3fSDimitry Andric       return V.slt(RHS.V);
83*5f757f3fSDimitry Andric     return V.slt(RHS.V);
84*5f757f3fSDimitry Andric   }
85*5f757f3fSDimitry Andric   bool operator<=(IntegralAP RHS) const {
86*5f757f3fSDimitry Andric     if constexpr (Signed)
87*5f757f3fSDimitry Andric       return V.ult(RHS.V);
88*5f757f3fSDimitry Andric     return V.ult(RHS.V);
89*5f757f3fSDimitry Andric   }
90*5f757f3fSDimitry Andric 
91*5f757f3fSDimitry Andric   template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
92*5f757f3fSDimitry Andric   explicit operator Ty() const {
93*5f757f3fSDimitry Andric     return truncateCast<Ty, Signed>(V);
94*5f757f3fSDimitry Andric   }
95*5f757f3fSDimitry Andric 
96*5f757f3fSDimitry Andric   template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
97*5f757f3fSDimitry Andric     assert(NumBits > 0);
98*5f757f3fSDimitry Andric     APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);
99*5f757f3fSDimitry Andric 
100*5f757f3fSDimitry Andric     return IntegralAP<Signed>(Copy);
101*5f757f3fSDimitry Andric   }
102*5f757f3fSDimitry Andric 
103*5f757f3fSDimitry Andric   template <bool InputSigned>
104*5f757f3fSDimitry Andric   static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
105*5f757f3fSDimitry Andric     if (NumBits == 0)
106*5f757f3fSDimitry Andric       NumBits = V.bitWidth();
107*5f757f3fSDimitry Andric 
108*5f757f3fSDimitry Andric     if constexpr (InputSigned)
109*5f757f3fSDimitry Andric       return IntegralAP<Signed>(V.V.sextOrTrunc(NumBits));
110*5f757f3fSDimitry Andric     return IntegralAP<Signed>(V.V.zextOrTrunc(NumBits));
111*5f757f3fSDimitry Andric   }
112*5f757f3fSDimitry Andric 
113*5f757f3fSDimitry Andric   template <unsigned Bits, bool InputSigned>
114*5f757f3fSDimitry Andric   static IntegralAP from(Integral<Bits, InputSigned> I, unsigned BitWidth) {
115*5f757f3fSDimitry Andric     APInt Copy = APInt(BitWidth, static_cast<uint64_t>(I), InputSigned);
116*5f757f3fSDimitry Andric 
117*5f757f3fSDimitry Andric     return IntegralAP<Signed>(Copy);
118*5f757f3fSDimitry Andric   }
119*5f757f3fSDimitry Andric 
120*5f757f3fSDimitry Andric   static IntegralAP zero(int32_t BitWidth) {
121*5f757f3fSDimitry Andric     APInt V = APInt(BitWidth, 0LL, Signed);
122*5f757f3fSDimitry Andric     return IntegralAP(V);
123*5f757f3fSDimitry Andric   }
124*5f757f3fSDimitry Andric 
125*5f757f3fSDimitry Andric   constexpr unsigned bitWidth() const { return V.getBitWidth(); }
126*5f757f3fSDimitry Andric 
127*5f757f3fSDimitry Andric   APSInt toAPSInt(unsigned Bits = 0) const {
128*5f757f3fSDimitry Andric     if (Bits == 0)
129*5f757f3fSDimitry Andric       Bits = bitWidth();
130*5f757f3fSDimitry Andric 
131*5f757f3fSDimitry Andric     if constexpr (Signed)
132*5f757f3fSDimitry Andric       return APSInt(V.sext(Bits), !Signed);
133*5f757f3fSDimitry Andric     else
134*5f757f3fSDimitry Andric       return APSInt(V.zext(Bits), !Signed);
135*5f757f3fSDimitry Andric   }
136*5f757f3fSDimitry Andric   APValue toAPValue() const { return APValue(toAPSInt()); }
137*5f757f3fSDimitry Andric 
138*5f757f3fSDimitry Andric   bool isZero() const { return V.isZero(); }
139*5f757f3fSDimitry Andric   bool isPositive() const { return V.isNonNegative(); }
140*5f757f3fSDimitry Andric   bool isNegative() const { return !V.isNonNegative(); }
141*5f757f3fSDimitry Andric   bool isMin() const { return V.isMinValue(); }
142*5f757f3fSDimitry Andric   bool isMax() const { return V.isMaxValue(); }
143*5f757f3fSDimitry Andric   static constexpr bool isSigned() { return Signed; }
144*5f757f3fSDimitry Andric   bool isMinusOne() const { return Signed && V == -1; }
145*5f757f3fSDimitry Andric 
146*5f757f3fSDimitry Andric   unsigned countLeadingZeros() const { return V.countl_zero(); }
147*5f757f3fSDimitry Andric 
148*5f757f3fSDimitry Andric   void print(llvm::raw_ostream &OS) const { OS << V; }
149*5f757f3fSDimitry Andric   std::string toDiagnosticString(const ASTContext &Ctx) const {
150*5f757f3fSDimitry Andric     std::string NameStr;
151*5f757f3fSDimitry Andric     llvm::raw_string_ostream OS(NameStr);
152*5f757f3fSDimitry Andric     print(OS);
153*5f757f3fSDimitry Andric     return NameStr;
154*5f757f3fSDimitry Andric   }
155*5f757f3fSDimitry Andric 
156*5f757f3fSDimitry Andric   IntegralAP truncate(unsigned BitWidth) const {
157*5f757f3fSDimitry Andric     return IntegralAP(V.trunc(BitWidth));
158*5f757f3fSDimitry Andric   }
159*5f757f3fSDimitry Andric 
160*5f757f3fSDimitry Andric   IntegralAP<false> toUnsigned() const {
161*5f757f3fSDimitry Andric     APInt Copy = V;
162*5f757f3fSDimitry Andric     return IntegralAP<false>(Copy);
163*5f757f3fSDimitry Andric   }
164*5f757f3fSDimitry Andric 
165*5f757f3fSDimitry Andric   ComparisonCategoryResult compare(const IntegralAP &RHS) const {
166*5f757f3fSDimitry Andric     assert(Signed == RHS.isSigned());
167*5f757f3fSDimitry Andric     assert(bitWidth() == RHS.bitWidth());
168*5f757f3fSDimitry Andric     if constexpr (Signed) {
169*5f757f3fSDimitry Andric       if (V.slt(RHS.V))
170*5f757f3fSDimitry Andric         return ComparisonCategoryResult::Less;
171*5f757f3fSDimitry Andric       if (V.sgt(RHS.V))
172*5f757f3fSDimitry Andric         return ComparisonCategoryResult::Greater;
173*5f757f3fSDimitry Andric       return ComparisonCategoryResult::Equal;
174*5f757f3fSDimitry Andric     }
175*5f757f3fSDimitry Andric 
176*5f757f3fSDimitry Andric     assert(!Signed);
177*5f757f3fSDimitry Andric     if (V.ult(RHS.V))
178*5f757f3fSDimitry Andric       return ComparisonCategoryResult::Less;
179*5f757f3fSDimitry Andric     if (V.ugt(RHS.V))
180*5f757f3fSDimitry Andric       return ComparisonCategoryResult::Greater;
181*5f757f3fSDimitry Andric     return ComparisonCategoryResult::Equal;
182*5f757f3fSDimitry Andric   }
183*5f757f3fSDimitry Andric 
184*5f757f3fSDimitry Andric   static bool increment(IntegralAP A, IntegralAP *R) {
185*5f757f3fSDimitry Andric     IntegralAP<Signed> One(1, A.bitWidth());
186*5f757f3fSDimitry Andric     return add(A, One, A.bitWidth() + 1, R);
187*5f757f3fSDimitry Andric   }
188*5f757f3fSDimitry Andric 
189*5f757f3fSDimitry Andric   static bool decrement(IntegralAP A, IntegralAP *R) {
190*5f757f3fSDimitry Andric     IntegralAP<Signed> One(1, A.bitWidth());
191*5f757f3fSDimitry Andric     return sub(A, One, A.bitWidth() + 1, R);
192*5f757f3fSDimitry Andric   }
193*5f757f3fSDimitry Andric 
194*5f757f3fSDimitry Andric   static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
195*5f757f3fSDimitry Andric     return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
196*5f757f3fSDimitry Andric   }
197*5f757f3fSDimitry Andric 
198*5f757f3fSDimitry Andric   static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
199*5f757f3fSDimitry Andric     return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
200*5f757f3fSDimitry Andric   }
201*5f757f3fSDimitry Andric 
202*5f757f3fSDimitry Andric   static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
203*5f757f3fSDimitry Andric     return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
204*5f757f3fSDimitry Andric   }
205*5f757f3fSDimitry Andric 
206*5f757f3fSDimitry Andric   static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
207*5f757f3fSDimitry Andric     // FIXME: Implement.
208*5f757f3fSDimitry Andric     assert(false);
209*5f757f3fSDimitry Andric     return false;
210*5f757f3fSDimitry Andric   }
211*5f757f3fSDimitry Andric 
212*5f757f3fSDimitry Andric   static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
213*5f757f3fSDimitry Andric     // FIXME: Implement.
214*5f757f3fSDimitry Andric     assert(false);
215*5f757f3fSDimitry Andric     return false;
216*5f757f3fSDimitry Andric   }
217*5f757f3fSDimitry Andric 
218*5f757f3fSDimitry Andric   static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
219*5f757f3fSDimitry Andric                      IntegralAP *R) {
220*5f757f3fSDimitry Andric     *R = IntegralAP(A.V & B.V);
221*5f757f3fSDimitry Andric     return false;
222*5f757f3fSDimitry Andric   }
223*5f757f3fSDimitry Andric 
224*5f757f3fSDimitry Andric   static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
225*5f757f3fSDimitry Andric                     IntegralAP *R) {
226*5f757f3fSDimitry Andric     *R = IntegralAP(A.V | B.V);
227*5f757f3fSDimitry Andric     return false;
228*5f757f3fSDimitry Andric   }
229*5f757f3fSDimitry Andric 
230*5f757f3fSDimitry Andric   static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
231*5f757f3fSDimitry Andric                      IntegralAP *R) {
232*5f757f3fSDimitry Andric     *R = IntegralAP(A.V ^ B.V);
233*5f757f3fSDimitry Andric     return false;
234*5f757f3fSDimitry Andric   }
235*5f757f3fSDimitry Andric 
236*5f757f3fSDimitry Andric   static bool neg(const IntegralAP &A, IntegralAP *R) {
237*5f757f3fSDimitry Andric     APInt AI = A.V;
238*5f757f3fSDimitry Andric     AI.negate();
239*5f757f3fSDimitry Andric     *R = IntegralAP(AI);
240*5f757f3fSDimitry Andric     return false;
241*5f757f3fSDimitry Andric   }
242*5f757f3fSDimitry Andric 
243*5f757f3fSDimitry Andric   static bool comp(IntegralAP A, IntegralAP *R) {
244*5f757f3fSDimitry Andric     *R = IntegralAP(~A.V);
245*5f757f3fSDimitry Andric     return false;
246*5f757f3fSDimitry Andric   }
247*5f757f3fSDimitry Andric 
248*5f757f3fSDimitry Andric   static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
249*5f757f3fSDimitry Andric                         IntegralAP *R) {
250*5f757f3fSDimitry Andric     *R = IntegralAP(A.V.shl(B.V.getZExtValue()));
251*5f757f3fSDimitry Andric   }
252*5f757f3fSDimitry Andric 
253*5f757f3fSDimitry Andric   static void shiftRight(const IntegralAP A, const IntegralAP B,
254*5f757f3fSDimitry Andric                          unsigned OpBits, IntegralAP *R) {
255*5f757f3fSDimitry Andric     unsigned ShiftAmount = B.V.getZExtValue();
256*5f757f3fSDimitry Andric     if constexpr (Signed)
257*5f757f3fSDimitry Andric       *R = IntegralAP(A.V.ashr(ShiftAmount));
258*5f757f3fSDimitry Andric     else
259*5f757f3fSDimitry Andric       *R = IntegralAP(A.V.lshr(ShiftAmount));
260*5f757f3fSDimitry Andric   }
261*5f757f3fSDimitry Andric 
262*5f757f3fSDimitry Andric private:
263*5f757f3fSDimitry Andric   template <template <typename T> class Op>
264*5f757f3fSDimitry Andric   static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
265*5f757f3fSDimitry Andric                                unsigned BitWidth, IntegralAP *R) {
266*5f757f3fSDimitry Andric     if constexpr (!Signed) {
267*5f757f3fSDimitry Andric       R->V = Op<APInt>{}(A.V, B.V);
268*5f757f3fSDimitry Andric       return false;
269*5f757f3fSDimitry Andric     }
270*5f757f3fSDimitry Andric 
271*5f757f3fSDimitry Andric     const APSInt &LHS = A.toAPSInt();
272*5f757f3fSDimitry Andric     const APSInt &RHS = B.toAPSInt();
273*5f757f3fSDimitry Andric     APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
274*5f757f3fSDimitry Andric     APSInt Result = Value.trunc(LHS.getBitWidth());
275*5f757f3fSDimitry Andric     R->V = Result;
276*5f757f3fSDimitry Andric 
277*5f757f3fSDimitry Andric     return Result.extend(BitWidth) != Value;
278*5f757f3fSDimitry Andric   }
279*5f757f3fSDimitry Andric };
280*5f757f3fSDimitry Andric 
281*5f757f3fSDimitry Andric template <bool Signed>
282*5f757f3fSDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
283*5f757f3fSDimitry Andric                                      IntegralAP<Signed> I) {
284*5f757f3fSDimitry Andric   I.print(OS);
285*5f757f3fSDimitry Andric   return OS;
286*5f757f3fSDimitry Andric }
287*5f757f3fSDimitry Andric 
288*5f757f3fSDimitry Andric } // namespace interp
289*5f757f3fSDimitry Andric } // namespace clang
290*5f757f3fSDimitry Andric 
291*5f757f3fSDimitry Andric #endif
292