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 bool clang::interp::readPointerToBuffer(const Context &Ctx, 263 const Pointer &FromPtr, 264 BitcastBuffer &Buffer, 265 bool ReturnOnUninit) { 266 const ASTContext &ASTCtx = Ctx.getASTContext(); 267 Endian TargetEndianness = 268 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 269 270 return enumeratePointerFields( 271 FromPtr, Ctx, Buffer.size(), 272 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, 273 bool PackedBools) -> bool { 274 Bits BitWidth = FullBitWidth; 275 276 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) 277 BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx), 278 (unsigned)FullBitWidth.getQuantity())); 279 else if (T == PT_Bool && PackedBools) 280 BitWidth = Bits(1); 281 282 if (BitWidth.isZero()) 283 return true; 284 285 // Bits will be left uninitialized and diagnosed when reading. 286 if (!P.isInitialized()) 287 return true; 288 289 if (T == PT_Ptr) { 290 assert(P.getType()->isNullPtrType()); 291 // Clang treats nullptr_t has having NO bits in its value 292 // representation. So, we accept it here and leave its bits 293 // uninitialized. 294 return true; 295 } 296 297 assert(P.isInitialized()); 298 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes()); 299 // Work around floating point types that contain unused padding bytes. 300 // This is really just `long double` on x86, which is the only 301 // fundamental type with padding bytes. 302 if (T == PT_Float) { 303 const Floating &F = P.deref<Floating>(); 304 Bits NumBits = Bits( 305 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics())); 306 assert(NumBits.isFullByte()); 307 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity()); 308 F.bitcastToMemory(Buff.get()); 309 // Now, only (maybe) swap the actual size of the float, excluding the 310 // padding bits. 311 if (llvm::sys::IsBigEndianHost) 312 swapBytes(Buff.get(), NumBits.roundToBytes()); 313 314 Buffer.markInitialized(BitOffset, NumBits); 315 } else { 316 BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); }); 317 318 if (llvm::sys::IsBigEndianHost) 319 swapBytes(Buff.get(), FullBitWidth.roundToBytes()); 320 Buffer.markInitialized(BitOffset, BitWidth); 321 } 322 323 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness); 324 return true; 325 }); 326 } 327 328 bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 329 std::byte *Buff, Bits BitWidth, Bits FullBitWidth, 330 bool &HasIndeterminateBits) { 331 assert(Ptr.isLive()); 332 assert(Ptr.isBlockPointer()); 333 assert(Buff); 334 assert(BitWidth <= FullBitWidth); 335 assert(FullBitWidth.isFullByte()); 336 assert(BitWidth.isFullByte()); 337 338 BitcastBuffer Buffer(FullBitWidth); 339 size_t BuffSize = FullBitWidth.roundToBytes(); 340 if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false)) 341 return false; 342 343 bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer, 344 /*ReturnOnUninit=*/false); 345 HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth); 346 347 const ASTContext &ASTCtx = S.getASTContext(); 348 Endian TargetEndianness = 349 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 350 auto B = 351 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness); 352 353 std::memcpy(Buff, B.get(), BuffSize); 354 355 if (llvm::sys::IsBigEndianHost) 356 swapBytes(Buff, BitWidth.roundToBytes()); 357 358 return Success; 359 } 360 bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, 361 const Pointer &FromPtr, Pointer &ToPtr) { 362 const ASTContext &ASTCtx = S.getASTContext(); 363 CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType()); 364 365 return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity()); 366 } 367 368 bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, 369 const Pointer &FromPtr, Pointer &ToPtr, 370 size_t Size) { 371 assert(FromPtr.isLive()); 372 assert(FromPtr.isBlockPointer()); 373 assert(ToPtr.isBlockPointer()); 374 375 QualType FromType = FromPtr.getType(); 376 QualType ToType = ToPtr.getType(); 377 378 if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true)) 379 return false; 380 if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false)) 381 return false; 382 383 const ASTContext &ASTCtx = S.getASTContext(); 384 BitcastBuffer Buffer(Bytes(Size).toBits()); 385 readPointerToBuffer(S.getContext(), FromPtr, Buffer, 386 /*ReturnOnUninit=*/false); 387 388 // Now read the values out of the buffer again and into ToPtr. 389 Endian TargetEndianness = 390 ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; 391 bool Success = enumeratePointerFields( 392 ToPtr, S.getContext(), Buffer.size(), 393 [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, 394 bool PackedBools) -> bool { 395 QualType PtrType = P.getType(); 396 if (T == PT_Float) { 397 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType); 398 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics)); 399 assert(NumBits.isFullByte()); 400 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity()); 401 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth, 402 TargetEndianness); 403 404 if (llvm::sys::IsBigEndianHost) 405 swapBytes(M.get(), NumBits.roundToBytes()); 406 407 P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics); 408 P.initialize(); 409 return true; 410 } 411 412 Bits BitWidth; 413 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) 414 BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx), 415 (unsigned)FullBitWidth.getQuantity())); 416 else if (T == PT_Bool && PackedBools) 417 BitWidth = Bits(1); 418 else 419 BitWidth = FullBitWidth; 420 421 // If any of the bits are uninitialized, we need to abort unless the 422 // target type is std::byte or unsigned char. 423 bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth); 424 if (!Initialized) { 425 if (!PtrType->isStdByteType() && 426 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) && 427 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) { 428 const Expr *E = S.Current->getExpr(OpPC); 429 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest) 430 << PtrType << S.getLangOpts().CharIsSigned 431 << E->getSourceRange(); 432 433 return false; 434 } 435 return true; 436 } 437 438 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth, 439 TargetEndianness); 440 if (llvm::sys::IsBigEndianHost) 441 swapBytes(Memory.get(), FullBitWidth.roundToBytes()); 442 443 BITCAST_TYPE_SWITCH_FIXED_SIZE(T, { 444 if (BitWidth.nonZero()) 445 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth()) 446 .truncate(BitWidth.getQuantity()); 447 else 448 P.deref<T>() = T::zero(); 449 }); 450 P.initialize(); 451 return true; 452 }); 453 454 return Success; 455 } 456