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/Integral.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_H
14
#define LLVM_CLANG_AST_INTERP_INTEGRAL_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
template <bool Signed> class IntegralAP;
33
34
// Helper structure to select the representation.
35
template <unsigned Bits, bool Signed> struct Repr;
36
template <> struct Repr<8, false> {
37
using Type = uint8_t;
38
};
39
template <> struct Repr<16, false> {
40
using Type = uint16_t;
41
};
42
template <> struct Repr<32, false> {
43
using Type = uint32_t;
44
};
45
template <> struct Repr<64, false> {
46
using Type = uint64_t;
47
};
48
template <> struct Repr<8, true> {
49
using Type = int8_t;
50
};
51
template <> struct Repr<16, true> {
52
using Type = int16_t;
53
};
54
template <> struct Repr<32, true> {
55
using Type = int32_t;
56
};
57
template <> struct Repr<64, true> {
58
using Type = int64_t;
59
};
60
61
/// Wrapper around numeric types.
62
///
63
/// These wrappers are required to shared an interface between APSint and
64
/// builtin primitive numeral types, while optimising for storage and
65
/// allowing methods operating on primitive type to compile to fast code.
66
template <unsigned Bits, bool Signed> class Integral final {
67
private:
68
template <unsigned OtherBits, bool OtherSigned> friend class Integral;
69
70
// The primitive representing the integral.
71
using ReprT = typename Repr<Bits, Signed>::Type;
72
ReprT V;
73
static_assert(std::is_trivially_copyable_v<ReprT>);
74
75
/// Primitive representing limits.
76
static const auto Min = std::numeric_limits<ReprT>::min();
77
static const auto Max = std::numeric_limits<ReprT>::max();
78
79
/// Construct an integral from anything that is convertible to storage.
80
template <typename T> explicit Integral(T V) : V(V) {}
81
82
public:
83
using AsUnsigned = Integral<Bits, false>;
84
85
/// Zero-initializes an integral.
86
Integral() : V(0) {}
87
88
/// Constructs an integral from another integral.
89
template <unsigned SrcBits, bool SrcSign>
90
explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
91
92
/// Construct an integral from a value based on signedness.
93
explicit Integral(const APSInt &V)
94
: V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
95
96
bool operator<(Integral RHS) const { return V < RHS.V; }
97
bool operator>(Integral RHS) const { return V > RHS.V; }
98
bool operator<=(Integral RHS) const { return V <= RHS.V; }
99
bool operator>=(Integral RHS) const { return V >= RHS.V; }
100
bool operator==(Integral RHS) const { return V == RHS.V; }
101
bool operator!=(Integral RHS) const { return V != RHS.V; }
102
bool operator>=(unsigned RHS) const {
103
return static_cast<unsigned>(V) >= RHS;
104
}
105
106
bool operator>(unsigned RHS) const {
107
return V >= 0 && static_cast<unsigned>(V) > RHS;
108
}
109
110
Integral operator-() const { return Integral(-V); }
111
Integral operator-(const Integral &Other) const {
112
return Integral(V - Other.V);
113
}
114
Integral operator~() const { return Integral(~V); }
115
116
template <unsigned DstBits, bool DstSign>
117
explicit operator Integral<DstBits, DstSign>() const {
118
return Integral<DstBits, DstSign>(V);
119
}
120
121
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
122
explicit operator Ty() const {
123
return V;
124
}
125
126
APSInt toAPSInt() const {
127
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
128
}
129
APSInt toAPSInt(unsigned BitWidth) const {
130
return APSInt(toAPInt(BitWidth), !Signed);
131
}
132
APInt toAPInt(unsigned BitWidth) const {
133
if constexpr (Signed)
134
return APInt(Bits, static_cast<uint64_t>(V), Signed)
135
.sextOrTrunc(BitWidth);
136
else
137
return APInt(Bits, static_cast<uint64_t>(V), Signed)
138
.zextOrTrunc(BitWidth);
139
}
140
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
141
142
Integral<Bits, false> toUnsigned() const {
143
return Integral<Bits, false>(*this);
144
}
145
146
constexpr static unsigned bitWidth() { return Bits; }
147
148
bool isZero() const { return !V; }
149
150
bool isMin() const { return *this == min(bitWidth()); }
151
152
bool isMinusOne() const { return Signed && V == ReprT(-1); }
153
154
constexpr static bool isSigned() { return Signed; }
155
156
bool isNegative() const { return V < ReprT(0); }
157
bool isPositive() const { return !isNegative(); }
158
159
ComparisonCategoryResult compare(const Integral &RHS) const {
160
return Compare(V, RHS.V);
161
}
162
163
void bitcastToMemory(std::byte *Dest) const {
164
std::memcpy(Dest, &V, sizeof(V));
165
}
166
167
static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
168
assert(BitWidth == sizeof(ReprT) * 8);
169
ReprT V;
170
171
std::memcpy(&V, Src, sizeof(ReprT));
172
return Integral(V);
173
}
174
175
std::string toDiagnosticString(const ASTContext &Ctx) const {
176
std::string NameStr;
177
llvm::raw_string_ostream OS(NameStr);
178
OS << V;
179
return NameStr;
180
}
181
182
unsigned countLeadingZeros() const {
183
if constexpr (!Signed)
184
return llvm::countl_zero<ReprT>(V);
185
if (isPositive())
186
return llvm::countl_zero<typename AsUnsigned::ReprT>(
187
static_cast<typename AsUnsigned::ReprT>(V));
188
llvm_unreachable("Don't call countLeadingZeros() on negative values.");
189
}
190
191
Integral truncate(unsigned TruncBits) const {
192
assert(TruncBits >= 1);
193
if (TruncBits >= Bits)
194
return *this;
195
const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
196
const ReprT SignBit = ReprT(1) << (TruncBits - 1);
197
const ReprT ExtMask = ~BitMask;
198
return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
199
}
200
201
void print(llvm::raw_ostream &OS) const { OS << V; }
202
203
static Integral min(unsigned NumBits) { return Integral(Min); }
204
static Integral max(unsigned NumBits) { return Integral(Max); }
205
206
template <typename ValT> static Integral from(ValT Value) {
207
if constexpr (std::is_integral<ValT>::value)
208
return Integral(Value);
209
else
210
return Integral::from(static_cast<Integral::ReprT>(Value));
211
}
212
213
template <unsigned SrcBits, bool SrcSign>
214
static std::enable_if_t<SrcBits != 0, Integral>
215
from(Integral<SrcBits, SrcSign> Value) {
216
return Integral(Value.V);
217
}
218
219
static Integral zero(unsigned BitWidth = 0) { return from(0); }
220
221
template <typename T> static Integral from(T Value, unsigned NumBits) {
222
return Integral(Value);
223
}
224
225
static bool inRange(int64_t Value, unsigned NumBits) {
226
return CheckRange<ReprT, Min, Max>(Value);
227
}
228
229
static bool increment(Integral A, Integral *R) {
230
return add(A, Integral(ReprT(1)), A.bitWidth(), R);
231
}
232
233
static bool decrement(Integral A, Integral *R) {
234
return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
235
}
236
237
static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
238
return CheckAddUB(A.V, B.V, R->V);
239
}
240
241
static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
242
return CheckSubUB(A.V, B.V, R->V);
243
}
244
245
static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
246
return CheckMulUB(A.V, B.V, R->V);
247
}
248
249
static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
250
*R = Integral(A.V % B.V);
251
return false;
252
}
253
254
static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
255
*R = Integral(A.V / B.V);
256
return false;
257
}
258
259
static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
260
*R = Integral(A.V & B.V);
261
return false;
262
}
263
264
static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
265
*R = Integral(A.V | B.V);
266
return false;
267
}
268
269
static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
270
*R = Integral(A.V ^ B.V);
271
return false;
272
}
273
274
static bool neg(Integral A, Integral *R) {
275
if (Signed && A.isMin())
276
return true;
277
278
*R = -A;
279
return false;
280
}
281
282
static bool comp(Integral A, Integral *R) {
283
*R = Integral(~A.V);
284
return false;
285
}
286
287
template <unsigned RHSBits, bool RHSSign>
288
static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
289
unsigned OpBits, Integral *R) {
290
*R = Integral::from(A.V << B.V, OpBits);
291
}
292
293
template <unsigned RHSBits, bool RHSSign>
294
static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
295
unsigned OpBits, Integral *R) {
296
*R = Integral::from(A.V >> B.V, OpBits);
297
}
298
299
private:
300
template <typename T> static bool CheckAddUB(T A, T B, T &R) {
301
if constexpr (std::is_signed_v<T>) {
302
return llvm::AddOverflow<T>(A, B, R);
303
} else {
304
R = A + B;
305
return false;
306
}
307
}
308
309
template <typename T> static bool CheckSubUB(T A, T B, T &R) {
310
if constexpr (std::is_signed_v<T>) {
311
return llvm::SubOverflow<T>(A, B, R);
312
} else {
313
R = A - B;
314
return false;
315
}
316
}
317
318
template <typename T> static bool CheckMulUB(T A, T B, T &R) {
319
if constexpr (std::is_signed_v<T>) {
320
return llvm::MulOverflow<T>(A, B, R);
321
} else {
322
R = A * B;
323
return false;
324
}
325
}
326
template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
327
if constexpr (std::is_signed_v<T>) {
328
return Min <= V && V <= Max;
329
} else {
330
return V >= 0 && static_cast<uint64_t>(V) <= Max;
331
}
332
}
333
};
334
335
template <unsigned Bits, bool Signed>
336
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
337
I.print(OS);
338
return OS;
339
}
340
341
} // namespace interp
342
} // namespace clang
343
344
#endif
345
346