clang 24.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(PtrView 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// FIXME: It is unfortunate that we have this function at all, but we can read
82// from a StringPointer. In the later callback-based reading and writing paths,
83// we do assume a BlockPointer though.
84static std::pair<Block *, std::unique_ptr<Descriptor>>
86 const StringLiteral *S = SP.getLiteral();
87 const size_t CharWidth = S->getCharByteWidth();
88 const size_t BitWidth = CharWidth * Ctx.getCharBit();
89 unsigned StringLength = S->getLength();
90
91 OptPrimType CharType =
93 assert(CharType);
94
95 // Create a descriptor for the string.
96 std::unique_ptr<Descriptor> Desc = std::make_unique<Descriptor>(
97 S, S->getType().getTypePtr(), *CharType, StringLength + 1,
98 /*IsConst=*/true,
99 /*isTemporary=*/false,
100 /*isMutable=*/false,
101 /*IsVolatile=*/false);
102
103 // Allocate storage for the string.
104 // The byte length does not include the null terminator.
105 auto *Memory = new std::byte[sizeof(Block) + Desc->getAllocSize()];
106 auto *B = new (Memory) Block(Ctx.getEvalID(), Desc.get(), Block::None);
107 B->invokeCtor();
108
109 Pointer Ptr(B);
110 if (CharWidth == 1) {
111 std::memcpy(&Ptr.elem<char>(0), S->getString().data(), StringLength);
112 } else {
113 // Construct the string in storage.
114 for (unsigned I = 0; I <= StringLength; ++I) {
115 uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
116 INT_TYPE_SWITCH_NO_BOOL(*CharType,
117 Ptr.elem<T>(I) = T::from(CodePoint, BitWidth););
118 }
119 }
120 Ptr.initializeAllElements();
121 return std::make_pair(std::move(B), std::move(Desc));
122}
123
124/// We use this to recursively iterate over all fields and elements of a pointer
125/// and extract relevant data for a bitcast.
126static Result enumerateData(PtrView P, const Context &Ctx, Bits Offset,
127 Bits BitsToRead, DataFunc F, bool Initialize) {
128 const Descriptor *FieldDesc = P.getFieldDesc();
129 assert(FieldDesc);
130
131 // Primitives.
132 if (FieldDesc->isPrimitive()) {
133 Bits FullBitWidth =
134 Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType()));
135 return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth,
136 /*PackedBools=*/false);
137 }
138
139 // Primitive arrays.
140 if (FieldDesc->isPrimitiveArray()) {
141 QualType ElemType = FieldDesc->getElemQualType();
142 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
143 PrimType ElemT = *Ctx.classify(ElemType);
144 // Special case, since the bools here are packed.
145 bool PackedBools =
146 FieldDesc->getType()->isPackedVectorBoolType(Ctx.getASTContext());
147 unsigned NumElems = FieldDesc->getNumElems();
148 bool Ok = true;
149 for (unsigned I = P.getIndex(); I != NumElems; ++I) {
150 Result Res = F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools);
151
152 Ok = Ok && (Res == Result::Success);
153 Offset += PackedBools ? Bits(1) : ElemSize;
154 if (Offset >= BitsToRead)
155 break;
156 }
157 return Ok ? Result::Success : Result::Skip;
158 }
159
160 // Composite arrays.
161 if (FieldDesc->isCompositeArray()) {
162 QualType ElemType = FieldDesc->getElemQualType();
163 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
164 for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) {
165 enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F,
166 Initialize);
167 Offset += ElemSize;
168 if (Offset >= BitsToRead)
169 break;
170 }
171 return Result::Success;
172 }
173
174 // Records.
175 if (FieldDesc->isRecord()) {
176 const Record *R = FieldDesc->ElemRecord;
177 if (R->getDecl()->isInvalidDecl())
178 return Result::Failure;
179 const ASTRecordLayout &Layout =
180 Ctx.getASTContext().getASTRecordLayout(R->getDecl());
181 bool Ok = true;
182
183 for (const Record::Field &Fi : R->fields()) {
184 if (Fi.isUnnamedBitField())
185 continue;
186
187 PtrView Elem = P.atField(Fi.Offset);
188 Bits BitOffset =
189 Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
190 Result Res =
191 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
192 if (Initialize) {
193 if (Res == Result::Success)
194 Elem.initialize();
195 else if (Res == Result::Skip)
196 Elem.startLifetime();
197 }
198 Ok = Ok && Res != Result::Failure;
199 }
200 for (const Record::Base &B : R->bases()) {
201 PtrView Elem = P.atField(B.Offset);
202 if (!Initialize && !Elem.isInitialized())
203 return Result::Failure;
204
205 CharUnits ByteOffset =
207 Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
208 Result Res =
209 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
210 if (Initialize) {
211 if (Res == Result::Success)
212 Elem.initialize();
213 else if (Res == Result::Skip)
214 Elem.startLifetime();
215 }
216 Ok = Ok && Res != Result::Failure;
217 }
218 return Ok ? Result::Success : Result::Failure;
219 }
220
221 llvm_unreachable("Unhandled data type");
222}
223
224static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
225 Bits BitsToRead, DataFunc F,
226 bool Initialize) {
227
228 if (P.isStringPointer()) {
229 auto [B, Desc] = convertToBlockPointer(Ctx, P.asStringPointer());
230
231 bool Result = enumerateData(Pointer(B).atIndex(P.getIndex()).view(), Ctx,
232 Bits::zero(), BitsToRead, F,
233 Initialize) == Result::Failure;
234 delete[] reinterpret_cast<std::byte *>(B);
235 return Result;
236 }
237
238 return enumerateData(P.view(), Ctx, Bits::zero(), BitsToRead, F,
239 Initialize) != Result::Failure;
240}
241
242// This function is constexpr if and only if To, From, and the types of
243// all subobjects of To and From are types T such that...
244// (3.1) - is_union_v<T> is false;
245// (3.2) - is_pointer_v<T> is false;
246// (3.3) - is_member_pointer_v<T> is false;
247// (3.4) - is_volatile_v<T> is false; and
248// (3.5) - T has no non-static data members of reference type
249//
250// NOTE: This is a version of checkBitCastConstexprEligibilityType() in
251// ExprConstant.cpp.
253 bool IsToType) {
254 enum {
255 E_Union = 0,
256 E_Pointer,
257 E_MemberPointer,
258 E_Volatile,
259 E_Reference,
260 };
261 enum { C_Member, C_Base };
262
263 auto diag = [&](int Reason) -> bool {
264 const Expr *E = S.Current->getExpr(OpPC);
265 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
266 << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
267 << E->getSourceRange();
268 return false;
269 };
270 auto note = [&](int Construct, QualType NoteType,
271 SourceRange NoteRange) -> bool {
272 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
273 << NoteType << Construct << T.getUnqualifiedType() << NoteRange;
274 return false;
275 };
276 auto unsupported = [&](QualType T) -> bool {
277 S.FFDiag(S.Current->getSource(OpPC),
278 diag::note_constexpr_bit_cast_unsupported_type)
279 << T;
280 return false;
281 };
282
283 T = T.getCanonicalType();
284
285 if (T->isUnionType())
286 return diag(E_Union);
287 if (T->isPointerType())
288 return diag(E_Pointer);
289 if (T->isMemberPointerType())
290 return diag(E_MemberPointer);
291 if (T.isVolatileQualified())
292 return diag(E_Volatile);
293
294 if (const RecordDecl *RD = T->getAsRecordDecl()) {
295 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
296 for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
297 if (!checkBitcastType(S, OpPC, BS.getType(), IsToType))
298 return note(C_Base, BS.getType(), BS.getBeginLoc());
299 }
300 }
301 for (const FieldDecl *FD : RD->fields()) {
302 if (FD->getType()->isReferenceType())
303 return diag(E_Reference);
304 if (!checkBitcastType(S, OpPC, FD->getType(), IsToType))
305 return note(C_Member, FD->getType(), FD->getSourceRange());
306 }
307 }
308
309 if (T->isArrayType() &&
311 IsToType))
312 return false;
313
314 if (const auto *VT = T->getAs<VectorType>()) {
315 const ASTContext &ASTCtx = S.getASTContext();
316 QualType EltTy = VT->getElementType();
317 unsigned NElts = VT->getNumElements();
318 unsigned EltSize =
319 VT->isPackedVectorBoolType(ASTCtx) ? 1 : ASTCtx.getTypeSize(EltTy);
320
321 if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) {
322 // The vector's size in bits is not a multiple of the target's byte size,
323 // so its layout is unspecified. For now, we'll simply treat these cases
324 // as unsupported (this should only be possible with OpenCL bool vectors
325 // whose element count isn't a multiple of the byte size).
326 S.FFDiag(S.Current->getSource(OpPC),
327 diag::note_constexpr_bit_cast_invalid_vector)
328 << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth();
329 return false;
330 }
331
332 if (EltTy->isRealFloatingType() &&
333 &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) {
334 // The layout for x86_fp80 vectors seems to be handled very inconsistently
335 // by both clang and LLVM, so for now we won't allow bit_casts involving
336 // it in a constexpr context.
337 return unsupported(EltTy);
338 }
339 }
340
341 if (T->isBlockPointerType())
342 return unsupported(T);
343
344 return true;
345}
346
348 const Pointer &FromPtr,
349 BitcastBuffer &Buffer,
350 bool ReturnOnUninit) {
351 const ASTContext &ASTCtx = Ctx.getASTContext();
352 Endian TargetEndianness =
354
356 FromPtr, Ctx, Buffer.size(),
357 [&](PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
358 bool PackedBools) -> Result {
359 Bits BitWidth = FullBitWidth;
360
361 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
362 BitWidth = Bits(std::min(FD->getBitWidthValue(),
363 (unsigned)FullBitWidth.getQuantity()));
364 else if (T == PT_Bool && PackedBools)
365 BitWidth = Bits(1);
366
367 if (BitWidth.isZero())
368 return Result::Skip;
369
370 // Bits will be left uninitialized and diagnosed when reading.
371 if (!P.isInitialized())
372 return Result::Skip;
373
374 if (T == PT_Ptr) {
375 assert(P.getType()->isNullPtrType());
376 // Clang treats nullptr_t has having NO bits in its value
377 // representation. So, we accept it here and leave its bits
378 // uninitialized.
379 return Result::Skip;
380 }
381
382 assert(P.isInitialized());
383 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes());
384 // Work around floating point types that contain unused padding bytes.
385 // This is really just `long double` on x86, which is the only
386 // fundamental type with padding bytes.
387 if (T == PT_Float) {
388 const Floating &F = P.deref<Floating>();
389 Bits NumBits = Bits(
390 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics()));
391 assert(NumBits.isFullByte());
392 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
393 F.bitcastToMemory(Buff.get());
394 // Now, only (maybe) swap the actual size of the float, excluding
395 // the padding bits.
396 if (llvm::sys::IsBigEndianHost)
397 swapBytes(Buff.get(), NumBits.roundToBytes());
398
399 Buffer.markInitialized(BitOffset, NumBits);
400 } else {
402 auto Val = P.deref<T>();
403 if (!Val.isNumber())
404 return Result::Failure;
405 Val.bitcastToMemory(Buff.get());
406 });
407
408 if (llvm::sys::IsBigEndianHost)
409 swapBytes(Buff.get(), FullBitWidth.roundToBytes());
410 Buffer.markInitialized(BitOffset, BitWidth);
411 }
412
413 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
414 return Result::Success;
415 },
416 false);
417}
418
420 std::byte *Buff, Bits BitWidth, Bits FullBitWidth,
421 bool &HasIndeterminateBits) {
422 assert(Ptr.isLive());
423 assert(Ptr.isReadablePointerType());
424 assert(Buff);
425 assert(BitWidth <= FullBitWidth);
426 assert(FullBitWidth.isFullByte());
427 assert(BitWidth.isFullByte());
428
429 BitcastBuffer Buffer(FullBitWidth);
430 size_t BuffSize = FullBitWidth.roundToBytes();
431 QualType DataType = Ptr.getType();
432 if (!checkBitcastType(S, OpPC, DataType, /*IsToType=*/false))
433 return false;
434
435 bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
436 /*ReturnOnUninit=*/false);
437 HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth);
438
439 const ASTContext &ASTCtx = S.getASTContext();
440 Endian TargetEndianness =
442 auto B =
443 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness);
444
445 std::memcpy(Buff, B.get(), BuffSize);
446
447 if (llvm::sys::IsBigEndianHost)
448 swapBytes(Buff, BitWidth.roundToBytes());
449
450 return Success;
451}
453 const Pointer &FromPtr, Pointer &ToPtr) {
454 const ASTContext &ASTCtx = S.getASTContext();
455 CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType());
456
457 return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity());
458}
459
461 const Pointer &FromPtr, Pointer &ToPtr,
462 size_t Size) {
463 assert(FromPtr.isLive());
464 assert(FromPtr.isBlockPointer());
465 assert(ToPtr.isBlockPointer());
466
467 QualType FromType = FromPtr.getFieldDesc()->getDataType(S.getASTContext());
468 QualType ToType = ToPtr.getFieldDesc()->getDataType(S.getASTContext());
469
470 if (!checkBitcastType(S, OpPC, ToType, /*IsToType=*/true))
471 return false;
472 if (!checkBitcastType(S, OpPC, FromType, /*IsToType=*/false))
473 return false;
474
475 const ASTContext &ASTCtx = S.getASTContext();
476 BitcastBuffer Buffer(Bytes(Size).toBits());
477 readPointerToBuffer(S.getContext(), FromPtr, Buffer,
478 /*ReturnOnUninit=*/false);
479
480 // Now read the values out of the buffer again and into ToPtr.
481 Endian TargetEndianness =
484 ToPtr, S.getContext(), Buffer.size(),
485 [&](PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
486 bool PackedBools) -> Result {
487 QualType PtrType = P.getType();
488 if (T == PT_Float) {
489 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);
490 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
491 assert(NumBits.isFullByte());
492 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
493 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
494 TargetEndianness);
495
496 if (llvm::sys::IsBigEndianHost)
497 swapBytes(M.get(), NumBits.roundToBytes());
498
499 Floating R = S.allocFloat(Semantics);
500 Floating::bitcastFromMemory(M.get(), Semantics, &R);
501 P.deref<Floating>() = R;
502 P.initialize();
503 return Result::Success;
504 }
505
506 Bits BitWidth;
507 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
508 BitWidth = Bits(std::min(FD->getBitWidthValue(),
509 (unsigned)FullBitWidth.getQuantity()));
510 else if (T == PT_Bool && PackedBools)
511 BitWidth = Bits(1);
512 else
513 BitWidth = FullBitWidth;
514
515 // If any of the bits are uninitialized, we need to abort unless the
516 // target type is std::byte or unsigned char.
517 bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth);
518 if (!Initialized) {
519 if (!PtrType->isStdByteType() &&
520 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&
521 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {
522 const Expr *E = S.Current->getExpr(OpPC);
523 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
524 << PtrType << S.getLangOpts().CharIsSigned
525 << E->getSourceRange();
526
527 return Result::Failure;
528 }
529 return Result::Skip;
530 }
531
532 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth,
533 TargetEndianness);
534 if (llvm::sys::IsBigEndianHost)
535 swapBytes(Memory.get(), FullBitWidth.roundToBytes());
536
537 if (T == PT_IntAPS) {
539 S.allocAP<IntegralAP<true>>(FullBitWidth.getQuantity());
541 FullBitWidth.getQuantity(),
542 &P.deref<IntegralAP<true>>());
543 } else if (T == PT_IntAP) {
545 S.allocAP<IntegralAP<false>>(FullBitWidth.getQuantity());
547 FullBitWidth.getQuantity(),
549 } else {
551 if (BitWidth.nonZero())
552 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
553 .truncate(BitWidth.getQuantity());
554 else
555 P.deref<T>() = T::zero();
556 });
557 }
558 P.initialize();
559 return Result::Success;
560 },
561 true);
562
563 return Success;
564}
565
567 std::variant<Pointer, MemberPointer, FixedPoint, Char<false>, Char<true>,
571 Reflect>;
572
573// NB: This implementation isn't exactly ideal, but:
574// 1) We can't just do a bitcast here since we need to be able to
575// copy pointers.
576// 2) This also needs to handle overlapping regions.
577// 3) We currently have no way of iterating over the fields of a pointer
578// backwards.
580 const Pointer &SrcPtr, const Pointer &DestPtr,
581 Bits Size) {
582 assert(SrcPtr.isReadablePointerType());
583 assert(DestPtr.isBlockPointer());
584
586
587 if (SrcPtr.isStringPointer()) {
588 const auto &SP = SrcPtr.asStringPointer();
589
590 auto [B, Desc] = convertToBlockPointer(S.getContext(), SP);
592 Pointer(B).atIndex(SrcPtr.getIndex()), S.getContext(), Size,
593 [&](const PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
594 bool PackedBools) -> Result {
595 TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
596 return Result::Success;
597 },
598 false);
599
600 delete[] B;
601 } else {
602
604 SrcPtr, S.getContext(), Size,
605 [&](const PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
606 bool PackedBools) -> Result {
607 TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
608 return Result::Success;
609 },
610 false);
611 }
612
613 unsigned ValueIndex = 0;
615 DestPtr, S.getContext(), Size,
616 [&](const PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
617 bool PackedBools) -> Result {
618 TYPE_SWITCH(T, {
619 P.deref<T>() = std::get<T>(Values[ValueIndex]);
620 P.initialize();
621 });
622
623 ++ValueIndex;
624 return Result::Success;
625 },
626 true);
627
628 // We should've read all the values into DestPtr.
629 assert(ValueIndex == Values.size());
630
631 return true;
632}
Defines the clang::ASTContext interface.
static Result enumerateData(PtrView 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.
static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, Bits BitsToRead, DataFunc F, bool Initialize)
static std::pair< Block *, std::unique_ptr< Descriptor > > convertToBlockPointer(const Context &Ctx, const StringPointer &SP)
llvm::function_ref< Result(PtrView P, PrimType Ty, Bits BitOffset, Bits FullBitWidth, bool PackedBools)> DataFunc
Used to iterate over pointer fields.
std::variant< Pointer, 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, Reflect > PrimTypeVariant
#define BITCAST_TYPE_SWITCH(Expr, B)
static bool checkBitcastType(InterpState &S, CodePtr OpPC, QualType T, bool IsToType)
#define INT_TYPE_SWITCH_NO_BOOL(Expr, B)
Definition PrimType.h:297
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:245
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:971
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.
QualType getElementType() const
Definition TypeBase.h:3832
Represents a base class of a C++ class.
Definition DeclCXX.h:146
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:155
This represents one expression.
Definition Expr.h:114
QualType getType() const
Definition Expr.h:146
Represents a member of a struct/union/class.
Definition Decl.h:3311
bool isBitField() const
Determines whether this field is a bitfield.
Definition Decl.h:3414
A (possibly-)qualified type.
Definition TypeBase.h:938
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8578
Represents a struct/union/class.
Definition Decl.h:4476
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
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1844
unsigned getLength() const
Definition Expr.h:1969
uint32_t getCodeUnit(size_t I) const
Return the code unit at the given position.
Definition Expr.h:1931
StringRef getString() const
Definition Expr.h:1912
unsigned getCharByteWidth() const
Definition Expr.h:1971
bool isLittleEndian() const
bool isPackedVectorBoolType(const ASTContext &ctx) const
Definition Type.cpp:542
const ArrayType * castAsArrayTypeUnsafe() const
A variant of castAs<> for array type which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9507
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2533
Represents a GCC generic vector type.
Definition TypeBase.h:4398
A memory block, either on the stack or in the heap.
Definition Block.h:68
Wrapper around boolean types.
Definition Boolean.h:23
Pointer into the code segment.
Definition Source.h:31
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:49
unsigned getCharBit() const
Returns CHAR_BIT.
Definition Context.cpp:607
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:116
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:524
unsigned getEvalID() const
Definition Context.h:190
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
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
const Expr * getExpr(CodePtr PC) const
Interpreter context.
Definition InterpState.h:47
Context & getContext() const
Definition InterpState.h:93
InterpFrame * Current
The current frame.
T allocAP(unsigned BitWidth)
A pointer to a memory block, live or dead.
Definition Pointer.h:547
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:1036
bool isStringPointer() const
Definition Pointer.h:877
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:727
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:675
const StringPointer & asStringPointer() const
Definition Pointer.h:864
bool isBlockPointer() const
Definition Pointer.h:873
bool isReadablePointerType() const
Definition Pointer.h:1213
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:717
PtrView view() const
Definition Pointer.h:606
Structure/Class descriptor.
Definition Record.h:27
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:86
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:37
ASTContext & getASTContext() const
Definition State.h:92
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:35
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest, bool Activate, bool Diagnose)
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)
Top level wrappers for InstallAPI frontend operations.
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:906
const FunctionProtoType * T
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:132
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:255
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:269
QualType getElemQualType() const
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:262
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:260
PrimType getPrimType() const
Definition Descriptor.h:240
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:274
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:156
PtrView atField(unsigned Offset) const
Definition Pointer.h:274
const Descriptor * getFieldDesc() const
Definition Pointer.h:81
const FieldDecl * getField() const
Definition Pointer.h:159
PtrView atIndex(unsigned Idx) const
Definition Pointer.h:210
void startLifetime() const
Definition Pointer.h:339
PtrView narrow() const
Definition Pointer.h:91
bool isInitialized() const
Definition Pointer.h:302
void initialize() const
Definition Pointer.cpp:817
T & deref() const
Definition Pointer.h:245
int64_t getIndex() const
Definition Pointer.h:219
const StringLiteral * getLiteral() const
Definition Pointer.h:400