clang 23.0.0git
InterpBuiltinBitCast.cpp
Go to the documentation of this file.
1//===-------------------- InterpBuiltinBitCast.cpp --------------*- 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//===----------------------------------------------------------------------===//
9#include "BitcastBuffer.h"
10#include "Boolean.h"
11#include "Char.h"
12#include "Context.h"
13#include "Floating.h"
14#include "Integral.h"
15#include "InterpState.h"
16#include "MemberPointer.h"
17#include "Pointer.h"
18#include "Record.h"
22
23#include <variant>
24
25using namespace clang;
26using namespace clang::interp;
27
28/// Implement __builtin_bit_cast and related operations.
29/// Since our internal representation for data is more complex than
30/// something we can simply memcpy or memcmp, we first bitcast all the data
31/// into a buffer, which we then later use to copy the data into the target.
32
33// TODO:
34// - Try to minimize heap allocations.
35// - Optimize the common case of only pushing and pulling full
36// bytes to/from the buffer.
37
38enum class Result { Success, Skip, Failure };
39
40/// Used to iterate over pointer fields.
41using DataFunc =
42 llvm::function_ref<Result(const Pointer &P, PrimType Ty, Bits BitOffset,
43 Bits FullBitWidth, bool PackedBools)>;
44
45#define BITCAST_TYPE_SWITCH(Expr, B) \
46 do { \
47 switch (Expr) { \
48 TYPE_SWITCH_CASE(PT_Sint8, B) \
49 TYPE_SWITCH_CASE(PT_Uint8, B) \
50 TYPE_SWITCH_CASE(PT_Sint16, B) \
51 TYPE_SWITCH_CASE(PT_Uint16, B) \
52 TYPE_SWITCH_CASE(PT_Sint32, B) \
53 TYPE_SWITCH_CASE(PT_Uint32, B) \
54 TYPE_SWITCH_CASE(PT_Sint64, B) \
55 TYPE_SWITCH_CASE(PT_Uint64, B) \
56 TYPE_SWITCH_CASE(PT_IntAP, B) \
57 TYPE_SWITCH_CASE(PT_IntAPS, B) \
58 TYPE_SWITCH_CASE(PT_Bool, B) \
59 default: \
60 llvm_unreachable("Unhandled bitcast type"); \
61 } \
62 } while (0)
63
64#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \
65 do { \
66 switch (Expr) { \
67 TYPE_SWITCH_CASE(PT_Sint8, B) \
68 TYPE_SWITCH_CASE(PT_Uint8, B) \
69 TYPE_SWITCH_CASE(PT_Sint16, B) \
70 TYPE_SWITCH_CASE(PT_Uint16, B) \
71 TYPE_SWITCH_CASE(PT_Sint32, B) \
72 TYPE_SWITCH_CASE(PT_Uint32, B) \
73 TYPE_SWITCH_CASE(PT_Sint64, B) \
74 TYPE_SWITCH_CASE(PT_Uint64, B) \
75 TYPE_SWITCH_CASE(PT_Bool, B) \
76 default: \
77 llvm_unreachable("Unhandled bitcast type"); \
78 } \
79 } while (0)
80
81/// We use this to recursively iterate over all fields and elements of a pointer
82/// and extract relevant data for a bitcast.
83static Result enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
84 Bits BitsToRead, DataFunc F, bool Initialize) {
85 const Descriptor *FieldDesc = P.getFieldDesc();
86 assert(FieldDesc);
87
88 // Primitives.
89 if (FieldDesc->isPrimitive()) {
90 Bits FullBitWidth =
91 Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType()));
92 return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth,
93 /*PackedBools=*/false);
94 }
95
96 // Primitive arrays.
97 if (FieldDesc->isPrimitiveArray()) {
98 QualType ElemType = FieldDesc->getElemQualType();
99 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
100 PrimType ElemT = *Ctx.classify(ElemType);
101 // Special case, since the bools here are packed.
102 bool PackedBools =
103 FieldDesc->getType()->isPackedVectorBoolType(Ctx.getASTContext());
104 unsigned NumElems = FieldDesc->getNumElems();
105 bool Ok = true;
106 for (unsigned I = P.getIndex(); I != NumElems; ++I) {
107 Result Res = F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools);
108
109 Ok = Ok && (Res == Result::Success);
110 Offset += PackedBools ? Bits(1) : ElemSize;
111 if (Offset >= BitsToRead)
112 break;
113 }
115 }
116
117 // Composite arrays.
118 if (FieldDesc->isCompositeArray()) {
119 QualType ElemType = FieldDesc->getElemQualType();
120 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
121 for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) {
122 enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F,
123 Initialize);
124 Offset += ElemSize;
125 if (Offset >= BitsToRead)
126 break;
127 }
128 return Result::Success;
129 }
130
131 // Records.
132 if (FieldDesc->isRecord()) {
133 const Record *R = FieldDesc->ElemRecord;
134 const ASTRecordLayout &Layout =
135 Ctx.getASTContext().getASTRecordLayout(R->getDecl());
136 bool Ok = true;
137
138 for (const Record::Field &Fi : R->fields()) {
139 if (Fi.isUnnamedBitField())
140 continue;
141
142 Pointer Elem = P.atField(Fi.Offset);
143 Bits BitOffset =
144 Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
145 Result Res =
146 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
147 if (Initialize) {
148 if (Res == Result::Success)
149 Elem.initialize();
150 else if (Res == Result::Skip)
151 Elem.startLifetime();
152 }
153 Ok = Ok && Res != Result::Failure;
154 }
155 for (const Record::Base &B : R->bases()) {
156 Pointer Elem = P.atField(B.Offset);
157 if (!Initialize && !Elem.isInitialized())
158 return Result::Failure;
159
160 CharUnits ByteOffset =
162 Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
163 Result Res =
164 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
165 if (Initialize) {
166 if (Res == Result::Success)
167 Elem.initialize();
168 else if (Res == Result::Skip)
169 Elem.startLifetime();
170 }
171 Ok = Ok && Res != Result::Failure;
172 }
174 }
175
176 llvm_unreachable("Unhandled data type");
177}
178
179static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
180 Bits BitsToRead, DataFunc F,
181 bool Initialize) {
182 return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F, Initialize) !=
184}
185
186// This function is constexpr if and only if To, From, and the types of
187// all subobjects of To and From are types T such that...
188// (3.1) - is_union_v<T> is false;
189// (3.2) - is_pointer_v<T> is false;
190// (3.3) - is_member_pointer_v<T> is false;
191// (3.4) - is_volatile_v<T> is false; and
192// (3.5) - T has no non-static data members of reference type
193//
194// NOTE: This is a version of checkBitCastConstexprEligibilityType() in
195// ExprConstant.cpp.
197 bool IsToType) {
198 enum {
199 E_Union = 0,
200 E_Pointer,
201 E_MemberPointer,
202 E_Volatile,
203 E_Reference,
204 };
205 enum { C_Member, C_Base };
206
207 auto diag = [&](int Reason) -> bool {
208 const Expr *E = S.Current->getExpr(OpPC);
209 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
210 << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
211 << E->getSourceRange();
212 return false;
213 };
214 auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) {
215 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
216 << NoteType << Construct << T.getUnqualifiedType() << NoteRange;
217 return false;
218 };
219
220 T = T.getCanonicalType();
221
222 if (T->isUnionType())
223 return diag(E_Union);
224 if (T->isPointerType())
225 return diag(E_Pointer);
226 if (T->isMemberPointerType())
227 return diag(E_MemberPointer);
228 if (T.isVolatileQualified())
229 return diag(E_Volatile);
230
231 if (const RecordDecl *RD = T->getAsRecordDecl()) {
232 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
233 for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
234 if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType))
235 return note(C_Base, BS.getType(), BS.getBeginLoc());
236 }
237 }
238 for (const FieldDecl *FD : RD->fields()) {
239 if (FD->getType()->isReferenceType())
240 return diag(E_Reference);
241 if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType))
242 return note(C_Member, FD->getType(), FD->getSourceRange());
243 }
244 }
245
246 if (T->isArrayType() &&
248 IsToType))
249 return false;
250
251 if (const auto *VT = T->getAs<VectorType>()) {
252 const ASTContext &ASTCtx = S.getASTContext();
253 QualType EltTy = VT->getElementType();
254 unsigned NElts = VT->getNumElements();
255 unsigned EltSize =
256 VT->isPackedVectorBoolType(ASTCtx) ? 1 : ASTCtx.getTypeSize(EltTy);
257
258 if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) {
259 // The vector's size in bits is not a multiple of the target's byte size,
260 // so its layout is unspecified. For now, we'll simply treat these cases
261 // as unsupported (this should only be possible with OpenCL bool vectors
262 // whose element count isn't a multiple of the byte size).
263 const Expr *E = S.Current->getExpr(OpPC);
264 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector)
265 << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth();
266 return false;
267 }
268
269 if (EltTy->isRealFloatingType() &&
270 &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) {
271 // The layout for x86_fp80 vectors seems to be handled very inconsistently
272 // by both clang and LLVM, so for now we won't allow bit_casts involving
273 // it in a constexpr context.
274 const Expr *E = S.Current->getExpr(OpPC);
275 S.FFDiag(E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy;
276 return false;
277 }
278 }
279
280 return true;
281}
282
284 const Pointer &FromPtr,
285 BitcastBuffer &Buffer,
286 bool ReturnOnUninit) {
287 const ASTContext &ASTCtx = Ctx.getASTContext();
288 Endian TargetEndianness =
290
292 FromPtr, Ctx, Buffer.size(),
293 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
294 bool PackedBools) -> Result {
295 Bits BitWidth = FullBitWidth;
296
297 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
298 BitWidth = Bits(std::min(FD->getBitWidthValue(),
299 (unsigned)FullBitWidth.getQuantity()));
300 else if (T == PT_Bool && PackedBools)
301 BitWidth = Bits(1);
302
303 if (BitWidth.isZero())
304 return Result::Skip;
305
306 // Bits will be left uninitialized and diagnosed when reading.
307 if (!P.isInitialized())
308 return Result::Skip;
309
310 if (T == PT_Ptr) {
311 assert(P.getType()->isNullPtrType());
312 // Clang treats nullptr_t has having NO bits in its value
313 // representation. So, we accept it here and leave its bits
314 // uninitialized.
315 return Result::Skip;
316 }
317
318 assert(P.isInitialized());
319 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes());
320 // Work around floating point types that contain unused padding bytes.
321 // This is really just `long double` on x86, which is the only
322 // fundamental type with padding bytes.
323 if (T == PT_Float) {
324 const Floating &F = P.deref<Floating>();
325 Bits NumBits = Bits(
326 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics()));
327 assert(NumBits.isFullByte());
328 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
329 F.bitcastToMemory(Buff.get());
330 // Now, only (maybe) swap the actual size of the float, excluding
331 // the padding bits.
332 if (llvm::sys::IsBigEndianHost)
333 swapBytes(Buff.get(), NumBits.roundToBytes());
334
335 Buffer.markInitialized(BitOffset, NumBits);
336 } else {
338 auto Val = P.deref<T>();
339 if (!Val.isNumber())
340 return Result::Failure;
341 Val.bitcastToMemory(Buff.get());
342 });
343
344 if (llvm::sys::IsBigEndianHost)
345 swapBytes(Buff.get(), FullBitWidth.roundToBytes());
346 Buffer.markInitialized(BitOffset, BitWidth);
347 }
348
349 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
350 return Result::Success;
351 },
352 false);
353}
354
356 std::byte *Buff, Bits BitWidth, Bits FullBitWidth,
357 bool &HasIndeterminateBits) {
358 assert(Ptr.isLive());
359 assert(Ptr.isBlockPointer());
360 assert(Buff);
361 assert(BitWidth <= FullBitWidth);
362 assert(FullBitWidth.isFullByte());
363 assert(BitWidth.isFullByte());
364
365 BitcastBuffer Buffer(FullBitWidth);
366 size_t BuffSize = FullBitWidth.roundToBytes();
367 QualType DataType = Ptr.getFieldDesc()->getDataType(S.getASTContext());
368 if (!CheckBitcastType(S, OpPC, DataType, /*IsToType=*/false))
369 return false;
370
371 bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
372 /*ReturnOnUninit=*/false);
373 HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth);
374
375 const ASTContext &ASTCtx = S.getASTContext();
376 Endian TargetEndianness =
378 auto B =
379 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness);
380
381 std::memcpy(Buff, B.get(), BuffSize);
382
383 if (llvm::sys::IsBigEndianHost)
384 swapBytes(Buff, BitWidth.roundToBytes());
385
386 return Success;
387}
389 const Pointer &FromPtr, Pointer &ToPtr) {
390 const ASTContext &ASTCtx = S.getASTContext();
391 CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType());
392
393 return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity());
394}
395
397 const Pointer &FromPtr, Pointer &ToPtr,
398 size_t Size) {
399 assert(FromPtr.isLive());
400 assert(FromPtr.isBlockPointer());
401 assert(ToPtr.isBlockPointer());
402
403 QualType FromType = FromPtr.getFieldDesc()->getDataType(S.getASTContext());
404 QualType ToType = ToPtr.getFieldDesc()->getDataType(S.getASTContext());
405
406 if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true))
407 return false;
408 if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false))
409 return false;
410
411 const ASTContext &ASTCtx = S.getASTContext();
412 BitcastBuffer Buffer(Bytes(Size).toBits());
413 readPointerToBuffer(S.getContext(), FromPtr, Buffer,
414 /*ReturnOnUninit=*/false);
415
416 // Now read the values out of the buffer again and into ToPtr.
417 Endian TargetEndianness =
420 ToPtr, S.getContext(), Buffer.size(),
421 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
422 bool PackedBools) -> Result {
423 QualType PtrType = P.getType();
424 if (T == PT_Float) {
425 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);
426 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
427 assert(NumBits.isFullByte());
428 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
429 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
430 TargetEndianness);
431
432 if (llvm::sys::IsBigEndianHost)
433 swapBytes(M.get(), NumBits.roundToBytes());
434
435 Floating R = S.allocFloat(Semantics);
436 Floating::bitcastFromMemory(M.get(), Semantics, &R);
437 P.deref<Floating>() = R;
438 P.initialize();
439 return Result::Success;
440 }
441
442 Bits BitWidth;
443 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
444 BitWidth = Bits(std::min(FD->getBitWidthValue(),
445 (unsigned)FullBitWidth.getQuantity()));
446 else if (T == PT_Bool && PackedBools)
447 BitWidth = Bits(1);
448 else
449 BitWidth = FullBitWidth;
450
451 // If any of the bits are uninitialized, we need to abort unless the
452 // target type is std::byte or unsigned char.
453 bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth);
454 if (!Initialized) {
455 if (!PtrType->isStdByteType() &&
456 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&
457 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {
458 const Expr *E = S.Current->getExpr(OpPC);
459 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
460 << PtrType << S.getLangOpts().CharIsSigned
461 << E->getSourceRange();
462
463 return Result::Failure;
464 }
465 return Result::Skip;
466 }
467
468 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth,
469 TargetEndianness);
470 if (llvm::sys::IsBigEndianHost)
471 swapBytes(Memory.get(), FullBitWidth.roundToBytes());
472
473 if (T == PT_IntAPS) {
475 S.allocAP<IntegralAP<true>>(FullBitWidth.getQuantity());
477 FullBitWidth.getQuantity(),
478 &P.deref<IntegralAP<true>>());
479 } else if (T == PT_IntAP) {
481 S.allocAP<IntegralAP<false>>(FullBitWidth.getQuantity());
483 FullBitWidth.getQuantity(),
485 } else {
487 if (BitWidth.nonZero())
488 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
489 .truncate(BitWidth.getQuantity());
490 else
491 P.deref<T>() = T::zero();
492 });
493 }
494 P.initialize();
495 return Result::Success;
496 },
497 true);
498
499 return Success;
500}
501
508
509// NB: This implementation isn't exactly ideal, but:
510// 1) We can't just do a bitcast here since we need to be able to
511// copy pointers.
512// 2) This also needs to handle overlapping regions.
513// 3) We currently have no way of iterating over the fields of a pointer
514// backwards.
516 const Pointer &SrcPtr, const Pointer &DestPtr,
517 Bits Size) {
518 assert(SrcPtr.isBlockPointer());
519 assert(DestPtr.isBlockPointer());
520
523 SrcPtr, S.getContext(), Size,
524 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
525 bool PackedBools) -> Result {
526 TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
527 return Result::Success;
528 },
529 false);
530
531 unsigned ValueIndex = 0;
533 DestPtr, S.getContext(), Size,
534 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
535 bool PackedBools) -> Result {
536 TYPE_SWITCH(T, {
537 P.deref<T>() = std::get<T>(Values[ValueIndex]);
538 P.initialize();
539 });
540
541 ++ValueIndex;
542 return Result::Success;
543 },
544 true);
545
546 // We should've read all the values into DestPtr.
547 assert(ValueIndex == Values.size());
548
549 return true;
550}
Defines the clang::ASTContext interface.
std::variant< Pointer, FunctionPointer, MemberPointer, FixedPoint, Char< false >, Char< true >, Integral< 16, false >, Integral< 16, true >, Integral< 32, false >, Integral< 32, true >, Integral< 64, false >, Integral< 64, true >, IntegralAP< true >, IntegralAP< false >, Boolean, Floating > PrimTypeVariant
static Result enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, Bits BitsToRead, DataFunc F, bool Initialize)
We use this to recursively iterate over all fields and elements of a pointer and extract relevant dat...
#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B)
Result
Implement __builtin_bit_cast and related operations.
llvm::function_ref< Result(const Pointer &P, PrimType Ty, Bits BitOffset, Bits FullBitWidth, bool PackedBools)> DataFunc
Used to iterate over pointer fields.
static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, Bits BitsToRead, DataFunc F, bool Initialize)
#define BITCAST_TYPE_SWITCH(Expr, B)
static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, bool IsToType)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:227
const llvm::fltSemantics & getFloatTypeSemantics(QualType T) const
Return the APFloat 'semantics' for the specified scalar floating point type.
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:924
uint64_t getCharWidth() const
Return the size of the character type, in bits.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Represents a base class of a C++ class.
Definition DeclCXX.h:146
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
This represents one expression.
Definition Expr.h:112
Represents a member of a struct/union/class.
Definition Decl.h:3178
bool isBitField() const
Determines whether this field is a bitfield.
Definition Decl.h:3281
A (possibly-)qualified type.
Definition TypeBase.h:937
Represents a struct/union/class.
Definition Decl.h:4343
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
bool isLittleEndian() const
bool isPackedVectorBoolType(const ASTContext &ctx) const
Definition Type.cpp:455
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2405
Represents a GCC generic vector type.
Definition TypeBase.h:4230
Wrapper around boolean types.
Definition Boolean.h:25
Pointer into the code segment.
Definition Source.h:30
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:47
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:98
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:408
Wrapper around fixed point types.
Definition FixedPoint.h:23
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
void bitcastToMemory(std::byte *Buff) const
Definition Floating.h:191
APFloat getAPFloat() const
Definition Floating.h:64
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition IntegralAP.h:36
static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, IntegralAP *Result)
Definition IntegralAP.h:207
Wrapper around numeric types.
Definition Integral.h:69
const Expr * getExpr(CodePtr PC) const
Interpreter context.
Definition InterpState.h:36
Context & getContext() const
Definition InterpState.h:74
InterpFrame * Current
The current frame.
T allocAP(unsigned BitWidth)
A pointer to a memory block, live or dead.
Definition Pointer.h:97
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:194
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:443
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:162
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:627
void startLifetime() const
Start the lifetime of this pointer.
Definition Pointer.cpp:507
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:179
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:687
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:346
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:278
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:492
bool isBlockPointer() const
Definition Pointer.h:479
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:336
void initialize() const
Initializes a field.
Definition Pointer.cpp:535
Structure/Class descriptor.
Definition Record.h:25
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:63
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:21
ASTContext & getASTContext() const
Definition State.h:93
const LangOptions & getLangOpts() const
Definition State.h:94
Defines the clang::TargetInfo interface.
bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, BitcastBuffer &Buffer, bool ReturnOnUninit)
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)
static void swapBytes(std::byte *M, size_t N)
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
@ Success
Annotation was successful.
Definition Parser.h:65
@ Result
The result type of a method or function.
Definition TypeBase.h:905
U cast(CodeGen::Address addr)
Definition Address.h:327
Track what bits have been initialized to known values and which ones have indeterminate value.
std::unique_ptr< std::byte[]> copyBits(Bits BitOffset, Bits BitWidth, Bits FullBitWidth, Endian TargetEndianness) const
Copy BitWidth bits at offset BitOffset from the buffer.
void markInitialized(Bits Start, Bits Length)
Marks the bits in the given range as initialized.
bool rangeInitialized(Bits Offset, Bits Length) const
Bits size() const
Returns the buffer size in bits.
void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth, Endian TargetEndianness)
Push BitWidth bits at BitOffset from In into the buffer.
A quantity in bits.
size_t roundToBytes() const
bool isFullByte() const
static Bits zero()
size_t getQuantity() const
A quantity in bytes.
Describes a memory block created by an allocation site.
Definition Descriptor.h:123
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:260
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:274
QualType getElemQualType() const
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:267
QualType getType() const
QualType getDataType(const ASTContext &Ctx) const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:265
PrimType getPrimType() const
Definition Descriptor.h:242
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:279
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:154