1 //===--- Program.cpp - Bytecode for the constexpr VM ------------*- 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 9 #include "Program.h" 10 #include "Context.h" 11 #include "Function.h" 12 #include "Integral.h" 13 #include "PrimType.h" 14 #include "clang/AST/Decl.h" 15 #include "clang/AST/DeclCXX.h" 16 17 using namespace clang; 18 using namespace clang::interp; 19 20 unsigned Program::getOrCreateNativePointer(const void *Ptr) { 21 auto It = NativePointerIndices.find(Ptr); 22 if (It != NativePointerIndices.end()) 23 return It->second; 24 25 unsigned Idx = NativePointers.size(); 26 NativePointers.push_back(Ptr); 27 NativePointerIndices[Ptr] = Idx; 28 return Idx; 29 } 30 31 const void *Program::getNativePointer(unsigned Idx) { 32 return NativePointers[Idx]; 33 } 34 35 unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { 36 const size_t CharWidth = S->getCharByteWidth(); 37 const size_t BitWidth = CharWidth * Ctx.getCharBit(); 38 39 PrimType CharType; 40 switch (CharWidth) { 41 case 1: 42 CharType = PT_Sint8; 43 break; 44 case 2: 45 CharType = PT_Uint16; 46 break; 47 case 4: 48 CharType = PT_Uint32; 49 break; 50 default: 51 llvm_unreachable("unsupported character width"); 52 } 53 54 if (!Base) 55 Base = S; 56 57 // Create a descriptor for the string. 58 Descriptor *Desc = allocateDescriptor(Base, CharType, Descriptor::GlobalMD, 59 S->getLength() + 1, 60 /*isConst=*/true, 61 /*isTemporary=*/false, 62 /*isMutable=*/false); 63 64 // Allocate storage for the string. 65 // The byte length does not include the null terminator. 66 unsigned I = Globals.size(); 67 unsigned Sz = Desc->getAllocSize(); 68 auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true, 69 /*isExtern=*/false); 70 G->block()->invokeCtor(); 71 72 new (G->block()->rawData()) InlineDescriptor(Desc); 73 Globals.push_back(G); 74 75 // Construct the string in storage. 76 const Pointer Ptr(G->block()); 77 for (unsigned I = 0, N = S->getLength(); I <= N; ++I) { 78 Pointer Field = Ptr.atIndex(I).narrow(); 79 const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I); 80 switch (CharType) { 81 case PT_Sint8: { 82 using T = PrimConv<PT_Sint8>::T; 83 Field.deref<T>() = T::from(CodePoint, BitWidth); 84 Field.initialize(); 85 break; 86 } 87 case PT_Uint16: { 88 using T = PrimConv<PT_Uint16>::T; 89 Field.deref<T>() = T::from(CodePoint, BitWidth); 90 Field.initialize(); 91 break; 92 } 93 case PT_Uint32: { 94 using T = PrimConv<PT_Uint32>::T; 95 Field.deref<T>() = T::from(CodePoint, BitWidth); 96 Field.initialize(); 97 break; 98 } 99 default: 100 llvm_unreachable("unsupported character type"); 101 } 102 } 103 return I; 104 } 105 106 Pointer Program::getPtrGlobal(unsigned Idx) const { 107 assert(Idx < Globals.size()); 108 return Pointer(Globals[Idx]->block()); 109 } 110 111 std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) { 112 if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end()) 113 return It->second; 114 115 // Find any previous declarations which were already evaluated. 116 std::optional<unsigned> Index; 117 for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) { 118 if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) { 119 Index = It->second; 120 break; 121 } 122 } 123 124 // Map the decl to the existing index. 125 if (Index) 126 GlobalIndices[VD] = *Index; 127 128 return std::nullopt; 129 } 130 131 std::optional<unsigned> Program::getGlobal(const Expr *E) { 132 if (auto It = GlobalIndices.find(E); It != GlobalIndices.end()) 133 return It->second; 134 return std::nullopt; 135 } 136 137 std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD, 138 const Expr *Init) { 139 if (auto Idx = getGlobal(VD)) 140 return Idx; 141 142 if (auto Idx = createGlobal(VD, Init)) { 143 GlobalIndices[VD] = *Idx; 144 return Idx; 145 } 146 return std::nullopt; 147 } 148 149 unsigned Program::getOrCreateDummy(const DeclTy &D) { 150 assert(D); 151 // Dedup blocks since they are immutable and pointers cannot be compared. 152 if (auto It = DummyVariables.find(D.getOpaqueValue()); 153 It != DummyVariables.end()) 154 return It->second; 155 156 QualType QT; 157 bool IsWeak = false; 158 if (const auto *E = dyn_cast<const Expr *>(D)) { 159 QT = E->getType(); 160 } else { 161 const ValueDecl *VD = cast<ValueDecl>(cast<const Decl *>(D)); 162 IsWeak = VD->isWeak(); 163 QT = VD->getType(); 164 if (const auto *RT = QT->getAs<ReferenceType>()) 165 QT = RT->getPointeeType(); 166 } 167 assert(!QT.isNull()); 168 169 Descriptor *Desc; 170 if (std::optional<PrimType> T = Ctx.classify(QT)) 171 Desc = createDescriptor(D, *T, std::nullopt, /*IsTemporary=*/true, 172 /*IsMutable=*/false); 173 else 174 Desc = createDescriptor(D, QT.getTypePtr(), std::nullopt, 175 /*IsTemporary=*/true, /*IsMutable=*/false); 176 if (!Desc) 177 Desc = allocateDescriptor(D); 178 179 assert(Desc); 180 Desc->makeDummy(); 181 182 assert(Desc->isDummy()); 183 184 // Allocate a block for storage. 185 unsigned I = Globals.size(); 186 187 auto *G = new (Allocator, Desc->getAllocSize()) 188 Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true, 189 /*IsExtern=*/false, IsWeak); 190 G->block()->invokeCtor(); 191 192 Globals.push_back(G); 193 DummyVariables[D.getOpaqueValue()] = I; 194 return I; 195 } 196 197 std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, 198 const Expr *Init) { 199 bool IsStatic, IsExtern; 200 bool IsWeak = VD->isWeak(); 201 if (const auto *Var = dyn_cast<VarDecl>(VD)) { 202 IsStatic = Context::shouldBeGloballyIndexed(VD); 203 IsExtern = Var->hasExternalStorage(); 204 } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl, 205 TemplateParamObjectDecl>(VD)) { 206 IsStatic = true; 207 IsExtern = false; 208 } else { 209 IsStatic = false; 210 IsExtern = true; 211 } 212 213 // Register all previous declarations as well. For extern blocks, just replace 214 // the index with the new variable. 215 if (auto Idx = 216 createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init)) { 217 for (const Decl *P = VD; P; P = P->getPreviousDecl()) { 218 if (P != VD) { 219 unsigned PIdx = GlobalIndices[P]; 220 if (Globals[PIdx]->block()->isExtern()) 221 Globals[PIdx] = Globals[*Idx]; 222 } 223 GlobalIndices[P] = *Idx; 224 } 225 return *Idx; 226 } 227 return std::nullopt; 228 } 229 230 std::optional<unsigned> Program::createGlobal(const Expr *E) { 231 if (auto Idx = getGlobal(E)) 232 return Idx; 233 if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true, 234 /*isExtern=*/false, /*IsWeak=*/false)) { 235 GlobalIndices[E] = *Idx; 236 return *Idx; 237 } 238 return std::nullopt; 239 } 240 241 std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, 242 bool IsStatic, bool IsExtern, 243 bool IsWeak, const Expr *Init) { 244 // Create a descriptor for the global. 245 Descriptor *Desc; 246 const bool IsConst = Ty.isConstQualified(); 247 const bool IsTemporary = D.dyn_cast<const Expr *>(); 248 if (std::optional<PrimType> T = Ctx.classify(Ty)) 249 Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary); 250 else 251 Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst, 252 IsTemporary); 253 254 if (!Desc) 255 return std::nullopt; 256 257 // Allocate a block for storage. 258 unsigned I = Globals.size(); 259 260 auto *G = new (Allocator, Desc->getAllocSize()) Global( 261 Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern, IsWeak); 262 G->block()->invokeCtor(); 263 264 // Initialize InlineDescriptor fields. 265 auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor(); 266 if (!Init) 267 GD->InitState = GlobalInitState::NoInitializer; 268 Globals.push_back(G); 269 270 return I; 271 } 272 273 Function *Program::getFunction(const FunctionDecl *F) { 274 F = F->getCanonicalDecl(); 275 assert(F); 276 auto It = Funcs.find(F); 277 return It == Funcs.end() ? nullptr : It->second.get(); 278 } 279 280 Record *Program::getOrCreateRecord(const RecordDecl *RD) { 281 // Use the actual definition as a key. 282 RD = RD->getDefinition(); 283 if (!RD) 284 return nullptr; 285 286 if (!RD->isCompleteDefinition()) 287 return nullptr; 288 289 // Return an existing record if available. Otherwise, we insert nullptr now 290 // and replace that later, so recursive calls to this function with the same 291 // RecordDecl don't run into infinite recursion. 292 auto [It, Inserted] = Records.try_emplace(RD); 293 if (!Inserted) 294 return It->second; 295 296 // Number of bytes required by fields and base classes. 297 unsigned BaseSize = 0; 298 // Number of bytes required by virtual base. 299 unsigned VirtSize = 0; 300 301 // Helper to get a base descriptor. 302 auto GetBaseDesc = [this](const RecordDecl *BD, 303 const Record *BR) -> const Descriptor * { 304 if (!BR) 305 return nullptr; 306 return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false, 307 /*isTemporary=*/false, 308 /*isMutable=*/false); 309 }; 310 311 // Reserve space for base classes. 312 Record::BaseList Bases; 313 Record::VirtualBaseList VirtBases; 314 if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) { 315 for (const CXXBaseSpecifier &Spec : CD->bases()) { 316 if (Spec.isVirtual()) 317 continue; 318 319 // In error cases, the base might not be a RecordType. 320 const auto *RT = Spec.getType()->getAs<RecordType>(); 321 if (!RT) 322 return nullptr; 323 const RecordDecl *BD = RT->getDecl(); 324 const Record *BR = getOrCreateRecord(BD); 325 326 const Descriptor *Desc = GetBaseDesc(BD, BR); 327 if (!Desc) 328 return nullptr; 329 330 BaseSize += align(sizeof(InlineDescriptor)); 331 Bases.push_back({BD, BaseSize, Desc, BR}); 332 BaseSize += align(BR->getSize()); 333 } 334 335 for (const CXXBaseSpecifier &Spec : CD->vbases()) { 336 const auto *RT = Spec.getType()->getAs<RecordType>(); 337 if (!RT) 338 return nullptr; 339 340 const RecordDecl *BD = RT->getDecl(); 341 const Record *BR = getOrCreateRecord(BD); 342 343 const Descriptor *Desc = GetBaseDesc(BD, BR); 344 if (!Desc) 345 return nullptr; 346 347 VirtSize += align(sizeof(InlineDescriptor)); 348 VirtBases.push_back({BD, VirtSize, Desc, BR}); 349 VirtSize += align(BR->getSize()); 350 } 351 } 352 353 // Reserve space for fields. 354 Record::FieldList Fields; 355 for (const FieldDecl *FD : RD->fields()) { 356 FD = FD->getFirstDecl(); 357 // Note that we DO create fields and descriptors 358 // for unnamed bitfields here, even though we later ignore 359 // them everywhere. That's so the FieldDecl's getFieldIndex() matches. 360 361 // Reserve space for the field's descriptor and the offset. 362 BaseSize += align(sizeof(InlineDescriptor)); 363 364 // Classify the field and add its metadata. 365 QualType FT = FD->getType(); 366 const bool IsConst = FT.isConstQualified(); 367 const bool IsMutable = FD->isMutable(); 368 const Descriptor *Desc; 369 if (std::optional<PrimType> T = Ctx.classify(FT)) { 370 Desc = createDescriptor(FD, *T, std::nullopt, IsConst, 371 /*isTemporary=*/false, IsMutable); 372 } else { 373 Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst, 374 /*isTemporary=*/false, IsMutable); 375 } 376 if (!Desc) 377 return nullptr; 378 Fields.push_back({FD, BaseSize, Desc}); 379 BaseSize += align(Desc->getAllocSize()); 380 } 381 382 Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), 383 std::move(VirtBases), VirtSize, BaseSize); 384 Records[RD] = R; 385 return R; 386 } 387 388 Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, 389 Descriptor::MetadataSize MDSize, 390 bool IsConst, bool IsTemporary, 391 bool IsMutable, const Expr *Init) { 392 393 // Classes and structures. 394 if (const auto *RT = Ty->getAs<RecordType>()) { 395 if (const auto *Record = getOrCreateRecord(RT->getDecl())) 396 return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, 397 IsMutable); 398 } 399 400 // Arrays. 401 if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) { 402 QualType ElemTy = ArrayType->getElementType(); 403 // Array of well-known bounds. 404 if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) { 405 size_t NumElems = CAT->getZExtSize(); 406 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 407 // Arrays of primitives. 408 unsigned ElemSize = primSize(*T); 409 if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { 410 return {}; 411 } 412 return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, 413 IsMutable); 414 } else { 415 // Arrays of composites. In this case, the array is a list of pointers, 416 // followed by the actual elements. 417 const Descriptor *ElemDesc = createDescriptor( 418 D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); 419 if (!ElemDesc) 420 return nullptr; 421 unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 422 if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) 423 return {}; 424 return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst, 425 IsTemporary, IsMutable); 426 } 427 } 428 429 // Array of unknown bounds - cannot be accessed and pointer arithmetic 430 // is forbidden on pointers to such objects. 431 if (isa<IncompleteArrayType>(ArrayType) || 432 isa<VariableArrayType>(ArrayType)) { 433 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 434 return allocateDescriptor(D, *T, MDSize, IsTemporary, 435 Descriptor::UnknownSize{}); 436 } else { 437 const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), 438 MDSize, IsConst, IsTemporary); 439 if (!Desc) 440 return nullptr; 441 return allocateDescriptor(D, Desc, MDSize, IsTemporary, 442 Descriptor::UnknownSize{}); 443 } 444 } 445 } 446 447 // Atomic types. 448 if (const auto *AT = Ty->getAs<AtomicType>()) { 449 const Type *InnerTy = AT->getValueType().getTypePtr(); 450 return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary, 451 IsMutable); 452 } 453 454 // Complex types - represented as arrays of elements. 455 if (const auto *CT = Ty->getAs<ComplexType>()) { 456 std::optional<PrimType> ElemTy = Ctx.classify(CT->getElementType()); 457 if (!ElemTy) 458 return nullptr; 459 460 return allocateDescriptor(D, *ElemTy, MDSize, 2, IsConst, IsTemporary, 461 IsMutable); 462 } 463 464 // Same with vector types. 465 if (const auto *VT = Ty->getAs<VectorType>()) { 466 std::optional<PrimType> ElemTy = Ctx.classify(VT->getElementType()); 467 if (!ElemTy) 468 return nullptr; 469 470 return allocateDescriptor(D, *ElemTy, MDSize, VT->getNumElements(), IsConst, 471 IsTemporary, IsMutable); 472 } 473 474 return nullptr; 475 } 476