clang 23.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, llvm::ArrayRef(Memory, NumWords));
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)
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 {
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 constexpr static bool isNumber() { return true; }
143
144 APSInt toAPSInt(unsigned Bits = 0) const {
145 if (Bits == 0)
146 Bits = bitWidth();
147
148 APInt V = getValue();
149 if constexpr (Signed)
150 return APSInt(getValue().sext(Bits), !Signed);
151 else
152 return APSInt(getValue().zext(Bits), !Signed);
153 }
154 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
155
156 bool isZero() const { return getValue().isZero(); }
157 bool isPositive() const {
158 if constexpr (Signed)
159 return getValue().isNonNegative();
160 return true;
161 }
162 bool isNegative() const {
163 if constexpr (Signed)
164 return !getValue().isNonNegative();
165 return false;
166 }
167 bool isMin() const {
168 if constexpr (Signed)
169 return getValue().isMinSignedValue();
170 return getValue().isMinValue();
171 }
172 bool isMax() const {
173 if constexpr (Signed)
174 return getValue().isMaxSignedValue();
175 return getValue().isMaxValue();
176 }
177 static constexpr bool isSigned() { return Signed; }
178 bool isMinusOne() const { return Signed && getValue().isAllOnes(); }
179
180 unsigned countLeadingZeros() const { return getValue().countl_zero(); }
181
182 void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }
183 std::string toDiagnosticString(const ASTContext &Ctx) const {
184 std::string NameStr;
185 llvm::raw_string_ostream OS(NameStr);
186 print(OS);
187 return NameStr;
188 }
189
190 IntegralAP truncate(unsigned BitWidth) const {
191 if constexpr (Signed)
192 return IntegralAP(
193 getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth()));
194 else
195 return IntegralAP(
196 getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth()));
197 }
198
202
203 void bitcastToMemory(std::byte *Dest) const {
204 llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8);
205 }
206
207 static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth,
209 APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
210 llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);
211 Result->copy(V);
212 }
213
215 assert(Signed == RHS.isSigned());
216 assert(bitWidth() == RHS.bitWidth());
217 APInt V1 = getValue();
218 APInt V2 = RHS.getValue();
219 if constexpr (Signed) {
220 if (V1.slt(V2))
222 if (V1.sgt(V2))
225 }
226
227 assert(!Signed);
228 if (V1.ult(V2))
230 if (V1.ugt(V2))
233 }
234
235 static bool increment(IntegralAP A, IntegralAP *R) {
236 APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);
237 return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);
238 }
239
240 static bool decrement(IntegralAP A, IntegralAP *R) {
241 APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);
242 return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);
243 }
244
245 static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
246 return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
247 }
248
249 static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
250 return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
251 }
252
253 static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
254 return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
255 }
256
257 static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
258 if constexpr (Signed)
259 R->copy(A.getValue().srem(B.getValue()));
260 else
261 R->copy(A.getValue().urem(B.getValue()));
262 return false;
263 }
264
265 static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
266 if constexpr (Signed)
267 R->copy(A.getValue().sdiv(B.getValue()));
268 else
269 R->copy(A.getValue().udiv(B.getValue()));
270 return false;
271 }
272
273 static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
274 IntegralAP *R) {
275 R->copy(A.getValue() & B.getValue());
276 return false;
277 }
278
279 static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
280 IntegralAP *R) {
281 R->copy(A.getValue() | B.getValue());
282 return false;
283 }
284
285 static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
286 IntegralAP *R) {
287 R->copy(A.getValue() ^ B.getValue());
288 return false;
289 }
290
291 static bool neg(const IntegralAP &A, IntegralAP *R) {
292 APInt AI = A.getValue();
293 AI.negate();
294 R->copy(AI);
295 return false;
296 }
297
298 static bool comp(IntegralAP A, IntegralAP *R) {
299 R->copy(~A.getValue());
300 return false;
301 }
302
303 static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
304 IntegralAP *R) {
305 *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue()));
306 }
307
308 static void shiftRight(const IntegralAP A, const IntegralAP B,
309 unsigned OpBits, IntegralAP *R) {
310 unsigned ShiftAmount = B.getValue().getZExtValue();
311 if constexpr (Signed)
312 R->copy(A.getValue().ashr(ShiftAmount));
313 else
314 R->copy(A.getValue().lshr(ShiftAmount));
315 }
316
317 // === Serialization support ===
318 size_t bytesToSerialize() const {
319 assert(BitWidth != 0);
320 return sizeof(uint32_t) + (numWords() * sizeof(uint64_t));
321 }
322
323 void serialize(std::byte *Buff) const {
324 std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
325 if (singleWord())
326 std::memcpy(Buff + sizeof(uint32_t), &Val, sizeof(uint64_t));
327 else {
328 std::memcpy(Buff + sizeof(uint32_t), Memory,
329 numWords() * sizeof(uint64_t));
330 }
331 }
332
333 static uint32_t deserializeSize(const std::byte *Buff) {
334 return *reinterpret_cast<const uint32_t *>(Buff);
335 }
336
337 static void deserialize(const std::byte *Buff, IntegralAP<Signed> *Result) {
338 uint32_t BitWidth = Result->BitWidth;
339 assert(BitWidth != 0);
340 unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
341
342 if (NumWords == 1)
343 std::memcpy(&Result->Val, Buff + sizeof(uint32_t), sizeof(uint64_t));
344 else {
345 assert(Result->Memory);
346 std::memcpy(Result->Memory, Buff + sizeof(uint32_t),
347 NumWords * sizeof(uint64_t));
348 }
349 }
350
351private:
352 template <template <typename T> class Op>
353 static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
354 unsigned BitWidth, IntegralAP *R) {
355 if constexpr (!Signed) {
356 R->copy(Op<APInt>{}(A.getValue(), B.getValue()));
357 return false;
358 }
359
360 const APSInt &LHS = A.toAPSInt();
361 const APSInt &RHS = B.toAPSInt();
362 APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
363 APSInt Result = Value.trunc(LHS.getBitWidth());
364 R->copy(Result);
365
366 return Result.extend(BitWidth) != Value;
367 }
368};
369
370template <bool Signed>
371inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
373 I.print(OS);
374 return OS;
375}
376
377template <bool Signed>
381
382} // namespace interp
383} // namespace clang
384
385#endif
#define V(N, I)
static uint32_t getBitWidth(const Expr *E)
llvm::APSInt APSInt
Definition Compiler.cpp:24
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:227
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:182
static constexpr bool isSigned()
Definition IntegralAP.h:177
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:303
IntegralAP(uint64_t *Memory, unsigned BitWidth)
Definition IntegralAP.h:98
IntegralAP< false > toUnsigned() const
Definition IntegralAP.h:199
static uint32_t deserializeSize(const std::byte *Buff)
Definition IntegralAP.h:333
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:257
void serialize(std::byte *Buff) const
Definition IntegralAP.h:323
static bool decrement(IntegralAP A, IntegralAP *R)
Definition IntegralAP.h:240
static bool increment(IntegralAP A, IntegralAP *R)
Definition IntegralAP.h:235
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:279
constexpr bool singleWord() const
Definition IntegralAP.h:141
static void shiftRight(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:308
bool operator>(const IntegralAP &RHS) const
Definition IntegralAP.h:109
APValue toAPValue(const ASTContext &) const
Definition IntegralAP.h:154
void bitcastToMemory(std::byte *Dest) const
Definition IntegralAP.h:203
static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, IntegralAP *Result)
Definition IntegralAP.h:207
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition IntegralAP.h:183
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:144
static IntegralAP from(T Value, unsigned NumBits=0)
Definition IntegralAP.h:130
ComparisonCategoryResult compare(const IntegralAP &RHS) const
Definition IntegralAP.h:214
IntegralAP truncate(unsigned BitWidth) const
Definition IntegralAP.h:190
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:245
static void deserialize(const std::byte *Buff, IntegralAP< Signed > *Result)
Definition IntegralAP.h:337
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:285
IntegralAP operator-() const
Definition IntegralAP.h:108
IntegralAP< false > AsUnsigned
Definition IntegralAP.h:70
constexpr uint32_t bitWidth() const
Definition IntegralAP.h:139
size_t bytesToSerialize() const
Definition IntegralAP.h:318
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:265
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:249
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:253
static constexpr bool isNumber()
Definition IntegralAP.h:142
unsigned countLeadingZeros() const
Definition IntegralAP.h:180
static bool comp(IntegralAP A, IntegralAP *R)
Definition IntegralAP.h:298
bool operator<(IntegralAP RHS) const
Definition IntegralAP.h:119
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition IntegralAP.h:273
static bool neg(const IntegralAP &A, IntegralAP *R)
Definition IntegralAP.h:291
constexpr unsigned numWords() const
Definition IntegralAP.h:140
FixedPoint getSwappedBytes(FixedPoint F)
Definition FixedPoint.h:188
llvm::APInt APInt
Definition FixedPoint.h:19
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition Boolean.h:153
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.
Definition TypeBase.h:905
A quantity in bits.
#define trunc(__x)
Definition tgmath.h:1216