xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/IntegralAP.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
32 /// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
33 /// It will NOT copy the memory (unless, of course, copy() is called) and it
34 /// won't alllocate anything. The allocation should happen via InterpState or
35 /// Program.
36 template <bool Signed> class IntegralAP final {
37 public:
38   union {
39     uint64_t *Memory = nullptr;
40     uint64_t Val;
41   };
42   uint32_t BitWidth = 0;
43   friend IntegralAP<!Signed>;
44 
45   template <typename T, bool InputSigned>
truncateCast(const APInt & V)46   static T truncateCast(const APInt &V) {
47     constexpr unsigned BitSize = sizeof(T) * 8;
48     if (BitSize >= V.getBitWidth()) {
49       APInt Extended;
50       if constexpr (InputSigned)
51         Extended = V.sext(BitSize);
52       else
53         Extended = V.zext(BitSize);
54       return std::is_signed_v<T> ? Extended.getSExtValue()
55                                  : Extended.getZExtValue();
56     }
57 
58     return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue()
59                                : V.trunc(BitSize).getZExtValue();
60   }
61 
getValue()62   APInt getValue() const {
63     if (singleWord())
64       return APInt(BitWidth, Val, Signed);
65     unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
66     return llvm::APInt(BitWidth, NumWords, Memory);
67   }
68 
69 public:
70   using AsUnsigned = IntegralAP<false>;
71 
take(uint64_t * NewMemory)72   void take(uint64_t *NewMemory) {
73     assert(!singleWord());
74     std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
75     Memory = NewMemory;
76   }
77 
copy(const APInt & V)78   void copy(const APInt &V) {
79     assert(BitWidth == V.getBitWidth());
80     assert(numWords() == V.getNumWords());
81 
82     if (V.isSingleWord()) {
83       if constexpr (Signed)
84         Val = V.getSExtValue();
85       else
86         Val = V.getZExtValue();
87       return;
88     }
89     assert(Memory);
90     std::memcpy(Memory, V.getRawData(), V.getNumWords() * sizeof(uint64_t));
91   }
92 
93   IntegralAP() = default;
94   /// Zeroed, single-word IntegralAP of the given bitwidth.
IntegralAP(unsigned BitWidth)95   IntegralAP(unsigned BitWidth) : Val(0), BitWidth(BitWidth) {
96     assert(singleWord());
97   }
IntegralAP(uint64_t * Memory,unsigned BitWidth)98   IntegralAP(uint64_t *Memory, unsigned BitWidth)
99       : Memory(Memory), BitWidth(BitWidth) {}
IntegralAP(const APInt & V)100   IntegralAP(const APInt &V) : BitWidth(V.getBitWidth()) {
101     if (V.isSingleWord()) {
102       Val = Signed ? V.getSExtValue() : V.getZExtValue();
103     } else {
104       Memory = const_cast<uint64_t *>(V.getRawData());
105     }
106   }
107 
108   IntegralAP operator-() const { return IntegralAP(-getValue()); }
109   bool operator>(const IntegralAP &RHS) const {
110     if constexpr (Signed)
111       return getValue().sgt(RHS.getValue());
112     return getValue().ugt(RHS.getValue());
113   }
114   bool operator>=(unsigned RHS) const {
115     if constexpr (Signed)
116       return getValue().sge(RHS);
117     return getValue().uge(RHS);
118   }
119   bool operator<(IntegralAP RHS) const {
120     if constexpr (Signed)
121       return getValue().slt(RHS.getValue());
122     return getValue().ult(RHS.getValue());
123   }
124 
125   template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
Ty()126   explicit operator Ty() const {
127     return truncateCast<Ty, Signed>(getValue());
128   }
129 
130   template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
131     if (NumBits == 0)
132       NumBits = sizeof(T) * 8;
133     assert(NumBits > 0);
134     assert(APInt::getNumWords(NumBits) == 1);
135     APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);
136     return IntegralAP<Signed>(Copy);
137   }
138 
bitWidth()139   constexpr uint32_t bitWidth() const { return BitWidth; }
numWords()140   constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }
singleWord()141   constexpr bool singleWord() const { return numWords() == 1; }
142 
143   APSInt toAPSInt(unsigned Bits = 0) const {
144     if (Bits == 0)
145       Bits = bitWidth();
146 
147     APInt V = getValue();
148     if constexpr (Signed)
149       return APSInt(getValue().sext(Bits), !Signed);
150     else
151       return APSInt(getValue().zext(Bits), !Signed);
152   }
toAPValue(const ASTContext &)153   APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
154 
isZero()155   bool isZero() const { return getValue().isZero(); }
isPositive()156   bool isPositive() const {
157     if constexpr (Signed)
158       return getValue().isNonNegative();
159     return true;
160   }
isNegative()161   bool isNegative() const {
162     if constexpr (Signed)
163       return !getValue().isNonNegative();
164     return false;
165   }
isMin()166   bool isMin() const {
167     if constexpr (Signed)
168       return getValue().isMinSignedValue();
169     return getValue().isMinValue();
170   }
isMax()171   bool isMax() const {
172     if constexpr (Signed)
173       return getValue().isMaxSignedValue();
174     return getValue().isMaxValue();
175   }
isSigned()176   static constexpr bool isSigned() { return Signed; }
isMinusOne()177   bool isMinusOne() const { return Signed && getValue().isAllOnes(); }
178 
countLeadingZeros()179   unsigned countLeadingZeros() const { return getValue().countl_zero(); }
180 
print(llvm::raw_ostream & OS)181   void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }
toDiagnosticString(const ASTContext & Ctx)182   std::string toDiagnosticString(const ASTContext &Ctx) const {
183     std::string NameStr;
184     llvm::raw_string_ostream OS(NameStr);
185     print(OS);
186     return NameStr;
187   }
188 
truncate(unsigned BitWidth)189   IntegralAP truncate(unsigned BitWidth) const {
190     if constexpr (Signed)
191       return IntegralAP(
192           getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth()));
193     else
194       return IntegralAP(
195           getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth()));
196   }
197 
toUnsigned()198   IntegralAP<false> toUnsigned() const {
199     return IntegralAP<false>(Memory, BitWidth);
200   }
201 
bitcastToMemory(std::byte * Dest)202   void bitcastToMemory(std::byte *Dest) const {
203     llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8);
204   }
205 
bitcastFromMemory(const std::byte * Src,unsigned BitWidth,IntegralAP * Result)206   static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth,
207                                 IntegralAP *Result) {
208     APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
209     llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);
210     Result->copy(V);
211   }
212 
compare(const IntegralAP & RHS)213   ComparisonCategoryResult compare(const IntegralAP &RHS) const {
214     assert(Signed == RHS.isSigned());
215     assert(bitWidth() == RHS.bitWidth());
216     APInt V1 = getValue();
217     APInt V2 = RHS.getValue();
218     if constexpr (Signed) {
219       if (V1.slt(V2))
220         return ComparisonCategoryResult::Less;
221       if (V1.sgt(V2))
222         return ComparisonCategoryResult::Greater;
223       return ComparisonCategoryResult::Equal;
224     }
225 
226     assert(!Signed);
227     if (V1.ult(V2))
228       return ComparisonCategoryResult::Less;
229     if (V1.ugt(V2))
230       return ComparisonCategoryResult::Greater;
231     return ComparisonCategoryResult::Equal;
232   }
233 
increment(IntegralAP A,IntegralAP * R)234   static bool increment(IntegralAP A, IntegralAP *R) {
235     APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);
236     return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);
237   }
238 
decrement(IntegralAP A,IntegralAP * R)239   static bool decrement(IntegralAP A, IntegralAP *R) {
240     APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);
241     return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);
242   }
243 
add(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)244   static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
245     return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
246   }
247 
sub(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)248   static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
249     return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
250   }
251 
mul(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)252   static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
253     return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
254   }
255 
rem(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)256   static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
257     if constexpr (Signed)
258       R->copy(A.getValue().srem(B.getValue()));
259     else
260       R->copy(A.getValue().urem(B.getValue()));
261     return false;
262   }
263 
div(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)264   static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
265     if constexpr (Signed)
266       R->copy(A.getValue().sdiv(B.getValue()));
267     else
268       R->copy(A.getValue().udiv(B.getValue()));
269     return false;
270   }
271 
bitAnd(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)272   static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
273                      IntegralAP *R) {
274     R->copy(A.getValue() & B.getValue());
275     return false;
276   }
277 
bitOr(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)278   static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
279                     IntegralAP *R) {
280     R->copy(A.getValue() | B.getValue());
281     return false;
282   }
283 
bitXor(IntegralAP A,IntegralAP B,unsigned OpBits,IntegralAP * R)284   static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
285                      IntegralAP *R) {
286     R->copy(A.getValue() ^ B.getValue());
287     return false;
288   }
289 
neg(const IntegralAP & A,IntegralAP * R)290   static bool neg(const IntegralAP &A, IntegralAP *R) {
291     APInt AI = A.getValue();
292     AI.negate();
293     R->copy(AI);
294     return false;
295   }
296 
comp(IntegralAP A,IntegralAP * R)297   static bool comp(IntegralAP A, IntegralAP *R) {
298     R->copy(~A.getValue());
299     return false;
300   }
301 
shiftLeft(const IntegralAP A,const IntegralAP B,unsigned OpBits,IntegralAP * R)302   static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
303                         IntegralAP *R) {
304     *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue()));
305   }
306 
shiftRight(const IntegralAP A,const IntegralAP B,unsigned OpBits,IntegralAP * R)307   static void shiftRight(const IntegralAP A, const IntegralAP B,
308                          unsigned OpBits, IntegralAP *R) {
309     unsigned ShiftAmount = B.getValue().getZExtValue();
310     if constexpr (Signed)
311       R->copy(A.getValue().ashr(ShiftAmount));
312     else
313       R->copy(A.getValue().lshr(ShiftAmount));
314   }
315 
316   // === Serialization support ===
bytesToSerialize()317   size_t bytesToSerialize() const {
318     assert(BitWidth != 0);
319     return sizeof(uint32_t) + (numWords() * sizeof(uint64_t));
320   }
321 
serialize(std::byte * Buff)322   void serialize(std::byte *Buff) const {
323     std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
324     if (singleWord())
325       std::memcpy(Buff + sizeof(uint32_t), &Val, sizeof(uint64_t));
326     else {
327       std::memcpy(Buff + sizeof(uint32_t), Memory,
328                   numWords() * sizeof(uint64_t));
329     }
330   }
331 
deserializeSize(const std::byte * Buff)332   static uint32_t deserializeSize(const std::byte *Buff) {
333     return *reinterpret_cast<const uint32_t *>(Buff);
334   }
335 
deserialize(const std::byte * Buff,IntegralAP<Signed> * Result)336   static void deserialize(const std::byte *Buff, IntegralAP<Signed> *Result) {
337     uint32_t BitWidth = Result->BitWidth;
338     assert(BitWidth != 0);
339     unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
340 
341     if (NumWords == 1)
342       std::memcpy(&Result->Val, Buff + sizeof(uint32_t), sizeof(uint64_t));
343     else {
344       assert(Result->Memory);
345       std::memcpy(Result->Memory, Buff + sizeof(uint32_t),
346                   NumWords * sizeof(uint64_t));
347     }
348   }
349 
350 private:
351   template <template <typename T> class Op>
CheckAddSubMulUB(const IntegralAP & A,const IntegralAP & B,unsigned BitWidth,IntegralAP * R)352   static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
353                                unsigned BitWidth, IntegralAP *R) {
354     if constexpr (!Signed) {
355       R->copy(Op<APInt>{}(A.getValue(), B.getValue()));
356       return false;
357     }
358 
359     const APSInt &LHS = A.toAPSInt();
360     const APSInt &RHS = B.toAPSInt();
361     APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
362     APSInt Result = Value.trunc(LHS.getBitWidth());
363     R->copy(Result);
364 
365     return Result.extend(BitWidth) != Value;
366   }
367 };
368 
369 template <bool Signed>
370 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
371                                      IntegralAP<Signed> I) {
372   I.print(OS);
373   return OS;
374 }
375 
376 template <bool Signed>
getSwappedBytes(IntegralAP<Signed> F)377 IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {
378   return F;
379 }
380 
381 } // namespace interp
382 } // namespace clang
383 
384 #endif
385