Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/IntegralAP.h
213799 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
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>
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
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
72
void take(uint64_t *NewMemory) {
73
assert(!singleWord());
74
std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
75
Memory = NewMemory;
76
}
77
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.
95
IntegralAP(unsigned BitWidth) : Val(0), BitWidth(BitWidth) {
96
assert(singleWord());
97
}
98
IntegralAP(uint64_t *Memory, unsigned BitWidth)
99
: Memory(Memory), BitWidth(BitWidth) {}
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>>>
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
139
constexpr uint32_t bitWidth() const { return BitWidth; }
140
constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }
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
}
153
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
154
155
bool isZero() const { return getValue().isZero(); }
156
bool isPositive() const {
157
if constexpr (Signed)
158
return getValue().isNonNegative();
159
return true;
160
}
161
bool isNegative() const {
162
if constexpr (Signed)
163
return !getValue().isNonNegative();
164
return false;
165
}
166
bool isMin() const {
167
if constexpr (Signed)
168
return getValue().isMinSignedValue();
169
return getValue().isMinValue();
170
}
171
bool isMax() const {
172
if constexpr (Signed)
173
return getValue().isMaxSignedValue();
174
return getValue().isMaxValue();
175
}
176
static constexpr bool isSigned() { return Signed; }
177
bool isMinusOne() const { return Signed && getValue().isAllOnes(); }
178
179
unsigned countLeadingZeros() const { return getValue().countl_zero(); }
180
181
void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }
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
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
198
IntegralAP<false> toUnsigned() const {
199
return IntegralAP<false>(Memory, BitWidth);
200
}
201
202
void bitcastToMemory(std::byte *Dest) const {
203
llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8);
204
}
205
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
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
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
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
244
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
245
return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
246
}
247
248
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
249
return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
250
}
251
252
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
253
return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
254
}
255
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
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
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
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
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
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
297
static bool comp(IntegralAP A, IntegralAP *R) {
298
R->copy(~A.getValue());
299
return false;
300
}
301
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
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 ===
317
size_t bytesToSerialize() const {
318
assert(BitWidth != 0);
319
return sizeof(uint32_t) + (numWords() * sizeof(uint64_t));
320
}
321
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
332
static uint32_t deserializeSize(const std::byte *Buff) {
333
return *reinterpret_cast<const uint32_t *>(Buff);
334
}
335
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>
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>
377
IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {
378
return F;
379
}
380
381
} // namespace interp
382
} // namespace clang
383
384
#endif
385
386