clang 20.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 "Context.h"
12#include "Floating.h"
13#include "Integral.h"
14#include "InterpState.h"
15#include "MemberPointer.h"
16#include "Pointer.h"
17#include "Record.h"
21
22using namespace clang;
23using namespace clang::interp;
24
25/// Implement __builtin_bit_cast and related operations.
26/// Since our internal representation for data is more complex than
27/// something we can simply memcpy or memcmp, we first bitcast all the data
28/// into a buffer, which we then later use to copy the data into the target.
29
30// TODO:
31// - Try to minimize heap allocations.
32// - Optimize the common case of only pushing and pulling full
33// bytes to/from the buffer.
34
35/// Used to iterate over pointer fields.
36using DataFunc =
37 llvm::function_ref<bool(const Pointer &P, PrimType Ty, Bits BitOffset,
38 Bits FullBitWidth, bool PackedBools)>;
39
40#define BITCAST_TYPE_SWITCH(Expr, B) \
41 do { \
42 switch (Expr) { \
43 TYPE_SWITCH_CASE(PT_Sint8, B) \
44 TYPE_SWITCH_CASE(PT_Uint8, B) \
45 TYPE_SWITCH_CASE(PT_Sint16, B) \
46 TYPE_SWITCH_CASE(PT_Uint16, B) \
47 TYPE_SWITCH_CASE(PT_Sint32, B) \
48 TYPE_SWITCH_CASE(PT_Uint32, B) \
49 TYPE_SWITCH_CASE(PT_Sint64, B) \
50 TYPE_SWITCH_CASE(PT_Uint64, B) \
51 TYPE_SWITCH_CASE(PT_IntAP, B) \
52 TYPE_SWITCH_CASE(PT_IntAPS, B) \
53 TYPE_SWITCH_CASE(PT_Bool, B) \
54 default: \
55 llvm_unreachable("Unhandled bitcast type"); \
56 } \
57 } while (0)
58
59#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \
60 do { \
61 switch (Expr) { \
62 TYPE_SWITCH_CASE(PT_Sint8, B) \
63 TYPE_SWITCH_CASE(PT_Uint8, B) \
64 TYPE_SWITCH_CASE(PT_Sint16, B) \
65 TYPE_SWITCH_CASE(PT_Uint16, B) \
66 TYPE_SWITCH_CASE(PT_Sint32, B) \
67 TYPE_SWITCH_CASE(PT_Uint32, B) \
68 TYPE_SWITCH_CASE(PT_Sint64, B) \
69 TYPE_SWITCH_CASE(PT_Uint64, B) \
70 TYPE_SWITCH_CASE(PT_Bool, B) \
71 default: \
72 llvm_unreachable("Unhandled bitcast type"); \
73 } \
74 } while (0)
75
76/// We use this to recursively iterate over all fields and elements of a pointer
77/// and extract relevant data for a bitcast.
78static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
79 Bits BitsToRead, DataFunc F) {
80 const Descriptor *FieldDesc = P.getFieldDesc();
81 assert(FieldDesc);
82
83 // Primitives.
84 if (FieldDesc->isPrimitive()) {
85 Bits FullBitWidth =
86 Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType()));
87 return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth,
88 /*PackedBools=*/false);
89 }
90
91 // Primitive arrays.
92 if (FieldDesc->isPrimitiveArray()) {
93 QualType ElemType = FieldDesc->getElemQualType();
94 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
95 PrimType ElemT = *Ctx.classify(ElemType);
96 // Special case, since the bools here are packed.
97 bool PackedBools = FieldDesc->getType()->isExtVectorBoolType();
98 unsigned NumElems = FieldDesc->getNumElems();
99 bool Ok = true;
100 for (unsigned I = P.getIndex(); I != NumElems; ++I) {
101 Ok = Ok && F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools);
102 Offset += PackedBools ? Bits(1) : ElemSize;
103 if (Offset >= BitsToRead)
104 break;
105 }
106 return Ok;
107 }
108
109 // Composite arrays.
110 if (FieldDesc->isCompositeArray()) {
111 QualType ElemType = FieldDesc->getElemQualType();
112 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
113 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
114 enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F);
115 Offset += ElemSize;
116 if (Offset >= BitsToRead)
117 break;
118 }
119 return true;
120 }
121
122 // Records.
123 if (FieldDesc->isRecord()) {
124 const Record *R = FieldDesc->ElemRecord;
125 const ASTRecordLayout &Layout =
127 bool Ok = true;
128
129 for (const Record::Field &Fi : R->fields()) {
130 if (Fi.isUnnamedBitField())
131 continue;
132 Pointer Elem = P.atField(Fi.Offset);
133 Bits BitOffset =
134 Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
135 Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
136 }
137 for (const Record::Base &B : R->bases()) {
138 Pointer Elem = P.atField(B.Offset);
139 CharUnits ByteOffset =
140 Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
141 Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
142 Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
143 // FIXME: We should only (need to) do this when bitcasting OUT of the
144 // buffer, not when copying data into it.
145 if (Ok)
146 Elem.initialize();
147 }
148
149 return Ok;
150 }
151
152 llvm_unreachable("Unhandled data type");
153}
154
155static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
156 Bits BitsToRead, DataFunc F) {
157 return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F);
158}
159
160// This function is constexpr if and only if To, From, and the types of
161// all subobjects of To and From are types T such that...
162// (3.1) - is_union_v<T> is false;
163// (3.2) - is_pointer_v<T> is false;
164// (3.3) - is_member_pointer_v<T> is false;
165// (3.4) - is_volatile_v<T> is false; and
166// (3.5) - T has no non-static data members of reference type
167//
168// NOTE: This is a version of checkBitCastConstexprEligibilityType() in
169// ExprConstant.cpp.
171 bool IsToType) {
172 enum {
173 E_Union = 0,
174 E_Pointer,
175 E_MemberPointer,
176 E_Volatile,
177 E_Reference,
178 };
179 enum { C_Member, C_Base };
180
181 auto diag = [&](int Reason) -> bool {
182 const Expr *E = S.Current->getExpr(OpPC);
183 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
184 << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
185 << E->getSourceRange();
186 return false;
187 };
188 auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) {
189 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
190 << NoteType << Construct << T.getUnqualifiedType() << NoteRange;
191 return false;
192 };
193
194 T = T.getCanonicalType();
195
196 if (T->isUnionType())
197 return diag(E_Union);
198 if (T->isPointerType())
199 return diag(E_Pointer);
200 if (T->isMemberPointerType())
201 return diag(E_MemberPointer);
202 if (T.isVolatileQualified())
203 return diag(E_Volatile);
204
205 if (const RecordDecl *RD = T->getAsRecordDecl()) {
206 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
207 for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
208 if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType))
209 return note(C_Base, BS.getType(), BS.getBeginLoc());
210 }
211 }
212 for (const FieldDecl *FD : RD->fields()) {
213 if (FD->getType()->isReferenceType())
214 return diag(E_Reference);
215 if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType))
216 return note(C_Member, FD->getType(), FD->getSourceRange());
217 }
218 }
219
220 if (T->isArrayType() &&
222 IsToType))
223 return false;
224
225 if (const auto *VT = T->getAs<VectorType>()) {
226 const ASTContext &ASTCtx = S.getASTContext();
227 QualType EltTy = VT->getElementType();
228 unsigned NElts = VT->getNumElements();
229 unsigned EltSize =
230 VT->isExtVectorBoolType() ? 1 : ASTCtx.getTypeSize(EltTy);
231
232 if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) {
233 // The vector's size in bits is not a multiple of the target's byte size,
234 // so its layout is unspecified. For now, we'll simply treat these cases
235 // as unsupported (this should only be possible with OpenCL bool vectors
236 // whose element count isn't a multiple of the byte size).
237 const Expr *E = S.Current->getExpr(OpPC);
238 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector)
239 << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth();
240 return false;
241 }
242
243 if (EltTy->isRealFloatingType() &&
244 &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) {
245 // The layout for x86_fp80 vectors seems to be handled very inconsistently
246 // by both clang and LLVM, so for now we won't allow bit_casts involving
247 // it in a constexpr context.
248 const Expr *E = S.Current->getExpr(OpPC);
249 S.FFDiag(E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy;
250 return false;
251 }
252 }
253
254 return true;
255}
256
258 const Pointer &FromPtr,
259 BitcastBuffer &Buffer,
260 bool ReturnOnUninit) {
261 const ASTContext &ASTCtx = Ctx.getASTContext();
262 Endian TargetEndianness =
263 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
264
266 FromPtr, Ctx, Buffer.size(),
267 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
268 bool PackedBools) -> bool {
269 Bits BitWidth = FullBitWidth;
270
271 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
272 BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
273 (unsigned)FullBitWidth.getQuantity()));
274 else if (T == PT_Bool && PackedBools)
275 BitWidth = Bits(1);
276
277 if (BitWidth.isZero())
278 return true;
279
280 // Bits will be left uninitialized and diagnosed when reading.
281 if (!P.isInitialized())
282 return true;
283
284 if (T == PT_Ptr) {
285 assert(P.getType()->isNullPtrType());
286 // Clang treats nullptr_t has having NO bits in its value
287 // representation. So, we accept it here and leave its bits
288 // uninitialized.
289 return true;
290 }
291
292 assert(P.isInitialized());
293 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes());
294 // Work around floating point types that contain unused padding bytes.
295 // This is really just `long double` on x86, which is the only
296 // fundamental type with padding bytes.
297 if (T == PT_Float) {
298 const Floating &F = P.deref<Floating>();
299 Bits NumBits = Bits(
300 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics()));
301 assert(NumBits.isFullByte());
302 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
303 F.bitcastToMemory(Buff.get());
304 // Now, only (maybe) swap the actual size of the float, excluding the
305 // padding bits.
306 if (llvm::sys::IsBigEndianHost)
307 swapBytes(Buff.get(), NumBits.roundToBytes());
308
309 Buffer.markInitialized(BitOffset, NumBits);
310 } else {
311 BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); });
312
313 if (llvm::sys::IsBigEndianHost)
314 swapBytes(Buff.get(), FullBitWidth.roundToBytes());
315 Buffer.markInitialized(BitOffset, BitWidth);
316 }
317
318 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
319 return true;
320 });
321}
322
324 std::byte *Buff, Bits BitWidth, Bits FullBitWidth,
325 bool &HasIndeterminateBits) {
326 assert(Ptr.isLive());
327 assert(Ptr.isBlockPointer());
328 assert(Buff);
329 assert(BitWidth <= FullBitWidth);
330 assert(FullBitWidth.isFullByte());
331 assert(BitWidth.isFullByte());
332
333 BitcastBuffer Buffer(FullBitWidth);
334 size_t BuffSize = FullBitWidth.roundToBytes();
335 if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false))
336 return false;
337
338 bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
339 /*ReturnOnUninit=*/false);
340 HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth);
341
342 const ASTContext &ASTCtx = S.getASTContext();
343 Endian TargetEndianness =
344 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
345 auto B =
346 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness);
347
348 std::memcpy(Buff, B.get(), BuffSize);
349
350 if (llvm::sys::IsBigEndianHost)
351 swapBytes(Buff, BitWidth.roundToBytes());
352
353 return Success;
354}
356 const Pointer &FromPtr, Pointer &ToPtr) {
357 const ASTContext &ASTCtx = S.getASTContext();
358 CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType());
359
360 return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity());
361}
362
364 const Pointer &FromPtr, Pointer &ToPtr,
365 size_t Size) {
366 assert(FromPtr.isLive());
367 assert(FromPtr.isBlockPointer());
368 assert(ToPtr.isBlockPointer());
369
370 QualType FromType = FromPtr.getType();
371 QualType ToType = ToPtr.getType();
372
373 if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true))
374 return false;
375 if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false))
376 return false;
377
378 const ASTContext &ASTCtx = S.getASTContext();
379 BitcastBuffer Buffer(Bytes(Size).toBits());
380 readPointerToBuffer(S.getContext(), FromPtr, Buffer,
381 /*ReturnOnUninit=*/false);
382
383 // Now read the values out of the buffer again and into ToPtr.
384 Endian TargetEndianness =
385 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
387 ToPtr, S.getContext(), Buffer.size(),
388 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth,
389 bool PackedBools) -> bool {
390 QualType PtrType = P.getType();
391 if (T == PT_Float) {
392 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);
393 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
394 assert(NumBits.isFullByte());
395 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
396 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
397 TargetEndianness);
398
399 if (llvm::sys::IsBigEndianHost)
400 swapBytes(M.get(), NumBits.roundToBytes());
401
402 P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics);
403 P.initialize();
404 return true;
405 }
406
407 Bits BitWidth;
408 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
409 BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
410 (unsigned)FullBitWidth.getQuantity()));
411 else if (T == PT_Bool && PackedBools)
412 BitWidth = Bits(1);
413 else
414 BitWidth = FullBitWidth;
415
416 // If any of the bits are uninitialized, we need to abort unless the
417 // target type is std::byte or unsigned char.
418 bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth);
419 if (!Initialized) {
420 if (!PtrType->isStdByteType() &&
421 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&
422 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {
423 const Expr *E = S.Current->getExpr(OpPC);
424 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
425 << PtrType << S.getLangOpts().CharIsSigned
426 << E->getSourceRange();
427
428 return false;
429 }
430 return true;
431 }
432
433 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth,
434 TargetEndianness);
435 if (llvm::sys::IsBigEndianHost)
436 swapBytes(Memory.get(), FullBitWidth.roundToBytes());
437
439 if (BitWidth.nonZero())
440 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
441 .truncate(BitWidth.getQuantity());
442 else
443 P.deref<T>() = T::zero();
444 });
445 P.initialize();
446 return true;
447 });
448
449 return Success;
450}
451
453 const Pointer &SrcPtr, const Pointer &DestPtr,
454 Bits Size) {
455 assert(SrcPtr.isBlockPointer());
456 assert(DestPtr.isBlockPointer());
457
458 unsigned SrcStartOffset = SrcPtr.getByteOffset();
459 unsigned DestStartOffset = DestPtr.getByteOffset();
460
461 enumeratePointerFields(SrcPtr, S.getContext(), Size,
462 [&](const Pointer &P, PrimType T, Bits BitOffset,
463 Bits FullBitWidth, bool PackedBools) -> bool {
464 unsigned SrcOffsetDiff =
465 P.getByteOffset() - SrcStartOffset;
466
467 Pointer DestP =
468 Pointer(DestPtr.asBlockPointer().Pointee,
469 DestPtr.asBlockPointer().Base,
470 DestStartOffset + SrcOffsetDiff);
471
472 TYPE_SWITCH(T, {
473 DestP.deref<T>() = P.deref<T>();
474 DestP.initialize();
475 });
476
477 return true;
478 });
479
480 return true;
481}
Defines the clang::ASTContext interface.
StringRef P
Expr * E
#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B)
llvm::function_ref< bool(const Pointer &P, PrimType Ty, Bits BitOffset, Bits FullBitWidth, bool PackedBools)> DataFunc
Implement __builtin_bit_cast and related operations.
#define BITCAST_TYPE_SWITCH(Expr, B)
static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, bool IsToType)
static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, Bits BitsToRead, DataFunc F)
static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, Bits BitsToRead, DataFunc F)
We use this to recursively iterate over all fields and elements of a pointer and extract relevant dat...
#define bool
Definition: amdgpuintrin.h:20
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
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.
Definition: ASTContext.h:2482
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:799
uint64_t getCharWidth() const
Return the size of the character type, in bits.
Definition: ASTContext.h:2486
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
Definition: RecordLayout.h:38
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
Definition: RecordLayout.h:200
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:249
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:110
Represents a member of a struct/union/class.
Definition: Decl.h:3033
A (possibly-)qualified type.
Definition: Type.h:929
Represents a struct/union/class.
Definition: Decl.h:4148
ASTContext & getASTContext() const
Definition: Sema.h:531
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:324
bool isLittleEndian() const
Definition: TargetInfo.h:1666
bool isArrayType() const
Definition: Type.h:8258
bool isPointerType() const
Definition: Type.h:8186
bool isExtVectorBoolType() const
Definition: Type.h:8306
bool isMemberPointerType() const
Definition: Type.h:8240
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2300
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8731
bool isUnionType() const
Definition: Type.cpp:704
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1920
Represents a GCC generic vector type.
Definition: Type.h:4034
Pointer into the code segment.
Definition: Source.h:30
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:40
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:62
std::optional< PrimType > classify(QualType T) const
Classifies a type.
Definition: Context.cpp:135
const APFloat & getAPFloat() const
Definition: Floating.h:40
void bitcastToMemory(std::byte *Buff) const
Definition: Floating.h:138
Interpreter context.
Definition: InterpState.h:36
A pointer to a memory block, live or dead.
Definition: Pointer.h:83
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:339
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:270
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:571
bool isBlockPointer() const
Definition: Pointer.h:467
void initialize() const
Initializes a field.
Definition: Pointer.cpp:356
Structure/Class descriptor.
Definition: Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition: Record.h:53
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:88
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:80
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())))
const FunctionProtoType * T
@ Success
Template argument deduction was successful.
Track what bits have been initialized to known values and which ones have indeterminate value.
Definition: BitcastBuffer.h:81
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.
Definition: BitcastBuffer.h:93
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.
Definition: BitcastBuffer.h:24
size_t roundToBytes() const
Definition: BitcastBuffer.h:30
bool isFullByte() const
Definition: BitcastBuffer.h:32
static Bits zero()
Definition: BitcastBuffer.h:27
size_t getQuantity() const
Definition: BitcastBuffer.h:29
A quantity in bytes.
Definition: BitcastBuffer.h:55
Describes a memory block created by an allocation site.
Definition: Descriptor.h:116
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:243
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition: Descriptor.h:257
QualType getElemQualType() const
Definition: Descriptor.cpp:408
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition: Descriptor.h:250
QualType getType() const
Definition: Descriptor.cpp:393
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:248
PrimType getPrimType() const
Definition: Descriptor.h:230
bool isRecord() const
Checks if the descriptor is of a record.
Definition: Descriptor.h:262
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:146