xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/IntegralAP.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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>
truncateCast(const APInt & V)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>
IntegralAP(T Value,unsigned BitWidth)59   IntegralAP(T Value, unsigned BitWidth)
60       : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {}
61 
IntegralAP(APInt V)62   IntegralAP(APInt V) : V(V) {}
63   /// Arbitrary value for uninitialized variables.
IntegralAP()64   IntegralAP() : IntegralAP(-1, 3) {}
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>>>
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>
from(Integral<Bits,InputSigned> I,unsigned BitWidth)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 
zero(int32_t BitWidth)120   static IntegralAP zero(int32_t BitWidth) {
121     APInt V = APInt(BitWidth, 0LL, Signed);
122     return IntegralAP(V);
123   }
124 
bitWidth()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   }
toAPValue(const ASTContext &)136   APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
137 
isZero()138   bool isZero() const { return V.isZero(); }
isPositive()139   bool isPositive() const { return V.isNonNegative(); }
isNegative()140   bool isNegative() const { return !V.isNonNegative(); }
isMin()141   bool isMin() const { return V.isMinValue(); }
isMax()142   bool isMax() const { return V.isMaxValue(); }
isSigned()143   static constexpr bool isSigned() { return Signed; }
isMinusOne()144   bool isMinusOne() const { return Signed && V == -1; }
145 
countLeadingZeros()146   unsigned countLeadingZeros() const { return V.countl_zero(); }
147 
print(llvm::raw_ostream & OS)148   void print(llvm::raw_ostream &OS) const { OS << V; }
toDiagnosticString(const ASTContext & Ctx)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 
truncate(unsigned BitWidth)156   IntegralAP truncate(unsigned BitWidth) const {
157     if constexpr (Signed)
158       return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));
159     else
160       return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));
161   }
162 
toUnsigned()163   IntegralAP<false> toUnsigned() const {
164     APInt Copy = V;
165     return IntegralAP<false>(Copy);
166   }
167 
compare(const IntegralAP & RHS)168   ComparisonCategoryResult compare(const IntegralAP &RHS) const {
169     assert(Signed == RHS.isSigned());
170     assert(bitWidth() == RHS.bitWidth());
171     if constexpr (Signed) {
172       if (V.slt(RHS.V))
173         return ComparisonCategoryResult::Less;
174       if (V.sgt(RHS.V))
175         return ComparisonCategoryResult::Greater;
176       return ComparisonCategoryResult::Equal;
177     }
178 
179     assert(!Signed);
180     if (V.ult(RHS.V))
181       return ComparisonCategoryResult::Less;
182     if (V.ugt(RHS.V))
183       return ComparisonCategoryResult::Greater;
184     return ComparisonCategoryResult::Equal;
185   }
186 
increment(IntegralAP A,IntegralAP * R)187   static bool increment(IntegralAP A, IntegralAP *R) {
188     IntegralAP<Signed> One(1, A.bitWidth());
189     return add(A, One, A.bitWidth() + 1, R);
190   }
191 
decrement(IntegralAP A,IntegralAP * R)192   static bool decrement(IntegralAP A, IntegralAP *R) {
193     IntegralAP<Signed> One(1, A.bitWidth());
194     return sub(A, One, A.bitWidth() + 1, R);
195   }
196 
add(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)197   static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
198     return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
199   }
200 
sub(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)201   static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
202     return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
203   }
204 
mul(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)205   static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
206     return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
207   }
208 
rem(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)209   static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
210     if constexpr (Signed)
211       *R = IntegralAP(A.V.srem(B.V));
212     else
213       *R = IntegralAP(A.V.urem(B.V));
214     return false;
215   }
216 
div(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)217   static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
218     if constexpr (Signed)
219       *R = IntegralAP(A.V.sdiv(B.V));
220     else
221       *R = IntegralAP(A.V.udiv(B.V));
222     return false;
223   }
224 
bitAnd(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)225   static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
226                      IntegralAP *R) {
227     *R = IntegralAP(A.V & B.V);
228     return false;
229   }
230 
bitOr(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)231   static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
232                     IntegralAP *R) {
233     *R = IntegralAP(A.V | B.V);
234     return false;
235   }
236 
bitXor(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)237   static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
238                      IntegralAP *R) {
239     *R = IntegralAP(A.V ^ B.V);
240     return false;
241   }
242 
neg(const IntegralAP & A,IntegralAP * R)243   static bool neg(const IntegralAP &A, IntegralAP *R) {
244     APInt AI = A.V;
245     AI.negate();
246     *R = IntegralAP(AI);
247     return false;
248   }
249 
comp(IntegralAP A,IntegralAP * R)250   static bool comp(IntegralAP A, IntegralAP *R) {
251     *R = IntegralAP(~A.V);
252     return false;
253   }
254 
shiftLeft(const IntegralAP A,const IntegralAP B,unsigned OpBits,IntegralAP * R)255   static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
256                         IntegralAP *R) {
257     *R = IntegralAP(A.V.shl(B.V.getZExtValue()));
258   }
259 
shiftRight(const IntegralAP A,const IntegralAP B,unsigned OpBits,IntegralAP * R)260   static void shiftRight(const IntegralAP A, const IntegralAP B,
261                          unsigned OpBits, IntegralAP *R) {
262     unsigned ShiftAmount = B.V.getZExtValue();
263     if constexpr (Signed)
264       *R = IntegralAP(A.V.ashr(ShiftAmount));
265     else
266       *R = IntegralAP(A.V.lshr(ShiftAmount));
267   }
268 
269   // === Serialization support ===
bytesToSerialize()270   size_t bytesToSerialize() const {
271     // 4 bytes for the BitWidth followed by N bytes for the actual APInt.
272     return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT);
273   }
274 
serialize(std::byte * Buff)275   void serialize(std::byte *Buff) const {
276     assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max());
277     uint32_t BitWidth = V.getBitWidth();
278 
279     std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
280     llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)),
281                            BitWidth / CHAR_BIT);
282   }
283 
deserialize(const std::byte * Buff)284   static IntegralAP<Signed> deserialize(const std::byte *Buff) {
285     uint32_t BitWidth;
286     std::memcpy(&BitWidth, Buff, sizeof(uint32_t));
287     IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed));
288 
289     llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t),
290                             BitWidth / CHAR_BIT);
291     return Val;
292   }
293 
294 private:
295   template <template <typename T> class Op>
CheckAddSubMulUB(const IntegralAP & A,const IntegralAP & B,unsigned BitWidth,IntegralAP * R)296   static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
297                                unsigned BitWidth, IntegralAP *R) {
298     if constexpr (!Signed) {
299       R->V = Op<APInt>{}(A.V, B.V);
300       return false;
301     }
302 
303     const APSInt &LHS = A.toAPSInt();
304     const APSInt &RHS = B.toAPSInt();
305     APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
306     APSInt Result = Value.trunc(LHS.getBitWidth());
307     R->V = Result;
308 
309     return Result.extend(BitWidth) != Value;
310   }
311 };
312 
313 template <bool Signed>
314 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
315                                      IntegralAP<Signed> I) {
316   I.print(OS);
317   return OS;
318 }
319 
320 template <bool Signed>
getSwappedBytes(IntegralAP<Signed> F)321 IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {
322   return F;
323 }
324 
325 } // namespace interp
326 } // namespace clang
327 
328 #endif
329