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