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