43 Bits FullBitWidth,
bool PackedBools)>;
45#define BITCAST_TYPE_SWITCH(Expr, B) \
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) \
60 llvm_unreachable("Unhandled bitcast type"); \
64#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \
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) \
77 llvm_unreachable("Unhandled bitcast type"); \
92 return F(P, FieldDesc->
getPrimType(), Offset, FullBitWidth,
106 for (
unsigned I = P.
getIndex(); I != NumElems; ++I) {
107 Result Res = F(P.
atIndex(I), ElemT, Offset, ElemSize, PackedBools);
110 Offset += PackedBools ?
Bits(1) : ElemSize;
111 if (Offset >= BitsToRead)
125 if (Offset >= BitsToRead)
134 if (R->getDecl()->isInvalidDecl())
140 for (
const Record::Field &Fi : R->fields()) {
141 if (Fi.isUnnamedBitField())
148 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
157 for (
const Record::Base &B : R->bases()) {
166 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
178 llvm_unreachable(
"Unhandled data type");
208 enum { C_Member, C_Base };
210 auto diag = [&](
int Reason) ->
bool {
212 S.
FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
213 <<
static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
217 auto note = [&](
int Construct,
QualType NoteType,
219 S.
Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
220 << NoteType << Construct << T.getUnqualifiedType() << NoteRange;
223 auto unsupported = [&](
QualType T) ->
bool {
225 diag::note_constexpr_bit_cast_unsupported_type)
230 T = T.getCanonicalType();
232 if (T->isUnionType())
233 return diag(E_Union);
234 if (T->isPointerType())
235 return diag(E_Pointer);
236 if (T->isMemberPointerType())
237 return diag(E_MemberPointer);
238 if (T.isVolatileQualified())
239 return diag(E_Volatile);
241 if (
const RecordDecl *RD = T->getAsRecordDecl()) {
242 if (
const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
245 return note(C_Base, BS.getType(), BS.getBeginLoc());
248 for (
const FieldDecl *FD : RD->fields()) {
249 if (FD->getType()->isReferenceType())
250 return diag(E_Reference);
252 return note(C_Member, FD->getType(), FD->getSourceRange());
256 if (T->isArrayType() &&
261 if (
const auto *VT = T->getAs<
VectorType>()) {
263 QualType EltTy = VT->getElementType();
264 unsigned NElts = VT->getNumElements();
274 S.
FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector)
284 return unsupported(EltTy);
288 if (T->isBlockPointerType())
289 return unsupported(T);
297 bool ReturnOnUninit) {
303 FromPtr, Ctx, Buffer.
size(),
305 bool PackedBools) ->
Result {
306 Bits BitWidth = FullBitWidth;
308 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
309 BitWidth = Bits(std::min(FD->getBitWidthValue(),
310 (unsigned)FullBitWidth.getQuantity()));
311 else if (T == PT_Bool && PackedBools)
314 if (BitWidth.isZero())
318 if (!P.isInitialized())
322 assert(P.getType()->isNullPtrType());
330 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.
roundToBytes());
337 llvm::APFloatBase::getSizeInBits(F.
getAPFloat().getSemantics()));
338 assert(NumBits.isFullByte());
339 assert(NumBits.getQuantity() <= FullBitWidth.
getQuantity());
343 if (llvm::sys::IsBigEndianHost)
344 swapBytes(Buff.get(), NumBits.roundToBytes());
349 auto Val = P.
deref<T>();
352 Val.bitcastToMemory(Buff.get());
355 if (llvm::sys::IsBigEndianHost)
360 Buffer.
pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
367 std::byte *Buff,
Bits BitWidth,
Bits FullBitWidth,
368 bool &HasIndeterminateBits) {
372 assert(BitWidth <= FullBitWidth);
392 std::memcpy(Buff, B.get(), BuffSize);
394 if (llvm::sys::IsBigEndianHost)
433 bool PackedBools) ->
Result {
434 QualType PtrType = P.getType();
436 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);
437 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
438 assert(NumBits.isFullByte());
439 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
440 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
443 if (llvm::sys::IsBigEndianHost)
444 swapBytes(M.get(), NumBits.roundToBytes());
446 Floating R = S.allocFloat(Semantics);
447 Floating::bitcastFromMemory(M.get(), Semantics, &R);
448 P.deref<Floating>() = R;
450 return Result::Success;
455 BitWidth =
Bits(std::min(FD->getBitWidthValue(),
460 BitWidth = FullBitWidth;
466 if (!PtrType->isStdByteType() &&
467 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&
468 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {
470 S.
FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
479 auto Memory = Buffer.
copyBits(BitOffset, BitWidth, FullBitWidth,
481 if (llvm::sys::IsBigEndianHost)
498 if (BitWidth.nonZero())
499 P.
deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
500 .truncate(BitWidth.getQuantity());
502 P.
deref<T>() = T::zero();
536 bool PackedBools) ->
Result {
537 TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
542 unsigned ValueIndex = 0;
544 DestPtr, S.getContext(), Size,
546 bool PackedBools) ->
Result {
548 P.deref<T>() = std::get<T>(Values[ValueIndex]);
558 assert(ValueIndex == Values.size());
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(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)
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)
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 ...
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
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.
CharUnits - This is an opaque type for sizes expressed in character units.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
This represents one expression.
Represents a member of a struct/union/class.
bool isBitField() const
Determines whether this field is a bitfield.
A (possibly-)qualified type.
Represents a struct/union/class.
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...
bool isLittleEndian() const
bool isPackedVectorBoolType(const ASTContext &ctx) const
bool isRealFloatingType() const
Floating point categories.
Represents a GCC generic vector type.
Wrapper around boolean types.
Pointer into the code segment.
Holds all information required to evaluate constexpr code in a module.
ASTContext & getASTContext() const
Returns the AST context.
OptPrimType classify(QualType T) const
Classifies a type.
Wrapper around fixed point types.
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
void bitcastToMemory(std::byte *Buff) const
APFloat getAPFloat() const
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, IntegralAP *Result)
Wrapper around numeric types.
const Expr * getExpr(CodePtr PC) const
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
Context & getContext() const
InterpFrame * Current
The current frame.
T allocAP(unsigned BitWidth)
A pointer to a memory block, live or dead.
QualType getType() const
Returns the type of the innermost field.
bool isLive() const
Checks if the pointer is live.
bool isBlockPointer() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Structure/Class descriptor.
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
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)
ASTContext & getASTContext() const
const LangOptions & getLangOpts() const
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.
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.
@ Result
The result type of a method or function.
U cast(CodeGen::Address addr)
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.
size_t roundToBytes() const
size_t getQuantity() const
Describes a memory block created by an allocation site.
unsigned getNumElems() const
Returns the number of elements stored in the block.
bool isPrimitive() const
Checks if the descriptor is of a primitive.
QualType getElemQualType() const
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
QualType getDataType(const ASTContext &Ctx) const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
PrimType getPrimType() const
bool isRecord() const
Checks if the descriptor is of a record.
const Record *const ElemRecord
Pointer to the record, if block contains records.
PtrView atField(unsigned Offset) const
const Descriptor * getFieldDesc() const
const FieldDecl * getField() const
PtrView atIndex(unsigned Idx) const
void startLifetime() const
bool isInitialized() const