clang 23.0.0git
Integral.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_H
14#define LLVM_CLANG_AST_INTERP_INTEGRAL_H
15
16#include "clang/AST/APValue.h"
17#include "clang/AST/CharUnits.h"
19#include "llvm/ADT/APSInt.h"
20#include "llvm/Support/MathExtras.h"
21#include "llvm/Support/raw_ostream.h"
22#include <cstddef>
23#include <cstdint>
24
25#include "Descriptor.h"
26#include "InterpBlock.h"
27#include "Primitives.h"
28
29namespace clang {
30namespace interp {
31
32using APInt = llvm::APInt;
33using APSInt = llvm::APSInt;
34
35template <bool Signed> class IntegralAP;
36
37// Helper structure to select the representation.
38template <unsigned Bits, bool Signed> struct Repr;
39template <> struct Repr<8, false> {
40 using Type = uint8_t;
41};
42template <> struct Repr<16, false> {
43 using Type = uint16_t;
44};
45template <> struct Repr<32, false> {
46 using Type = uint32_t;
47};
48template <> struct Repr<64, false> {
49 using Type = uint64_t;
50};
51template <> struct Repr<8, true> {
52 using Type = int8_t;
53};
54template <> struct Repr<16, true> {
55 using Type = int16_t;
56};
57template <> struct Repr<32, true> {
58 using Type = int32_t;
59};
60template <> struct Repr<64, true> {
61 using Type = int64_t;
62};
63
64/// Wrapper around numeric types.
65///
66/// These wrappers are required to shared an interface between APSint and
67/// builtin primitive numeral types, while optimising for storage and
68/// allowing methods operating on primitive type to compile to fast code.
69template <unsigned Bits, bool Signed> class Integral final {
70 static_assert(Bits >= 16);
71
72public:
73 // The primitive representing the integral.
75
76private:
77 using OffsetT = intptr_t;
78 static_assert(std::is_trivially_copyable_v<ReprT>);
79 template <unsigned OtherBits, bool OtherSigned> friend class Integral;
80
82 union {
84 struct {
85 const void *P;
86 OffsetT Offset;
87 } Ptr;
88 struct {
92 };
93
94 /// Primitive representing limits.
95 static const auto Min = std::numeric_limits<ReprT>::min();
96 static const auto Max = std::numeric_limits<ReprT>::max();
97
98 /// Construct an integral from anything that is convertible to storage.
99 template <typename T> explicit Integral(T V) : V(V) {}
100 template <typename T>
101 explicit Integral(IntegralKind Kind, T V) : Kind(Kind), V(V) {}
102
103public:
105
106 /// Zero-initializes an integral.
107 Integral() : V(0) {}
108
109 /// Constructs an integral from another integral.
110 template <unsigned SrcBits, bool SrcSign>
111 explicit Integral(Integral<SrcBits, SrcSign> V) : Kind(V.Kind), V(V) {}
112
113 /// Pointer integral of the given kind.
114 explicit Integral(IntegralKind Kind, const void *P, OffsetT Offset = 0)
115 : Kind(Kind) {
116 Ptr.P = P;
117 Ptr.Offset = Offset;
118 }
119
120 /// AddrLabelDiff integral.
121 explicit Integral(const AddrLabelExpr *P1, const AddrLabelExpr *P2)
122 : Kind(IntegralKind::AddrLabelDiff) {
123 AddrLabelDiff.L1 = P1;
124 AddrLabelDiff.L2 = P2;
125 }
126
127 IntegralKind getKind() const { return Kind; }
128 bool isNumber() const { return Kind == IntegralKind::Number; }
129 const void *getPtr() const {
130 assert(!isNumber());
131 assert(Kind != IntegralKind::AddrLabelDiff);
132 return Ptr.P;
133 }
134 ReprT getOffset() const {
135 assert(!isNumber());
136 assert(Kind != IntegralKind::AddrLabelDiff);
137 return Ptr.Offset;
138 }
139 const AddrLabelExpr *getLabel1() const {
140 assert(Kind == IntegralKind::AddrLabelDiff);
141 return AddrLabelDiff.L1;
142 }
143 const AddrLabelExpr *getLabel2() const {
144 assert(Kind == IntegralKind::AddrLabelDiff);
145 return AddrLabelDiff.L2;
146 }
147
148 /// Construct an integral from a value based on signedness.
149 explicit Integral(const APSInt &V)
150 : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
151
152 bool operator<(Integral RHS) const { return V < RHS.V; }
153 bool operator>(Integral RHS) const { return V > RHS.V; }
154 bool operator<=(Integral RHS) const { return V <= RHS.V; }
155 bool operator>=(Integral RHS) const { return V >= RHS.V; }
156 bool operator==(Integral RHS) const { return V == RHS.V; }
157 bool operator!=(Integral RHS) const { return V != RHS.V; }
158 bool operator>=(unsigned RHS) const {
159 return static_cast<unsigned>(V) >= RHS;
160 }
161
162 bool operator>(unsigned RHS) const {
163 return V >= 0 && static_cast<unsigned>(V) > RHS;
164 }
165
166 Integral operator-() const { return Integral(-V); }
168 return Integral(V - Other.V);
169 }
170 Integral operator~() const { return Integral(~V); }
171
172 template <unsigned DstBits, bool DstSign>
173 explicit operator Integral<DstBits, DstSign>() const {
174 return Integral<DstBits, DstSign>(Kind, V);
175 }
176
177 template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
178 explicit operator Ty() const {
179 return V;
180 }
181
182 APSInt toAPSInt() const {
183 assert(isNumber());
184 return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
185 }
186
187 APSInt toAPSInt(unsigned BitWidth) const {
188 return APSInt(toAPInt(BitWidth), !Signed);
189 }
190
191 APInt toAPInt(unsigned BitWidth) const {
192 assert(isNumber());
193 if constexpr (Signed)
194 return APInt(Bits, static_cast<uint64_t>(V), Signed)
195 .sextOrTrunc(BitWidth);
196 else
197 return APInt(Bits, static_cast<uint64_t>(V), Signed)
198 .zextOrTrunc(BitWidth);
199 }
200
201 APValue toAPValue(const ASTContext &) const {
202 switch (Kind) {
204 return APValue((const ValueDecl *)Ptr.P,
207 }
209 return APValue((const Expr *)Ptr.P, CharUnits::Zero(),
211 }
213 const Block *B = reinterpret_cast<const Block *>(Ptr.P);
214 const Descriptor *D = B->getDescriptor();
215 if (const Expr *E = D->asExpr())
217
218 return APValue(D->asValueDecl(), CharUnits::Zero(),
220 }
222 return APValue((const FunctionDecl *)Ptr.P,
225 }
227 return APValue(AddrLabelDiff.L1, AddrLabelDiff.L2);
228 }
230 return APValue(toAPSInt());
231 }
232 llvm_unreachable("Unhandled IntegralKind");
233 }
234
236 return Integral<Bits, false>(*this);
237 }
238
239 constexpr static unsigned bitWidth() { return Bits; }
240 constexpr static bool isSigned() { return Signed; }
241
242 bool isZero() const { return !V; }
243 bool isMin() const { return *this == min(bitWidth()); }
244 bool isMinusOne() const { return Signed && V == ReprT(-1); }
245 bool isNegative() const { return V < ReprT(0); }
246 bool isPositive() const { return !isNegative(); }
247
249 return Compare(V, RHS.V);
250 }
251
252 void bitcastToMemory(std::byte *Dest) const {
253 assert(isNumber());
254 std::memcpy(Dest, &V, sizeof(V));
255 }
256
257 static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
258 assert(BitWidth == sizeof(ReprT) * 8);
259 ReprT V;
260
261 std::memcpy(&V, Src, sizeof(ReprT));
262 return Integral(V);
263 }
264
265 std::string toDiagnosticString(const ASTContext &Ctx) const {
266 std::string NameStr;
267 llvm::raw_string_ostream OS(NameStr);
268 OS << V;
269 return NameStr;
270 }
271
272 unsigned countLeadingZeros() const {
273 assert(isNumber());
274 if constexpr (!Signed)
275 return llvm::countl_zero<ReprT>(V);
276 if (isPositive())
277 return llvm::countl_zero<typename AsUnsigned::ReprT>(
278 static_cast<typename AsUnsigned::ReprT>(V));
279 llvm_unreachable("Don't call countLeadingZeros() on negative values.");
280 }
281
282 Integral truncate(unsigned TruncBits) const {
283 assert(TruncBits >= 1);
284 if (TruncBits >= Bits)
285 return *this;
286 const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
287 const ReprT SignBit = ReprT(1) << (TruncBits - 1);
288 const ReprT ExtMask = ~BitMask;
289 return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
290 }
291
292 void print(llvm::raw_ostream &OS) const {
293 switch (Kind) {
295 OS << V;
296 break;
298 OS << AddrLabelDiff.L1 << " - " << AddrLabelDiff.L2 << " (AddrLabelDiff)";
299 break;
301 OS << Ptr.P << " + " << Ptr.Offset << " (Address)";
302 break;
304 OS << Ptr.P << " + " << Ptr.Offset << " (BlockAddress)";
305 break;
307 OS << Ptr.P << " + " << Ptr.Offset << " (LabelAddress)";
308 break;
310 OS << Ptr.P << " + " << Ptr.Offset << " (FunctionAddress)";
311 }
312 }
313
314 static Integral min(unsigned NumBits) { return Integral(Min); }
315 static Integral max(unsigned NumBits) { return Integral(Max); }
316 static Integral zero(unsigned BitWidth = 0) { return from(0); }
317
318 template <typename ValT>
319 static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, Integral>
320 from(ValT V, unsigned NumBits = 0) {
321 if constexpr (std::is_integral_v<ValT>)
322 return Integral(V);
323 else
324 return Integral(static_cast<Integral::ReprT>(V));
325 }
326
327 template <unsigned SrcBits, bool SrcSign>
328 static std::enable_if_t<SrcBits != 0, Integral>
330 switch (V.Kind) {
332 return Integral(V.V);
334 return Integral(V.getLabel1(), V.getLabel2());
339 return Integral(V.getKind(), V.getPtr(), V.getOffset());
340 }
341 llvm_unreachable("Unhandled IntegralKind");
342 }
343
344 template <typename T> static Integral from(IntegralKind Kind, T V) {
345 return Integral(Kind, V);
346 }
347
348 static bool increment(Integral A, Integral *R) {
349 assert(A.isNumber());
350 return add(A, Integral(ReprT(1)), A.bitWidth(), R);
351 }
352
353 static bool decrement(Integral A, Integral *R) {
354 assert(A.isNumber());
355 return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
356 }
357
358 static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
359 assert(A.isNumber() && B.isNumber());
360 return CheckAddUB(A.V, B.V, R->V);
361 }
362
363 static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
364 assert(A.isNumber() && B.isNumber());
365 return CheckSubUB(A.V, B.V, R->V);
366 }
367
368 static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
369 assert(A.isNumber() && B.isNumber());
370 return CheckMulUB(A.V, B.V, R->V);
371 }
372
373 static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
374 assert(A.isNumber() && B.isNumber());
375 *R = Integral(A.V % B.V);
376 return false;
377 }
378
379 static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
380 assert(A.isNumber() && B.isNumber());
381 *R = Integral(A.V / B.V);
382 return false;
383 }
384
385 static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
386 assert(A.isNumber() && B.isNumber());
387 *R = Integral(A.V & B.V);
388 return false;
389 }
390
391 static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
392 assert(A.isNumber() && B.isNumber());
393 *R = Integral(A.V | B.V);
394 return false;
395 }
396
397 static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
398 assert(A.isNumber() && B.isNumber());
399 *R = Integral(A.V ^ B.V);
400 return false;
401 }
402
403 static bool neg(Integral A, Integral *R) {
404 if (Signed && A.isMin())
405 return true;
406
407 *R = -A;
408 return false;
409 }
410
411 static bool comp(Integral A, Integral *R) {
412 *R = Integral(~A.V);
413 return false;
414 }
415
416 template <unsigned RHSBits, bool RHSSign>
417 static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
418 unsigned OpBits, Integral *R) {
419 *R = Integral::from(A.V << B.V, OpBits);
420 }
421
422 template <unsigned RHSBits, bool RHSSign>
423 static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
424 unsigned OpBits, Integral *R) {
425 *R = Integral::from(A.V >> B.V, OpBits);
426 }
427};
428
429template <unsigned Bits, bool Signed>
430llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
431 I.print(OS);
432 return OS;
433}
434
435} // namespace interp
436} // namespace clang
437
438#endif
#define V(N, I)
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
AddrLabelExpr - The GNU address of label extension, representing &&label.
Definition Expr.h:4553
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
This represents one expression.
Definition Expr.h:112
Represents a function declaration or definition.
Definition Decl.h:2013
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:44
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:73
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition IntegralAP.h:36
Wrapper around numeric types.
Definition Integral.h:69
static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth)
Definition Integral.h:257
Integral< Bits, false > toUnsigned() const
Definition Integral.h:235
bool isMinusOne() const
Definition Integral.h:244
bool isNegative() const
Definition Integral.h:245
IntegralKind getKind() const
Definition Integral.h:127
static Integral max(unsigned NumBits)
Definition Integral.h:315
Integral()
Zero-initializes an integral.
Definition Integral.h:107
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition Integral.h:265
static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:368
bool operator>=(Integral RHS) const
Definition Integral.h:155
struct clang::interp::Integral::@160043211265056200131370130202171044251230110336::@236040326051144126115245243244367376012363112306 AddrLabelDiff
typename Repr< Bits, Signed >::Type ReprT
Definition Integral.h:74
bool isNumber() const
Definition Integral.h:128
friend class Integral
Definition Integral.h:79
void print(llvm::raw_ostream &OS) const
Definition Integral.h:292
static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:363
static constexpr unsigned bitWidth()
Definition Integral.h:239
APSInt toAPSInt() const
Definition Integral.h:182
static void shiftRight(const Integral A, const Integral< RHSBits, RHSSign > B, unsigned OpBits, Integral *R)
Definition Integral.h:423
bool operator>(Integral RHS) const
Definition Integral.h:153
bool operator>(unsigned RHS) const
Definition Integral.h:162
Integral operator-(const Integral &Other) const
Definition Integral.h:167
bool isZero() const
Definition Integral.h:242
unsigned countLeadingZeros() const
Definition Integral.h:272
ReprT getOffset() const
Definition Integral.h:134
Integral operator~() const
Definition Integral.h:170
Integral truncate(unsigned TruncBits) const
Definition Integral.h:282
bool operator<(Integral RHS) const
Definition Integral.h:152
static Integral zero(unsigned BitWidth=0)
Definition Integral.h:316
struct clang::interp::Integral::@160043211265056200131370130202171044251230110336::@320007000314117147377312357337153052223131102230 Ptr
ComparisonCategoryResult compare(const Integral &RHS) const
Definition Integral.h:248
Integral< Bits, false > AsUnsigned
Definition Integral.h:104
static bool neg(Integral A, Integral *R)
Definition Integral.h:403
static Integral from(IntegralKind Kind, T V)
Definition Integral.h:344
bool operator!=(Integral RHS) const
Definition Integral.h:157
APValue toAPValue(const ASTContext &) const
Definition Integral.h:201
APSInt toAPSInt(unsigned BitWidth) const
Definition Integral.h:187
static bool decrement(Integral A, Integral *R)
Definition Integral.h:353
static bool comp(Integral A, Integral *R)
Definition Integral.h:411
Integral(Integral< SrcBits, SrcSign > V)
Constructs an integral from another integral.
Definition Integral.h:111
bool operator<=(Integral RHS) const
Definition Integral.h:154
const AddrLabelExpr * getLabel2() const
Definition Integral.h:143
static bool div(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:379
static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:397
static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:373
bool operator==(Integral RHS) const
Definition Integral.h:156
static std::enable_if_t<!std::is_same_v< ValT, IntegralKind >, Integral > from(ValT V, unsigned NumBits=0)
Definition Integral.h:320
Integral(const APSInt &V)
Construct an integral from a value based on signedness.
Definition Integral.h:149
Integral(IntegralKind Kind, const void *P, OffsetT Offset=0)
Pointer integral of the given kind.
Definition Integral.h:114
static std::enable_if_t< SrcBits !=0, Integral > from(Integral< SrcBits, SrcSign > V)
Definition Integral.h:329
static Integral min(unsigned NumBits)
Definition Integral.h:314
bool operator>=(unsigned RHS) const
Definition Integral.h:158
const void * getPtr() const
Definition Integral.h:129
const AddrLabelExpr * getLabel1() const
Definition Integral.h:139
static constexpr bool isSigned()
Definition Integral.h:240
APInt toAPInt(unsigned BitWidth) const
Definition Integral.h:191
static void shiftLeft(const Integral A, const Integral< RHSBits, RHSSign > B, unsigned OpBits, Integral *R)
Definition Integral.h:417
static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:391
void bitcastToMemory(std::byte *Dest) const
Definition Integral.h:252
Integral operator-() const
Definition Integral.h:166
bool isPositive() const
Definition Integral.h:246
static bool add(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:358
static bool increment(Integral A, Integral *R)
Definition Integral.h:348
Integral(const AddrLabelExpr *P1, const AddrLabelExpr *P2)
AddrLabelDiff integral.
Definition Integral.h:121
static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition Integral.h:385
bool CheckMulUB(T A, T B, T &R)
Definition Primitives.h:66
llvm::APInt APInt
Definition FixedPoint.h:19
@ BlockAddress
A pointer to an interp::Block.
Definition Primitives.h:30
@ AddrLabelDiff
Difference between two AddrLabelExpr.
Definition Primitives.h:36
@ Number
Just a number, nothing else.
Definition Primitives.h:26
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
@ LabelAddress
A pointer to a AddrLabelExpr.
Definition Primitives.h:32
@ FunctionAddress
A pointer to a FunctionDecl.
Definition Primitives.h:34
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition Boolean.h:153
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition Primitives.h:40
bool CheckSubUB(T A, T B, T &R)
Definition Primitives.h:57
bool CheckAddUB(T A, T B, T &R)
Definition Primitives.h:48
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.
@ Other
Other implicit parameter.
Definition Decl.h:1759
__INTPTR_TYPE__ intptr_t
A signed integer type with the property that any valid pointer to void can be converted to this type,...
#define false
Definition stdbool.h:26
#define true
Definition stdbool.h:25
A quantity in bits.
Describes a memory block created by an allocation site.
Definition Descriptor.h:123
const ValueDecl * asValueDecl() const
Definition Descriptor.h:216
const Expr * asExpr() const
Definition Descriptor.h:213