Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/IntegralAP.h
35292 views
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, 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>>>
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 ASTContext &) 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
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
163
IntegralAP<false> toUnsigned() const {
164
APInt Copy = V;
165
return IntegralAP<false>(Copy);
166
}
167
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
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
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
197
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
198
return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
199
}
200
201
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
202
return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
203
}
204
205
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
206
return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
207
}
208
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
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
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
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
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
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
250
static bool comp(IntegralAP A, IntegralAP *R) {
251
*R = IntegralAP(~A.V);
252
return false;
253
}
254
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
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 ===
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
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
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>
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>
321
IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {
322
return F;
323
}
324
325
} // namespace interp
326
} // namespace clang
327
328
#endif
329
330