1ef2a104cSTimm Baeder //===-------------------- InterpBuiltinBitCast.cpp --------------*- C++ -*-===// 2ef2a104cSTimm Baeder // 3ef2a104cSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ef2a104cSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5ef2a104cSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ef2a104cSTimm Baeder // 7ef2a104cSTimm Baeder //===----------------------------------------------------------------------===// 8ef2a104cSTimm Baeder #include "InterpBuiltinBitCast.h" 912ca72baSTimm Bäder #include "BitcastBuffer.h" 10ef2a104cSTimm Baeder #include "Boolean.h" 11ef2a104cSTimm Baeder #include "Context.h" 12ef2a104cSTimm Baeder #include "Floating.h" 13ef2a104cSTimm Baeder #include "Integral.h" 14ef2a104cSTimm Baeder #include "InterpState.h" 15ef2a104cSTimm Baeder #include "MemberPointer.h" 16ef2a104cSTimm Baeder #include "Pointer.h" 17ef2a104cSTimm Baeder #include "Record.h" 18ef2a104cSTimm Baeder #include "clang/AST/ASTContext.h" 19ef2a104cSTimm Baeder #include "clang/AST/RecordLayout.h" 20ef2a104cSTimm Baeder #include "clang/Basic/TargetInfo.h" 21ef2a104cSTimm Baeder 22ef2a104cSTimm Baeder using namespace clang; 23ef2a104cSTimm Baeder using namespace clang::interp; 24ef2a104cSTimm Baeder 2512ca72baSTimm Bäder /// Implement __builtin_bit_cast and related operations. 2612ca72baSTimm Bäder /// Since our internal representation for data is more complex than 2712ca72baSTimm Bäder /// something we can simply memcpy or memcmp, we first bitcast all the data 2812ca72baSTimm Bäder /// into a buffer, which we then later use to copy the data into the target. 2912ca72baSTimm Bäder 3012ca72baSTimm Bäder // TODO: 3112ca72baSTimm Bäder // - Try to minimize heap allocations. 3212ca72baSTimm Bäder // - Optimize the common case of only pushing and pulling full 3312ca72baSTimm Bäder // bytes to/from the buffer. 3412ca72baSTimm Bäder 35ef2a104cSTimm Baeder /// Used to iterate over pointer fields. 3674393f3dSTimm Baeder using DataFunc = 3774393f3dSTimm Baeder llvm::function_ref<bool(const Pointer &P, PrimType Ty, Bits BitOffset, 3874393f3dSTimm Baeder Bits FullBitWidth, bool PackedBools)>; 39ef2a104cSTimm Baeder 40ef2a104cSTimm Baeder #define BITCAST_TYPE_SWITCH(Expr, B) \ 41ef2a104cSTimm Baeder do { \ 42ef2a104cSTimm Baeder switch (Expr) { \ 43ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint8, B) \ 44ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint8, B) \ 45ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint16, B) \ 46ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint16, B) \ 47ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint32, B) \ 48ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint32, B) \ 49ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint64, B) \ 50ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint64, B) \ 51ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_IntAP, B) \ 52ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_IntAPS, B) \ 53ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Bool, B) \ 54ef2a104cSTimm Baeder default: \ 55ef2a104cSTimm Baeder llvm_unreachable("Unhandled bitcast type"); \ 56ef2a104cSTimm Baeder } \ 57ef2a104cSTimm Baeder } while (0) 58ef2a104cSTimm Baeder 592588b8beSTimm Baeder #define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \ 60ef2a104cSTimm Baeder do { \ 61ef2a104cSTimm Baeder switch (Expr) { \ 62ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint8, B) \ 63ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint8, B) \ 64ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint16, B) \ 65ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint16, B) \ 66ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint32, B) \ 67ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint32, B) \ 68ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Sint64, B) \ 69ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Uint64, B) \ 70ef2a104cSTimm Baeder TYPE_SWITCH_CASE(PT_Bool, B) \ 71ef2a104cSTimm Baeder default: \ 72ef2a104cSTimm Baeder llvm_unreachable("Unhandled bitcast type"); \ 73ef2a104cSTimm Baeder } \ 74ef2a104cSTimm Baeder } while (0) 75ef2a104cSTimm Baeder 7612ca72baSTimm Bäder /// We use this to recursively iterate over all fields and elements of a pointer 77ef2a104cSTimm Baeder /// and extract relevant data for a bitcast. 7812ca72baSTimm Bäder static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, 7912ca72baSTimm Bäder Bits BitsToRead, DataFunc F) { 80ef2a104cSTimm Baeder const Descriptor *FieldDesc = P.getFieldDesc(); 81ef2a104cSTimm Baeder assert(FieldDesc); 82ef2a104cSTimm Baeder 83ef2a104cSTimm Baeder // Primitives. 8474393f3dSTimm Baeder if (FieldDesc->isPrimitive()) { 8574393f3dSTimm Baeder Bits FullBitWidth = 8674393f3dSTimm Baeder Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType())); 8774393f3dSTimm Baeder return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth, 8874393f3dSTimm Baeder /*PackedBools=*/false); 8974393f3dSTimm Baeder } 90ef2a104cSTimm Baeder 91ef2a104cSTimm Baeder // Primitive arrays. 92ef2a104cSTimm Baeder if (FieldDesc->isPrimitiveArray()) { 93ef2a104cSTimm Baeder QualType ElemType = FieldDesc->getElemQualType(); 9474393f3dSTimm Baeder Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); 95ef2a104cSTimm Baeder PrimType ElemT = *Ctx.classify(ElemType); 961b3da362STimm Baeder // Special case, since the bools here are packed. 971b3da362STimm Baeder bool PackedBools = FieldDesc->getType()->isExtVectorBoolType(); 9812ca72baSTimm Bäder unsigned NumElems = FieldDesc->getNumElems(); 99ef2a104cSTimm Baeder bool Ok = true; 10012ca72baSTimm Bäder for (unsigned I = P.getIndex(); I != NumElems; ++I) { 10174393f3dSTimm Baeder Ok = Ok && F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools); 10274393f3dSTimm Baeder Offset += PackedBools ? Bits(1) : ElemSize; 10312ca72baSTimm Bäder if (Offset >= BitsToRead) 10412ca72baSTimm Bäder break; 105ef2a104cSTimm Baeder } 106ef2a104cSTimm Baeder return Ok; 107ef2a104cSTimm Baeder } 108ef2a104cSTimm Baeder 109ef2a104cSTimm Baeder // Composite arrays. 110ef2a104cSTimm Baeder if (FieldDesc->isCompositeArray()) { 111ef2a104cSTimm Baeder QualType ElemType = FieldDesc->getElemQualType(); 11274393f3dSTimm Baeder Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); 113d5c8af49STimm Baeder for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) { 11412ca72baSTimm Bäder enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); 11574393f3dSTimm Baeder Offset += ElemSize; 11612ca72baSTimm Bäder if (Offset >= BitsToRead) 11712ca72baSTimm Bäder break; 118ef2a104cSTimm Baeder } 119ef2a104cSTimm Baeder return true; 120ef2a104cSTimm Baeder } 121ef2a104cSTimm Baeder 122ef2a104cSTimm Baeder // Records. 123ef2a104cSTimm Baeder if (FieldDesc->isRecord()) { 124ef2a104cSTimm Baeder const Record *R = FieldDesc->ElemRecord; 125ef2a104cSTimm Baeder const ASTRecordLayout &Layout = 126ef2a104cSTimm Baeder Ctx.getASTContext().getASTRecordLayout(R->getDecl()); 127ef2a104cSTimm Baeder bool Ok = true; 128ef2a104cSTimm Baeder 12912ca72baSTimm Bäder for (const Record::Field &Fi : R->fields()) { 1307aec6dc4STimm Baeder if (Fi.isUnnamedBitField()) 1317aec6dc4STimm Baeder continue; 13212ca72baSTimm Bäder Pointer Elem = P.atField(Fi.Offset); 13312ca72baSTimm Bäder Bits BitOffset = 13412ca72baSTimm Bäder Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex())); 13512ca72baSTimm Bäder Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F); 136ef2a104cSTimm Baeder } 13712ca72baSTimm Bäder for (const Record::Base &B : R->bases()) { 13812ca72baSTimm Bäder Pointer Elem = P.atField(B.Offset); 139ef2a104cSTimm Baeder CharUnits ByteOffset = 14012ca72baSTimm Bäder Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl)); 14112ca72baSTimm Bäder Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset)); 14212ca72baSTimm Bäder Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F); 1437aec6dc4STimm Baeder // FIXME: We should only (need to) do this when bitcasting OUT of the 1447aec6dc4STimm Baeder // buffer, not when copying data into it. 1457aec6dc4STimm Baeder if (Ok) 1467aec6dc4STimm Baeder Elem.initialize(); 147ef2a104cSTimm Baeder } 148ef2a104cSTimm Baeder 149ef2a104cSTimm Baeder return Ok; 150ef2a104cSTimm Baeder } 151ef2a104cSTimm Baeder 152ef2a104cSTimm Baeder llvm_unreachable("Unhandled data type"); 153ef2a104cSTimm Baeder } 154ef2a104cSTimm Baeder 155ef2a104cSTimm Baeder static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, 15612ca72baSTimm Bäder Bits BitsToRead, DataFunc F) { 15712ca72baSTimm Bäder return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F); 158ef2a104cSTimm Baeder } 159ef2a104cSTimm Baeder 160ef2a104cSTimm Baeder // This function is constexpr if and only if To, From, and the types of 161ef2a104cSTimm Baeder // all subobjects of To and From are types T such that... 162ef2a104cSTimm Baeder // (3.1) - is_union_v<T> is false; 163ef2a104cSTimm Baeder // (3.2) - is_pointer_v<T> is false; 164ef2a104cSTimm Baeder // (3.3) - is_member_pointer_v<T> is false; 165ef2a104cSTimm Baeder // (3.4) - is_volatile_v<T> is false; and 166ef2a104cSTimm Baeder // (3.5) - T has no non-static data members of reference type 167ef2a104cSTimm Baeder // 168ef2a104cSTimm Baeder // NOTE: This is a version of checkBitCastConstexprEligibilityType() in 169ef2a104cSTimm Baeder // ExprConstant.cpp. 170ef2a104cSTimm Baeder static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, 171ef2a104cSTimm Baeder bool IsToType) { 172ef2a104cSTimm Baeder enum { 173ef2a104cSTimm Baeder E_Union = 0, 174ef2a104cSTimm Baeder E_Pointer, 175ef2a104cSTimm Baeder E_MemberPointer, 176ef2a104cSTimm Baeder E_Volatile, 177ef2a104cSTimm Baeder E_Reference, 178ef2a104cSTimm Baeder }; 179ef2a104cSTimm Baeder enum { C_Member, C_Base }; 180ef2a104cSTimm Baeder 181ef2a104cSTimm Baeder auto diag = [&](int Reason) -> bool { 182ef2a104cSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 183ef2a104cSTimm Baeder S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type) 184ef2a104cSTimm Baeder << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason 185ef2a104cSTimm Baeder << E->getSourceRange(); 186ef2a104cSTimm Baeder return false; 187ef2a104cSTimm Baeder }; 188ef2a104cSTimm Baeder auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) { 189ef2a104cSTimm Baeder S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype) 190476b208eSTimm Baeder << NoteType << Construct << T.getUnqualifiedType() << NoteRange; 191ef2a104cSTimm Baeder return false; 192ef2a104cSTimm Baeder }; 193ef2a104cSTimm Baeder 194ef2a104cSTimm Baeder T = T.getCanonicalType(); 195ef2a104cSTimm Baeder 196ef2a104cSTimm Baeder if (T->isUnionType()) 197ef2a104cSTimm Baeder return diag(E_Union); 198ef2a104cSTimm Baeder if (T->isPointerType()) 199ef2a104cSTimm Baeder return diag(E_Pointer); 200ef2a104cSTimm Baeder if (T->isMemberPointerType()) 201ef2a104cSTimm Baeder return diag(E_MemberPointer); 202ef2a104cSTimm Baeder if (T.isVolatileQualified()) 203ef2a104cSTimm Baeder return diag(E_Volatile); 204ef2a104cSTimm Baeder 205ef2a104cSTimm Baeder if (const RecordDecl *RD = T->getAsRecordDecl()) { 206ef2a104cSTimm Baeder if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { 207ef2a104cSTimm Baeder for (const CXXBaseSpecifier &BS : CXXRD->bases()) { 208ef2a104cSTimm Baeder if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType)) 209ef2a104cSTimm Baeder return note(C_Base, BS.getType(), BS.getBeginLoc()); 210ef2a104cSTimm Baeder } 211ef2a104cSTimm Baeder } 212ef2a104cSTimm Baeder for (const FieldDecl *FD : RD->fields()) { 213ef2a104cSTimm Baeder if (FD->getType()->isReferenceType()) 214ef2a104cSTimm Baeder return diag(E_Reference); 215ef2a104cSTimm Baeder if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType)) 216ef2a104cSTimm Baeder return note(C_Member, FD->getType(), FD->getSourceRange()); 217ef2a104cSTimm Baeder } 218ef2a104cSTimm Baeder } 219ef2a104cSTimm Baeder 220ef2a104cSTimm Baeder if (T->isArrayType() && 221ef2a104cSTimm Baeder !CheckBitcastType(S, OpPC, S.getASTContext().getBaseElementType(T), 222ef2a104cSTimm Baeder IsToType)) 223ef2a104cSTimm Baeder return false; 224ef2a104cSTimm Baeder 2250fb06172STimm Baeder if (const auto *VT = T->getAs<VectorType>()) { 2260fb06172STimm Baeder const ASTContext &ASTCtx = S.getASTContext(); 2270fb06172STimm Baeder QualType EltTy = VT->getElementType(); 2280fb06172STimm Baeder unsigned NElts = VT->getNumElements(); 2290fb06172STimm Baeder unsigned EltSize = 2300fb06172STimm Baeder VT->isExtVectorBoolType() ? 1 : ASTCtx.getTypeSize(EltTy); 2310fb06172STimm Baeder 2320fb06172STimm Baeder if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) { 2330fb06172STimm Baeder // The vector's size in bits is not a multiple of the target's byte size, 2340fb06172STimm Baeder // so its layout is unspecified. For now, we'll simply treat these cases 2350fb06172STimm Baeder // as unsupported (this should only be possible with OpenCL bool vectors 2360fb06172STimm Baeder // whose element count isn't a multiple of the byte size). 2370fb06172STimm Baeder const Expr *E = S.Current->getExpr(OpPC); 2380fb06172STimm Baeder S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector) 2390fb06172STimm Baeder << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth(); 2400fb06172STimm Baeder return false; 2410fb06172STimm Baeder } 2420fb06172STimm Baeder 2430fb06172STimm Baeder if (EltTy->isRealFloatingType() && 2440fb06172STimm Baeder &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) { 2450fb06172STimm Baeder // The layout for x86_fp80 vectors seems to be handled very inconsistently 2460fb06172STimm Baeder // by both clang and LLVM, so for now we won't allow bit_casts involving 2470fb06172STimm Baeder // it in a constexpr context. 2480fb06172STimm Baeder const Expr *E = S.Current->getExpr(OpPC); 2490fb06172STimm Baeder S.FFDiag(E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy; 2500fb06172STimm Baeder return false; 2510fb06172STimm Baeder } 2520fb06172STimm Baeder } 2530fb06172STimm Baeder 254ef2a104cSTimm Baeder return true; 255ef2a104cSTimm Baeder } 256ef2a104cSTimm Baeder 2578713914dSTimm Baeder bool clang::interp::readPointerToBuffer(const Context &Ctx, 2588713914dSTimm Baeder const Pointer &FromPtr, 2598713914dSTimm Baeder BitcastBuffer &Buffer, 2608713914dSTimm Baeder bool ReturnOnUninit) { 261ef2a104cSTimm Baeder const ASTContext &ASTCtx = Ctx.getASTContext(); 26212ca72baSTimm Bäder Endian TargetEndianness = 26312ca72baSTimm Bäder ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 264ef2a104cSTimm Baeder 265ef2a104cSTimm Baeder return enumeratePointerFields( 26612ca72baSTimm Bäder FromPtr, Ctx, Buffer.size(), 26774393f3dSTimm Baeder [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, 2681b3da362STimm Baeder bool PackedBools) -> bool { 26974393f3dSTimm Baeder Bits BitWidth = FullBitWidth; 270ef2a104cSTimm Baeder 27174393f3dSTimm Baeder if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) 272*cfe26358STimm Baeder BitWidth = Bits(std::min(FD->getBitWidthValue(), 2737aec6dc4STimm Baeder (unsigned)FullBitWidth.getQuantity())); 27474393f3dSTimm Baeder else if (T == PT_Bool && PackedBools) 2757aec6dc4STimm Baeder BitWidth = Bits(1); 2767aec6dc4STimm Baeder 2777aec6dc4STimm Baeder if (BitWidth.isZero()) 2787aec6dc4STimm Baeder return true; 2797aec6dc4STimm Baeder 280b4150ed1STimm Baeder // Bits will be left uninitialized and diagnosed when reading. 281b4150ed1STimm Baeder if (!P.isInitialized()) 282b4150ed1STimm Baeder return true; 2837aec6dc4STimm Baeder 284b6217f67STimm Baeder if (T == PT_Ptr) { 285b6217f67STimm Baeder assert(P.getType()->isNullPtrType()); 286b6217f67STimm Baeder // Clang treats nullptr_t has having NO bits in its value 287b6217f67STimm Baeder // representation. So, we accept it here and leave its bits 288b6217f67STimm Baeder // uninitialized. 289b6217f67STimm Baeder return true; 290b6217f67STimm Baeder } 291ef2a104cSTimm Baeder 292b4150ed1STimm Baeder assert(P.isInitialized()); 29374393f3dSTimm Baeder auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes()); 2945b32c595STimm Baeder // Work around floating point types that contain unused padding bytes. 2955b32c595STimm Baeder // This is really just `long double` on x86, which is the only 2965b32c595STimm Baeder // fundamental type with padding bytes. 2975b32c595STimm Baeder if (T == PT_Float) { 298fb30208dSTimm Baeder const Floating &F = P.deref<Floating>(); 29912ca72baSTimm Bäder Bits NumBits = Bits( 30012ca72baSTimm Bäder llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics())); 30112ca72baSTimm Bäder assert(NumBits.isFullByte()); 30212ca72baSTimm Bäder assert(NumBits.getQuantity() <= FullBitWidth.getQuantity()); 30312ca72baSTimm Bäder F.bitcastToMemory(Buff.get()); 304*cfe26358STimm Baeder // Now, only (maybe) swap the actual size of the float, excluding 305*cfe26358STimm Baeder // the padding bits. 30612ca72baSTimm Bäder if (llvm::sys::IsBigEndianHost) 30712ca72baSTimm Bäder swapBytes(Buff.get(), NumBits.roundToBytes()); 3085b32c595STimm Baeder 3091fbbf4c4STimm Baeder Buffer.markInitialized(BitOffset, NumBits); 3105b32c595STimm Baeder } else { 31112ca72baSTimm Bäder BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); }); 31212ca72baSTimm Bäder 31312ca72baSTimm Bäder if (llvm::sys::IsBigEndianHost) 31412ca72baSTimm Bäder swapBytes(Buff.get(), FullBitWidth.roundToBytes()); 3151fbbf4c4STimm Baeder Buffer.markInitialized(BitOffset, BitWidth); 3165b32c595STimm Baeder } 317ef2a104cSTimm Baeder 31812ca72baSTimm Bäder Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness); 319ef2a104cSTimm Baeder return true; 320ef2a104cSTimm Baeder }); 321ef2a104cSTimm Baeder } 322ef2a104cSTimm Baeder 323ef2a104cSTimm Baeder bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 3241fbbf4c4STimm Baeder std::byte *Buff, Bits BitWidth, Bits FullBitWidth, 325ef2a104cSTimm Baeder bool &HasIndeterminateBits) { 326ef2a104cSTimm Baeder assert(Ptr.isLive()); 327ef2a104cSTimm Baeder assert(Ptr.isBlockPointer()); 328ef2a104cSTimm Baeder assert(Buff); 3291fbbf4c4STimm Baeder assert(BitWidth <= FullBitWidth); 3301fbbf4c4STimm Baeder assert(FullBitWidth.isFullByte()); 3311fbbf4c4STimm Baeder assert(BitWidth.isFullByte()); 332ef2a104cSTimm Baeder 3331fbbf4c4STimm Baeder BitcastBuffer Buffer(FullBitWidth); 3341fbbf4c4STimm Baeder size_t BuffSize = FullBitWidth.roundToBytes(); 335ef2a104cSTimm Baeder if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false)) 336ef2a104cSTimm Baeder return false; 337ef2a104cSTimm Baeder 338ef2a104cSTimm Baeder bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer, 339ef2a104cSTimm Baeder /*ReturnOnUninit=*/false); 3401fbbf4c4STimm Baeder HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth); 34112ca72baSTimm Bäder 34212ca72baSTimm Bäder const ASTContext &ASTCtx = S.getASTContext(); 34312ca72baSTimm Bäder Endian TargetEndianness = 34412ca72baSTimm Bäder ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 3451fbbf4c4STimm Baeder auto B = 3461fbbf4c4STimm Baeder Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness); 34712ca72baSTimm Bäder 34812ca72baSTimm Bäder std::memcpy(Buff, B.get(), BuffSize); 349ef2a104cSTimm Baeder 35088823d08STimm Baeder if (llvm::sys::IsBigEndianHost) 3511fbbf4c4STimm Baeder swapBytes(Buff, BitWidth.roundToBytes()); 35288823d08STimm Baeder 353ef2a104cSTimm Baeder return Success; 354ef2a104cSTimm Baeder } 3552588b8beSTimm Baeder bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, 3562588b8beSTimm Baeder const Pointer &FromPtr, Pointer &ToPtr) { 357abc27039STimm Baeder const ASTContext &ASTCtx = S.getASTContext(); 358abc27039STimm Baeder CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType()); 359abc27039STimm Baeder 360abc27039STimm Baeder return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity()); 361abc27039STimm Baeder } 362abc27039STimm Baeder 363abc27039STimm Baeder bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, 364abc27039STimm Baeder const Pointer &FromPtr, Pointer &ToPtr, 365abc27039STimm Baeder size_t Size) { 3662588b8beSTimm Baeder assert(FromPtr.isLive()); 3672588b8beSTimm Baeder assert(FromPtr.isBlockPointer()); 3682588b8beSTimm Baeder assert(ToPtr.isBlockPointer()); 3692588b8beSTimm Baeder 3702588b8beSTimm Baeder QualType FromType = FromPtr.getType(); 3712588b8beSTimm Baeder QualType ToType = ToPtr.getType(); 3722588b8beSTimm Baeder 3732588b8beSTimm Baeder if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true)) 3742588b8beSTimm Baeder return false; 375476b208eSTimm Baeder if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false)) 376476b208eSTimm Baeder return false; 3772588b8beSTimm Baeder 37812ca72baSTimm Bäder const ASTContext &ASTCtx = S.getASTContext(); 379abc27039STimm Baeder BitcastBuffer Buffer(Bytes(Size).toBits()); 3802588b8beSTimm Baeder readPointerToBuffer(S.getContext(), FromPtr, Buffer, 3812588b8beSTimm Baeder /*ReturnOnUninit=*/false); 3822588b8beSTimm Baeder 3832588b8beSTimm Baeder // Now read the values out of the buffer again and into ToPtr. 38412ca72baSTimm Bäder Endian TargetEndianness = 38512ca72baSTimm Bäder ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 3862588b8beSTimm Baeder bool Success = enumeratePointerFields( 38712ca72baSTimm Bäder ToPtr, S.getContext(), Buffer.size(), 38874393f3dSTimm Baeder [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, 38912ca72baSTimm Bäder bool PackedBools) -> bool { 390b4150ed1STimm Baeder QualType PtrType = P.getType(); 39112ca72baSTimm Bäder if (T == PT_Float) { 392b4150ed1STimm Baeder const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType); 39312ca72baSTimm Bäder Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics)); 39412ca72baSTimm Bäder assert(NumBits.isFullByte()); 39512ca72baSTimm Bäder assert(NumBits.getQuantity() <= FullBitWidth.getQuantity()); 39612ca72baSTimm Bäder auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth, 39712ca72baSTimm Bäder TargetEndianness); 3982588b8beSTimm Baeder 3992f13fbfcSTimm Baeder if (llvm::sys::IsBigEndianHost) 40012ca72baSTimm Bäder swapBytes(M.get(), NumBits.roundToBytes()); 4012f13fbfcSTimm Baeder 40212ca72baSTimm Bäder P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics); 4032f13fbfcSTimm Baeder P.initialize(); 4042f13fbfcSTimm Baeder return true; 4052f13fbfcSTimm Baeder } 4062f13fbfcSTimm Baeder 40712ca72baSTimm Bäder Bits BitWidth; 40812ca72baSTimm Bäder if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) 409*cfe26358STimm Baeder BitWidth = Bits(std::min(FD->getBitWidthValue(), 41012ca72baSTimm Bäder (unsigned)FullBitWidth.getQuantity())); 41112ca72baSTimm Bäder else if (T == PT_Bool && PackedBools) 41212ca72baSTimm Bäder BitWidth = Bits(1); 41312ca72baSTimm Bäder else 41412ca72baSTimm Bäder BitWidth = FullBitWidth; 41554db1622STimm Bäder 416b4150ed1STimm Baeder // If any of the bits are uninitialized, we need to abort unless the 417b4150ed1STimm Baeder // target type is std::byte or unsigned char. 418b4150ed1STimm Baeder bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth); 419b4150ed1STimm Baeder if (!Initialized) { 420b4150ed1STimm Baeder if (!PtrType->isStdByteType() && 421b4150ed1STimm Baeder !PtrType->isSpecificBuiltinType(BuiltinType::UChar) && 422b4150ed1STimm Baeder !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) { 423b4150ed1STimm Baeder const Expr *E = S.Current->getExpr(OpPC); 424b4150ed1STimm Baeder S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest) 425b4150ed1STimm Baeder << PtrType << S.getLangOpts().CharIsSigned 426b4150ed1STimm Baeder << E->getSourceRange(); 427b4150ed1STimm Baeder 428b4150ed1STimm Baeder return false; 429b4150ed1STimm Baeder } 430b4150ed1STimm Baeder return true; 431b4150ed1STimm Baeder } 432b4150ed1STimm Baeder 43312ca72baSTimm Bäder auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth, 43412ca72baSTimm Bäder TargetEndianness); 43554db1622STimm Bäder if (llvm::sys::IsBigEndianHost) 43612ca72baSTimm Bäder swapBytes(Memory.get(), FullBitWidth.roundToBytes()); 43754db1622STimm Bäder 43812ca72baSTimm Bäder BITCAST_TYPE_SWITCH_FIXED_SIZE(T, { 43912ca72baSTimm Bäder if (BitWidth.nonZero()) 44012ca72baSTimm Bäder P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth()) 44112ca72baSTimm Bäder .truncate(BitWidth.getQuantity()); 44212ca72baSTimm Bäder else 44312ca72baSTimm Bäder P.deref<T>() = T::zero(); 44454db1622STimm Bäder }); 44512ca72baSTimm Bäder P.initialize(); 4462588b8beSTimm Baeder return true; 4472588b8beSTimm Baeder }); 4482588b8beSTimm Baeder 4492588b8beSTimm Baeder return Success; 4502588b8beSTimm Baeder } 4511f2d9345STimm Baeder 4521f2d9345STimm Baeder bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC, 4531f2d9345STimm Baeder const Pointer &SrcPtr, const Pointer &DestPtr, 4541f2d9345STimm Baeder Bits Size) { 4551f2d9345STimm Baeder assert(SrcPtr.isBlockPointer()); 4561f2d9345STimm Baeder assert(DestPtr.isBlockPointer()); 4571f2d9345STimm Baeder 4581f2d9345STimm Baeder unsigned SrcStartOffset = SrcPtr.getByteOffset(); 4591f2d9345STimm Baeder unsigned DestStartOffset = DestPtr.getByteOffset(); 4601f2d9345STimm Baeder 4611f2d9345STimm Baeder enumeratePointerFields(SrcPtr, S.getContext(), Size, 4621f2d9345STimm Baeder [&](const Pointer &P, PrimType T, Bits BitOffset, 4631f2d9345STimm Baeder Bits FullBitWidth, bool PackedBools) -> bool { 4641f2d9345STimm Baeder unsigned SrcOffsetDiff = 4651f2d9345STimm Baeder P.getByteOffset() - SrcStartOffset; 4661f2d9345STimm Baeder 4671f2d9345STimm Baeder Pointer DestP = 4681f2d9345STimm Baeder Pointer(DestPtr.asBlockPointer().Pointee, 4691f2d9345STimm Baeder DestPtr.asBlockPointer().Base, 4701f2d9345STimm Baeder DestStartOffset + SrcOffsetDiff); 4711f2d9345STimm Baeder 4721f2d9345STimm Baeder TYPE_SWITCH(T, { 4731f2d9345STimm Baeder DestP.deref<T>() = P.deref<T>(); 4741f2d9345STimm Baeder DestP.initialize(); 4751f2d9345STimm Baeder }); 4761f2d9345STimm Baeder 4771f2d9345STimm Baeder return true; 4781f2d9345STimm Baeder }); 4791f2d9345STimm Baeder 4801f2d9345STimm Baeder return true; 4811f2d9345STimm Baeder } 482