clang 22.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;
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.
36template <bool Signed> class IntegralAP final {
37public:
38 union {
39 uint64_t *Memory = nullptr;
40 uint64_t Val;
41 };
42 uint32_t BitWidth = 0;
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
69public:
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.
96 assert(singleWord());
97 }
98 IntegralAP(uint64_t *Memory, unsigned 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
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,
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
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))
221 if (V1.sgt(V2))
224 }
225
226 assert(!Signed);
227 if (V1.ult(V2))
229 if (V1.ugt(V2))
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
350private:
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
369template <bool Signed>
370inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
372 I.print(OS);
373 return OS;
374}
375
376template <bool Signed>
378 return F;
379}
380
381} // namespace interp
382} // namespace clang
383
384#endif
#define V(N, I)
Definition: ASTContext.h:3597
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
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition: IntegralAP.h:36
IntegralAP(unsigned BitWidth)
Zeroed, single-word IntegralAP of the given bitwidth.
Definition: IntegralAP.h:95
void take(uint64_t *NewMemory)
Definition: IntegralAP.h:72
void print(llvm::raw_ostream &OS) const
Definition: IntegralAP.h:181
static constexpr bool isSigned()
Definition: IntegralAP.h:176
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:302
IntegralAP(uint64_t *Memory, unsigned BitWidth)
Definition: IntegralAP.h:98
IntegralAP< false > toUnsigned() const
Definition: IntegralAP.h:198
static uint32_t deserializeSize(const std::byte *Buff)
Definition: IntegralAP.h:332
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:256
void serialize(std::byte *Buff) const
Definition: IntegralAP.h:322
static bool decrement(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:239
static bool increment(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:234
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:278
constexpr bool singleWord() const
Definition: IntegralAP.h:141
static void shiftRight(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:307
bool operator>(const IntegralAP &RHS) const
Definition: IntegralAP.h:109
APValue toAPValue(const ASTContext &) const
Definition: IntegralAP.h:153
void bitcastToMemory(std::byte *Dest) const
Definition: IntegralAP.h:202
static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, IntegralAP *Result)
Definition: IntegralAP.h:206
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition: IntegralAP.h:182
IntegralAP(const APInt &V)
Definition: IntegralAP.h:100
bool operator>=(unsigned RHS) const
Definition: IntegralAP.h:114
APSInt toAPSInt(unsigned Bits=0) const
Definition: IntegralAP.h:143
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:130
APInt getValue() const
Definition: IntegralAP.h:62
ComparisonCategoryResult compare(const IntegralAP &RHS) const
Definition: IntegralAP.h:213
IntegralAP truncate(unsigned BitWidth) const
Definition: IntegralAP.h:189
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:244
static void deserialize(const std::byte *Buff, IntegralAP< Signed > *Result)
Definition: IntegralAP.h:336
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:284
IntegralAP operator-() const
Definition: IntegralAP.h:108
constexpr uint32_t bitWidth() const
Definition: IntegralAP.h:139
size_t bytesToSerialize() const
Definition: IntegralAP.h:317
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:264
static T truncateCast(const APInt &V)
Definition: IntegralAP.h:46
void copy(const APInt &V)
Definition: IntegralAP.h:78
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:248
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:252
unsigned countLeadingZeros() const
Definition: IntegralAP.h:179
static bool comp(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:297
bool operator<(IntegralAP RHS) const
Definition: IntegralAP.h:119
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:272
static bool neg(const IntegralAP &A, IntegralAP *R)
Definition: IntegralAP.h:290
constexpr unsigned numWords() const
Definition: IntegralAP.h:140
llvm::APInt APInt
Definition: FixedPoint.h:19
FixedPoint getSwappedBytes(FixedPoint F)
Definition: FixedPoint.h:188
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition: Boolean.h:154
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
A quantity in bits.
Definition: BitcastBuffer.h:24
#define trunc(__x)
Definition: tgmath.h:1216