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 //===----------------------------------------------------------------------===// 8 #include "InterpBuiltinBitCast.h" 9 #include "BitcastBuffer.h" 10 #include "Boolean.h" 11 #include "Context.h" 12 #include "Floating.h" 13 #include "Integral.h" 14 #include "InterpState.h" 15 #include "MemberPointer.h" 16 #include "Pointer.h" 17 #include "Record.h" 18 #include "clang/AST/ASTContext.h" 19 #include "clang/AST/RecordLayout.h" 20 #include "clang/Basic/TargetInfo.h" 21 22 using namespace clang; 23 using namespace clang::interp; 24 25 /// Implement __builtin_bit_cast and related operations. 26 /// Since our internal representation for data is more complex than 27 /// something we can simply memcpy or memcmp, we first bitcast all the data 28 /// into a buffer, which we then later use to copy the data into the target. 29 30 // TODO: 31 // - Try to minimize heap allocations. 32 // - Optimize the common case of only pushing and pulling full 33 // bytes to/from the buffer. 34 35 /// Used to iterate over pointer fields. 36 using DataFunc = 37 llvm::function_ref<bool(const Pointer &P, PrimType Ty, Bits BitOffset, 38 Bits FullBitWidth, bool PackedBools)>; 39 40 #define BITCAST_TYPE_SWITCH(Expr, B) \ 41 do { \ 42 switch (Expr) { \ 43 TYPE_SWITCH_CASE(PT_Sint8, B) \ 44 TYPE_SWITCH_CASE(PT_Uint8, B) \ 45 TYPE_SWITCH_CASE(PT_Sint16, B) \ 46 TYPE_SWITCH_CASE(PT_Uint16, B) \ 47 TYPE_SWITCH_CASE(PT_Sint32, B) \ 48 TYPE_SWITCH_CASE(PT_Uint32, B) \ 49 TYPE_SWITCH_CASE(PT_Sint64, B) \ 50 TYPE_SWITCH_CASE(PT_Uint64, B) \ 51 TYPE_SWITCH_CASE(PT_IntAP, B) \ 52 TYPE_SWITCH_CASE(PT_IntAPS, B) \ 53 TYPE_SWITCH_CASE(PT_Bool, B) \ 54 default: \ 55 llvm_unreachable("Unhandled bitcast type"); \ 56 } \ 57 } while (0) 58 59 #define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \ 60 do { \ 61 switch (Expr) { \ 62 TYPE_SWITCH_CASE(PT_Sint8, B) \ 63 TYPE_SWITCH_CASE(PT_Uint8, B) \ 64 TYPE_SWITCH_CASE(PT_Sint16, B) \ 65 TYPE_SWITCH_CASE(PT_Uint16, B) \ 66 TYPE_SWITCH_CASE(PT_Sint32, B) \ 67 TYPE_SWITCH_CASE(PT_Uint32, B) \ 68 TYPE_SWITCH_CASE(PT_Sint64, B) \ 69 TYPE_SWITCH_CASE(PT_Uint64, B) \ 70 TYPE_SWITCH_CASE(PT_Bool, B) \ 71 default: \ 72 llvm_unreachable("Unhandled bitcast type"); \ 73 } \ 74 } while (0) 75 76 static void swapBytes(std::byte *M, size_t N) { 77 for (size_t I = 0; I != (N / 2); ++I) 78 std::swap(M[I], M[N - 1 - I]); 79 } 80 81 /// We use this to recursively iterate over all fields and elements of a pointer 82 /// and extract relevant data for a bitcast. 83 static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, 84 Bits BitsToRead, DataFunc F) { 85 const Descriptor *FieldDesc = P.getFieldDesc(); 86 assert(FieldDesc); 87 88 // Primitives. 89 if (FieldDesc->isPrimitive()) { 90 Bits FullBitWidth = 91 Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType())); 92 return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth, 93 /*PackedBools=*/false); 94 } 95 96 // Primitive arrays. 97 if (FieldDesc->isPrimitiveArray()) { 98 QualType ElemType = FieldDesc->getElemQualType(); 99 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); 100 PrimType ElemT = *Ctx.classify(ElemType); 101 // Special case, since the bools here are packed. 102 bool PackedBools = FieldDesc->getType()->isExtVectorBoolType(); 103 unsigned NumElems = FieldDesc->getNumElems(); 104 bool Ok = true; 105 for (unsigned I = P.getIndex(); I != NumElems; ++I) { 106 Ok = Ok && F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools); 107 Offset += PackedBools ? Bits(1) : ElemSize; 108 if (Offset >= BitsToRead) 109 break; 110 } 111 return Ok; 112 } 113 114 // Composite arrays. 115 if (FieldDesc->isCompositeArray()) { 116 QualType ElemType = FieldDesc->getElemQualType(); 117 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); 118 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) { 119 enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); 120 Offset += ElemSize; 121 if (Offset >= BitsToRead) 122 break; 123 } 124 return true; 125 } 126 127 // Records. 128 if (FieldDesc->isRecord()) { 129 const Record *R = FieldDesc->ElemRecord; 130 const ASTRecordLayout &Layout = 131 Ctx.getASTContext().getASTRecordLayout(R->getDecl()); 132 bool Ok = true; 133 134 for (const Record::Field &Fi : R->fields()) { 135 if (Fi.isUnnamedBitField()) 136 continue; 137 Pointer Elem = P.atField(Fi.Offset); 138 Bits BitOffset = 139 Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex())); 140 Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F); 141 } 142 for (const Record::Base &B : R->bases()) { 143 Pointer Elem = P.atField(B.Offset); 144 CharUnits ByteOffset = 145 Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl)); 146 Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset)); 147 Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F); 148 // FIXME: We should only (need to) do this when bitcasting OUT of the 149 // buffer, not when copying data into it. 150 if (Ok) 151 Elem.initialize(); 152 } 153 154 return Ok; 155 } 156 157 llvm_unreachable("Unhandled data type"); 158 } 159 160 static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, 161 Bits BitsToRead, DataFunc F) { 162 return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F); 163 } 164 165 // This function is constexpr if and only if To, From, and the types of 166 // all subobjects of To and From are types T such that... 167 // (3.1) - is_union_v<T> is false; 168 // (3.2) - is_pointer_v<T> is false; 169 // (3.3) - is_member_pointer_v<T> is false; 170 // (3.4) - is_volatile_v<T> is false; and 171 // (3.5) - T has no non-static data members of reference type 172 // 173 // NOTE: This is a version of checkBitCastConstexprEligibilityType() in 174 // ExprConstant.cpp. 175 static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, 176 bool IsToType) { 177 enum { 178 E_Union = 0, 179 E_Pointer, 180 E_MemberPointer, 181 E_Volatile, 182 E_Reference, 183 }; 184 enum { C_Member, C_Base }; 185 186 auto diag = [&](int Reason) -> bool { 187 const Expr *E = S.Current->getExpr(OpPC); 188 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type) 189 << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason 190 << E->getSourceRange(); 191 return false; 192 }; 193 auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) { 194 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype) 195 << NoteType << Construct << T.getUnqualifiedType() << NoteRange; 196 return false; 197 }; 198 199 T = T.getCanonicalType(); 200 201 if (T->isUnionType()) 202 return diag(E_Union); 203 if (T->isPointerType()) 204 return diag(E_Pointer); 205 if (T->isMemberPointerType()) 206 return diag(E_MemberPointer); 207 if (T.isVolatileQualified()) 208 return diag(E_Volatile); 209 210 if (const RecordDecl *RD = T->getAsRecordDecl()) { 211 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { 212 for (const CXXBaseSpecifier &BS : CXXRD->bases()) { 213 if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType)) 214 return note(C_Base, BS.getType(), BS.getBeginLoc()); 215 } 216 } 217 for (const FieldDecl *FD : RD->fields()) { 218 if (FD->getType()->isReferenceType()) 219 return diag(E_Reference); 220 if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType)) 221 return note(C_Member, FD->getType(), FD->getSourceRange()); 222 } 223 } 224 225 if (T->isArrayType() && 226 !CheckBitcastType(S, OpPC, S.getASTContext().getBaseElementType(T), 227 IsToType)) 228 return false; 229 230 if (const auto *VT = T->getAs<VectorType>()) { 231 const ASTContext &ASTCtx = S.getASTContext(); 232 QualType EltTy = VT->getElementType(); 233 unsigned NElts = VT->getNumElements(); 234 unsigned EltSize = 235 VT->isExtVectorBoolType() ? 1 : ASTCtx.getTypeSize(EltTy); 236 237 if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) { 238 // The vector's size in bits is not a multiple of the target's byte size, 239 // so its layout is unspecified. For now, we'll simply treat these cases 240 // as unsupported (this should only be possible with OpenCL bool vectors 241 // whose element count isn't a multiple of the byte size). 242 const Expr *E = S.Current->getExpr(OpPC); 243 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector) 244 << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth(); 245 return false; 246 } 247 248 if (EltTy->isRealFloatingType() && 249 &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) { 250 // The layout for x86_fp80 vectors seems to be handled very inconsistently 251 // by both clang and LLVM, so for now we won't allow bit_casts involving 252 // it in a constexpr context. 253 const Expr *E = S.Current->getExpr(OpPC); 254 S.FFDiag(E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy; 255 return false; 256 } 257 } 258 259 return true; 260 } 261 262 static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, 263 BitcastBuffer &Buffer, bool ReturnOnUninit) { 264 const ASTContext &ASTCtx = Ctx.getASTContext(); 265 Endian TargetEndianness = 266 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 267 268 return enumeratePointerFields( 269 FromPtr, Ctx, Buffer.size(), 270 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, 271 bool PackedBools) -> bool { 272 Bits BitWidth = FullBitWidth; 273 274 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) 275 BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx), 276 (unsigned)FullBitWidth.getQuantity())); 277 else if (T == PT_Bool && PackedBools) 278 BitWidth = Bits(1); 279 280 if (BitWidth.isZero()) 281 return true; 282 283 // Bits will be left uninitialized and diagnosed when reading. 284 if (!P.isInitialized()) 285 return true; 286 287 if (T == PT_Ptr) { 288 assert(P.getType()->isNullPtrType()); 289 // Clang treats nullptr_t has having NO bits in its value 290 // representation. So, we accept it here and leave its bits 291 // uninitialized. 292 return true; 293 } 294 295 assert(P.isInitialized()); 296 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes()); 297 // Work around floating point types that contain unused padding bytes. 298 // This is really just `long double` on x86, which is the only 299 // fundamental type with padding bytes. 300 if (T == PT_Float) { 301 const Floating &F = P.deref<Floating>(); 302 Bits NumBits = Bits( 303 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics())); 304 assert(NumBits.isFullByte()); 305 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity()); 306 F.bitcastToMemory(Buff.get()); 307 // Now, only (maybe) swap the actual size of the float, excluding the 308 // padding bits. 309 if (llvm::sys::IsBigEndianHost) 310 swapBytes(Buff.get(), NumBits.roundToBytes()); 311 312 Buffer.markInitialized(BitOffset, NumBits); 313 } else { 314 BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); }); 315 316 if (llvm::sys::IsBigEndianHost) 317 swapBytes(Buff.get(), FullBitWidth.roundToBytes()); 318 Buffer.markInitialized(BitOffset, BitWidth); 319 } 320 321 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness); 322 return true; 323 }); 324 } 325 326 bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 327 std::byte *Buff, Bits BitWidth, Bits FullBitWidth, 328 bool &HasIndeterminateBits) { 329 assert(Ptr.isLive()); 330 assert(Ptr.isBlockPointer()); 331 assert(Buff); 332 assert(BitWidth <= FullBitWidth); 333 assert(FullBitWidth.isFullByte()); 334 assert(BitWidth.isFullByte()); 335 336 BitcastBuffer Buffer(FullBitWidth); 337 size_t BuffSize = FullBitWidth.roundToBytes(); 338 if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false)) 339 return false; 340 341 bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer, 342 /*ReturnOnUninit=*/false); 343 HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth); 344 345 const ASTContext &ASTCtx = S.getASTContext(); 346 Endian TargetEndianness = 347 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 348 auto B = 349 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness); 350 351 std::memcpy(Buff, B.get(), BuffSize); 352 353 if (llvm::sys::IsBigEndianHost) 354 swapBytes(Buff, BitWidth.roundToBytes()); 355 356 return Success; 357 } 358 bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, 359 const Pointer &FromPtr, Pointer &ToPtr) { 360 const ASTContext &ASTCtx = S.getASTContext(); 361 CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType()); 362 363 return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity()); 364 } 365 366 bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, 367 const Pointer &FromPtr, Pointer &ToPtr, 368 size_t Size) { 369 assert(FromPtr.isLive()); 370 assert(FromPtr.isBlockPointer()); 371 assert(ToPtr.isBlockPointer()); 372 373 QualType FromType = FromPtr.getType(); 374 QualType ToType = ToPtr.getType(); 375 376 if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true)) 377 return false; 378 if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false)) 379 return false; 380 381 const ASTContext &ASTCtx = S.getASTContext(); 382 BitcastBuffer Buffer(Bytes(Size).toBits()); 383 readPointerToBuffer(S.getContext(), FromPtr, Buffer, 384 /*ReturnOnUninit=*/false); 385 386 // Now read the values out of the buffer again and into ToPtr. 387 Endian TargetEndianness = 388 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 389 bool Success = enumeratePointerFields( 390 ToPtr, S.getContext(), Buffer.size(), 391 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, 392 bool PackedBools) -> bool { 393 QualType PtrType = P.getType(); 394 if (T == PT_Float) { 395 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType); 396 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics)); 397 assert(NumBits.isFullByte()); 398 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity()); 399 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth, 400 TargetEndianness); 401 402 if (llvm::sys::IsBigEndianHost) 403 swapBytes(M.get(), NumBits.roundToBytes()); 404 405 P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics); 406 P.initialize(); 407 return true; 408 } 409 410 Bits BitWidth; 411 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) 412 BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx), 413 (unsigned)FullBitWidth.getQuantity())); 414 else if (T == PT_Bool && PackedBools) 415 BitWidth = Bits(1); 416 else 417 BitWidth = FullBitWidth; 418 419 // If any of the bits are uninitialized, we need to abort unless the 420 // target type is std::byte or unsigned char. 421 bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth); 422 if (!Initialized) { 423 if (!PtrType->isStdByteType() && 424 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) && 425 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) { 426 const Expr *E = S.Current->getExpr(OpPC); 427 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest) 428 << PtrType << S.getLangOpts().CharIsSigned 429 << E->getSourceRange(); 430 431 return false; 432 } 433 return true; 434 } 435 436 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth, 437 TargetEndianness); 438 if (llvm::sys::IsBigEndianHost) 439 swapBytes(Memory.get(), FullBitWidth.roundToBytes()); 440 441 BITCAST_TYPE_SWITCH_FIXED_SIZE(T, { 442 if (BitWidth.nonZero()) 443 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth()) 444 .truncate(BitWidth.getQuantity()); 445 else 446 P.deref<T>() = T::zero(); 447 }); 448 P.initialize(); 449 return true; 450 }); 451 452 return Success; 453 } 454