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