40 Bits FullBitWidth,
bool PackedBools)>;
42#define BITCAST_TYPE_SWITCH(Expr, B) \
45 TYPE_SWITCH_CASE(PT_Sint8, B) \
46 TYPE_SWITCH_CASE(PT_Uint8, B) \
47 TYPE_SWITCH_CASE(PT_Sint16, B) \
48 TYPE_SWITCH_CASE(PT_Uint16, B) \
49 TYPE_SWITCH_CASE(PT_Sint32, B) \
50 TYPE_SWITCH_CASE(PT_Uint32, B) \
51 TYPE_SWITCH_CASE(PT_Sint64, B) \
52 TYPE_SWITCH_CASE(PT_Uint64, B) \
53 TYPE_SWITCH_CASE(PT_IntAP, B) \
54 TYPE_SWITCH_CASE(PT_IntAPS, B) \
55 TYPE_SWITCH_CASE(PT_Bool, B) \
57 llvm_unreachable("Unhandled bitcast type"); \
61#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \
64 TYPE_SWITCH_CASE(PT_Sint8, B) \
65 TYPE_SWITCH_CASE(PT_Uint8, B) \
66 TYPE_SWITCH_CASE(PT_Sint16, B) \
67 TYPE_SWITCH_CASE(PT_Uint16, B) \
68 TYPE_SWITCH_CASE(PT_Sint32, B) \
69 TYPE_SWITCH_CASE(PT_Uint32, B) \
70 TYPE_SWITCH_CASE(PT_Sint64, B) \
71 TYPE_SWITCH_CASE(PT_Uint64, B) \
72 TYPE_SWITCH_CASE(PT_Bool, B) \
74 llvm_unreachable("Unhandled bitcast type"); \
89 return F(
P, FieldDesc->
getPrimType(), Offset, FullBitWidth,
97 PrimType ElemT = *Ctx.classify(ElemType);
103 for (
unsigned I =
P.getIndex(); I != NumElems; ++I) {
104 Ok =
Ok && F(
P.atIndex(I), ElemT, Offset, ElemSize, PackedBools);
105 Offset += PackedBools ?
Bits(1) : ElemSize;
106 if (Offset >= BitsToRead)
116 for (
unsigned I =
P.getIndex(); I != FieldDesc->
getNumElems(); ++I) {
119 if (Offset >= BitsToRead)
132 for (
const Record::Field &Fi : R->
fields()) {
133 if (Fi.isUnnamedBitField())
135 Pointer Elem =
P.atField(Fi.Offset);
140 for (
const Record::Base &B : R->
bases()) {
144 Bits BitOffset = Offset +
Bits(Ctx.getASTContext().
toBits(ByteOffset));
155 llvm_unreachable(
"Unhandled data type");
182 enum { C_Member, C_Base };
184 auto diag = [&](
int Reason) ->
bool {
185 const Expr *
E = S.Current->getExpr(OpPC);
186 S.FFDiag(
E, diag::note_constexpr_bit_cast_invalid_type)
187 <<
static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
192 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
193 << NoteType << Construct <<
T.getUnqualifiedType() << NoteRange;
197 T =
T.getCanonicalType();
200 return diag(E_Union);
202 return diag(E_Pointer);
204 return diag(E_MemberPointer);
205 if (
T.isVolatileQualified())
206 return diag(E_Volatile);
209 if (
const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
212 return note(C_Base, BS.getType(), BS.getBeginLoc());
215 for (
const FieldDecl *FD : RD->fields()) {
216 if (FD->getType()->isReferenceType())
217 return diag(E_Reference);
219 return note(C_Member, FD->getType(), FD->getSourceRange());
230 QualType EltTy = VT->getElementType();
231 unsigned NElts = VT->getNumElements();
240 const Expr *
E = S.Current->getExpr(OpPC);
241 S.FFDiag(
E, diag::note_constexpr_bit_cast_invalid_vector)
251 const Expr *
E = S.Current->getExpr(OpPC);
252 S.FFDiag(
E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy;
263 bool ReturnOnUninit) {
264 const ASTContext &ASTCtx = Ctx.getASTContext();
269 FromPtr, Ctx, Buffer.
size(),
271 bool PackedBools) ->
bool {
272 Bits BitWidth = FullBitWidth;
274 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
275 BitWidth = Bits(std::min(FD->getBitWidthValue(),
276 (unsigned)FullBitWidth.getQuantity()));
277 else if (T == PT_Bool && PackedBools)
280 if (BitWidth.isZero())
284 if (!P.isInitialized())
288 assert(P.getType()->isNullPtrType());
295 assert(
P.isInitialized());
296 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.
roundToBytes());
303 llvm::APFloatBase::getSizeInBits(F.
getAPFloat().getSemantics()));
304 assert(NumBits.isFullByte());
305 assert(NumBits.getQuantity() <= FullBitWidth.
getQuantity());
309 if (llvm::sys::IsBigEndianHost)
310 swapBytes(Buff.get(), NumBits.roundToBytes());
316 if (llvm::sys::IsBigEndianHost)
321 Buffer.
pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
327 std::byte *Buff,
Bits BitWidth,
Bits FullBitWidth,
328 bool &HasIndeterminateBits) {
332 assert(BitWidth <= FullBitWidth);
352 std::memcpy(Buff, B.get(), BuffSize);
354 if (llvm::sys::IsBigEndianHost)
391 ToPtr, S.getContext(), Buffer.
size(),
393 bool PackedBools) ->
bool {
394 QualType PtrType = P.getType();
396 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);
397 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
398 assert(NumBits.isFullByte());
399 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
400 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
403 if (llvm::sys::IsBigEndianHost)
404 swapBytes(M.get(), NumBits.roundToBytes());
406 Floating R = S.allocFloat(Semantics);
407 Floating::bitcastFromMemory(M.get(), Semantics, &R);
408 P.deref<Floating>() = R;
414 if (
const FieldDecl *FD =
P.getField(); FD && FD->isBitField())
415 BitWidth =
Bits(std::min(FD->getBitWidthValue(),
420 BitWidth = FullBitWidth;
426 if (!PtrType->isStdByteType() &&
427 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&
428 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {
429 const Expr *E = S.Current->getExpr(OpPC);
430 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
431 << PtrType << S.getLangOpts().CharIsSigned
432 << E->getSourceRange();
439 auto Memory = Buffer.
copyBits(BitOffset, BitWidth, FullBitWidth,
441 if (llvm::sys::IsBigEndianHost)
445 if (BitWidth.nonZero())
446 P.deref<
T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
447 .truncate(BitWidth.getQuantity());
449 P.deref<
T>() = T::zero();
480 Bits FullBitWidth,
bool PackedBools) ->
bool {
481 TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
485 unsigned ValueIndex = 0;
488 Bits FullBitWidth,
bool PackedBools) ->
bool {
490 P.deref<T>() = std::get<T>(Values[ValueIndex]);
499 assert(ValueIndex == Values.size());
Defines the clang::ASTContext interface.
#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B)
std::variant< Pointer, FunctionPointer, MemberPointer, FixedPoint, Integral< 8, false >, Integral< 8, 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
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...
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.
A (possibly-)qualified type.
Represents a struct/union/class.
ASTContext & getASTContext() const
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
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isPointerType() const
bool isMemberPointerType() const
bool isRealFloatingType() const
Floating point categories.
const T * getAs() const
Member-template getAs<specific type>'.
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.
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.
Wrapper around numeric types.
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.
void initialize() const
Initializes a field.
Structure/Class descriptor.
const RecordDecl * getDecl() const
Returns the underlying declaration.
llvm::iterator_range< const_base_iter > bases() const
llvm::iterator_range< const_field_iter > fields() 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.
const FunctionProtoType * 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.
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.