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