clang 20.0.0git
IntegralAP.h
Go to the documentation of this file.
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"
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
26namespace clang {
27namespace interp {
28
29using APInt = llvm::APInt;
30using APSInt = llvm::APSInt;
31template <unsigned Bits, bool Signed> class Integral;
32
33template <bool Signed> class IntegralAP final {
34private:
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
55public:
57
58 template <typename T>
59 IntegralAP(T Value, unsigned BitWidth)
60 : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {}
61
63 /// Arbitrary value for uninitialized variables.
64 IntegralAP() : IntegralAP(Signed ? -1 : 7, 3) {}
65
66 IntegralAP operator-() const { return IntegralAP(-V); }
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 return IntegralAP<Signed>(I.toAPInt(BitWidth));
116 }
117
118 static IntegralAP zero(int32_t BitWidth) {
119 APInt V = APInt(BitWidth, 0LL, Signed);
120 return IntegralAP(V);
121 }
122
123 constexpr unsigned bitWidth() const { return V.getBitWidth(); }
124
125 APSInt toAPSInt(unsigned Bits = 0) const {
126 if (Bits == 0)
127 Bits = bitWidth();
128
129 if constexpr (Signed)
130 return APSInt(V.sext(Bits), !Signed);
131 else
132 return APSInt(V.zext(Bits), !Signed);
133 }
134 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
135
136 bool isZero() const { return V.isZero(); }
137 bool isPositive() const {
138 if constexpr (Signed)
139 return V.isNonNegative();
140 return true;
141 }
142 bool isNegative() const {
143 if constexpr (Signed)
144 return !V.isNonNegative();
145 return false;
146 }
147 bool isMin() const { return V.isMinValue(); }
148 bool isMax() const { return V.isMaxValue(); }
149 static constexpr bool isSigned() { return Signed; }
150 bool isMinusOne() const { return Signed && V == -1; }
151
152 unsigned countLeadingZeros() const { return V.countl_zero(); }
153
154 void print(llvm::raw_ostream &OS) const { V.print(OS, Signed);}
155 std::string toDiagnosticString(const ASTContext &Ctx) const {
156 std::string NameStr;
157 llvm::raw_string_ostream OS(NameStr);
158 print(OS);
159 return NameStr;
160 }
161
162 IntegralAP truncate(unsigned BitWidth) const {
163 if constexpr (Signed)
164 return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));
165 else
166 return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));
167 }
168
170 APInt Copy = V;
171 return IntegralAP<false>(Copy);
172 }
173
174 void bitcastToMemory(std::byte *Dest) const {
175 llvm::StoreIntToMemory(V, (uint8_t *)Dest, bitWidth() / 8);
176 }
177
178 static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
179 APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
180 llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);
181 return IntegralAP(V);
182 }
183
185 assert(Signed == RHS.isSigned());
186 assert(bitWidth() == RHS.bitWidth());
187 if constexpr (Signed) {
188 if (V.slt(RHS.V))
190 if (V.sgt(RHS.V))
193 }
194
195 assert(!Signed);
196 if (V.ult(RHS.V))
198 if (V.ugt(RHS.V))
201 }
202
203 static bool increment(IntegralAP A, IntegralAP *R) {
204 IntegralAP<Signed> One(1, A.bitWidth());
205 return add(A, One, A.bitWidth() + 1, R);
206 }
207
208 static bool decrement(IntegralAP A, IntegralAP *R) {
209 IntegralAP<Signed> One(1, A.bitWidth());
210 return sub(A, One, A.bitWidth() + 1, R);
211 }
212
213 static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
214 return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
215 }
216
217 static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
218 return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
219 }
220
221 static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
222 return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
223 }
224
225 static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
226 if constexpr (Signed)
227 *R = IntegralAP(A.V.srem(B.V));
228 else
229 *R = IntegralAP(A.V.urem(B.V));
230 return false;
231 }
232
233 static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
234 if constexpr (Signed)
235 *R = IntegralAP(A.V.sdiv(B.V));
236 else
237 *R = IntegralAP(A.V.udiv(B.V));
238 return false;
239 }
240
241 static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
242 IntegralAP *R) {
243 *R = IntegralAP(A.V & B.V);
244 return false;
245 }
246
247 static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
248 IntegralAP *R) {
249 *R = IntegralAP(A.V | B.V);
250 return false;
251 }
252
253 static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
254 IntegralAP *R) {
255 *R = IntegralAP(A.V ^ B.V);
256 return false;
257 }
258
259 static bool neg(const IntegralAP &A, IntegralAP *R) {
260 APInt AI = A.V;
261 AI.negate();
262 *R = IntegralAP(AI);
263 return false;
264 }
265
266 static bool comp(IntegralAP A, IntegralAP *R) {
267 *R = IntegralAP(~A.V);
268 return false;
269 }
270
271 static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
272 IntegralAP *R) {
273 *R = IntegralAP(A.V.shl(B.V.getZExtValue()));
274 }
275
276 static void shiftRight(const IntegralAP A, const IntegralAP B,
277 unsigned OpBits, IntegralAP *R) {
278 unsigned ShiftAmount = B.V.getZExtValue();
279 if constexpr (Signed)
280 *R = IntegralAP(A.V.ashr(ShiftAmount));
281 else
282 *R = IntegralAP(A.V.lshr(ShiftAmount));
283 }
284
285 // === Serialization support ===
286 size_t bytesToSerialize() const {
287 // 4 bytes for the BitWidth followed by N bytes for the actual APInt.
288 return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT);
289 }
290
291 void serialize(std::byte *Buff) const {
292 assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max());
293 uint32_t BitWidth = V.getBitWidth();
294
295 std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
296 llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)),
297 BitWidth / CHAR_BIT);
298 }
299
300 static IntegralAP<Signed> deserialize(const std::byte *Buff) {
301 uint32_t BitWidth;
302 std::memcpy(&BitWidth, Buff, sizeof(uint32_t));
303 IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed));
304
305 llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t),
306 BitWidth / CHAR_BIT);
307 return Val;
308 }
309
310private:
311 template <template <typename T> class Op>
312 static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
313 unsigned BitWidth, IntegralAP *R) {
314 if constexpr (!Signed) {
315 R->V = Op<APInt>{}(A.V, B.V);
316 return false;
317 }
318
319 const APSInt &LHS = A.toAPSInt();
320 const APSInt &RHS = B.toAPSInt();
321 APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
322 APSInt Result = Value.trunc(LHS.getBitWidth());
323 R->V = Result;
324
325 return Result.extend(BitWidth) != Value;
326 }
327};
328
329template <bool Signed>
330inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
332 I.print(OS);
333 return OS;
334}
335
336template <bool Signed>
338 return F;
339}
340
341} // namespace interp
342} // namespace clang
343
344#endif
#define V(N, I)
Definition: ASTContext.h:3443
llvm::APSInt APSInt
Definition: Compiler.cpp:23
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:300
void print(llvm::raw_ostream &OS) const
Definition: IntegralAP.h:154
static constexpr bool isSigned()
Definition: IntegralAP.h:149
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:271
static IntegralAP zero(int32_t BitWidth)
Definition: IntegralAP.h:118
bool operator<=(IntegralAP RHS) const
Definition: IntegralAP.h:85
IntegralAP< false > toUnsigned() const
Definition: IntegralAP.h:169
static IntegralAP from(IntegralAP< InputSigned > V, unsigned NumBits=0)
Definition: IntegralAP.h:104
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:225
void serialize(std::byte *Buff) const
Definition: IntegralAP.h:291
static bool decrement(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:208
static bool increment(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:203
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:247
static void shiftRight(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:276
IntegralAP operator-(const IntegralAP &Other) const
Definition: IntegralAP.h:67
bool operator>(const IntegralAP &RHS) const
Definition: IntegralAP.h:70
APValue toAPValue(const ASTContext &) const
Definition: IntegralAP.h:134
void bitcastToMemory(std::byte *Dest) const
Definition: IntegralAP.h:174
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition: IntegralAP.h:155
IntegralAP(T Value, unsigned BitWidth)
Definition: IntegralAP.h:59
APSInt toAPSInt(unsigned Bits=0) const
Definition: IntegralAP.h:125
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
ComparisonCategoryResult compare(const IntegralAP &RHS) const
Definition: IntegralAP.h:184
IntegralAP truncate(unsigned BitWidth) const
Definition: IntegralAP.h:162
constexpr unsigned bitWidth() const
Definition: IntegralAP.h:123
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:213
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:253
IntegralAP operator-() const
Definition: IntegralAP.h:66
size_t bytesToSerialize() const
Definition: IntegralAP.h:286
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:233
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:217
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:221
static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth)
Definition: IntegralAP.h:178
bool operator>=(IntegralAP RHS) const
Definition: IntegralAP.h:75
unsigned countLeadingZeros() const
Definition: IntegralAP.h:152
static bool comp(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:266
bool operator<(IntegralAP RHS) const
Definition: IntegralAP.h:80
static IntegralAP from(Integral< Bits, InputSigned > I, unsigned BitWidth)
Definition: IntegralAP.h:114
IntegralAP()
Arbitrary value for uninitialized variables.
Definition: IntegralAP.h:64
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:241
static bool neg(const IntegralAP &A, IntegralAP *R)
Definition: IntegralAP.h:259
Wrapper around numeric types.
Definition: Integral.h:66
APInt toAPInt(unsigned BitWidth) const
Definition: Integral.h:129
#define CHAR_BIT
Definition: limits.h:71
llvm::APInt APInt
Definition: FixedPoint.h:19
FixedPoint getSwappedBytes(FixedPoint F)
Definition: FixedPoint.h:162
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition: Boolean.h:160
llvm::APSInt APSInt
Definition: FixedPoint.h:20
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Other
Other implicit parameter.
A quantity in bits.
Definition: BitcastBuffer.h:24