xref: /llvm-project/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp (revision cfe26358e3051755961fb1f3b46328dc2c326895)
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