1a7dea167SDimitry Andric //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "Program.h" 10a7dea167SDimitry Andric #include "ByteCodeStmtGen.h" 11a7dea167SDimitry Andric #include "Context.h" 12a7dea167SDimitry Andric #include "Function.h" 1306c3fb27SDimitry Andric #include "Integral.h" 14a7dea167SDimitry Andric #include "Opcode.h" 15a7dea167SDimitry Andric #include "PrimType.h" 16a7dea167SDimitry Andric #include "clang/AST/Decl.h" 17a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 18a7dea167SDimitry Andric 19a7dea167SDimitry Andric using namespace clang; 20a7dea167SDimitry Andric using namespace clang::interp; 21a7dea167SDimitry Andric 22349cc55cSDimitry Andric unsigned Program::getOrCreateNativePointer(const void *Ptr) { 23349cc55cSDimitry Andric auto It = NativePointerIndices.find(Ptr); 24349cc55cSDimitry Andric if (It != NativePointerIndices.end()) 25349cc55cSDimitry Andric return It->second; 26349cc55cSDimitry Andric 27349cc55cSDimitry Andric unsigned Idx = NativePointers.size(); 28349cc55cSDimitry Andric NativePointers.push_back(Ptr); 29349cc55cSDimitry Andric NativePointerIndices[Ptr] = Idx; 30349cc55cSDimitry Andric return Idx; 31349cc55cSDimitry Andric } 32349cc55cSDimitry Andric 33349cc55cSDimitry Andric const void *Program::getNativePointer(unsigned Idx) { 34349cc55cSDimitry Andric return NativePointers[Idx]; 35349cc55cSDimitry Andric } 36349cc55cSDimitry Andric 37a7dea167SDimitry Andric unsigned Program::createGlobalString(const StringLiteral *S) { 38a7dea167SDimitry Andric const size_t CharWidth = S->getCharByteWidth(); 39a7dea167SDimitry Andric const size_t BitWidth = CharWidth * Ctx.getCharBit(); 40a7dea167SDimitry Andric 41a7dea167SDimitry Andric PrimType CharType; 42a7dea167SDimitry Andric switch (CharWidth) { 43a7dea167SDimitry Andric case 1: 44a7dea167SDimitry Andric CharType = PT_Sint8; 45a7dea167SDimitry Andric break; 46a7dea167SDimitry Andric case 2: 47a7dea167SDimitry Andric CharType = PT_Uint16; 48a7dea167SDimitry Andric break; 49a7dea167SDimitry Andric case 4: 50a7dea167SDimitry Andric CharType = PT_Uint32; 51a7dea167SDimitry Andric break; 52a7dea167SDimitry Andric default: 53a7dea167SDimitry Andric llvm_unreachable("unsupported character width"); 54a7dea167SDimitry Andric } 55a7dea167SDimitry Andric 56a7dea167SDimitry Andric // Create a descriptor for the string. 57bdd1243dSDimitry Andric Descriptor *Desc = 58bdd1243dSDimitry Andric allocateDescriptor(S, CharType, std::nullopt, S->getLength() + 1, 59a7dea167SDimitry Andric /*isConst=*/true, 60a7dea167SDimitry Andric /*isTemporary=*/false, 61a7dea167SDimitry Andric /*isMutable=*/false); 62a7dea167SDimitry Andric 63a7dea167SDimitry Andric // Allocate storage for the string. 64a7dea167SDimitry Andric // The byte length does not include the null terminator. 65a7dea167SDimitry Andric unsigned I = Globals.size(); 66a7dea167SDimitry Andric unsigned Sz = Desc->getAllocSize(); 67a7dea167SDimitry Andric auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true, 68a7dea167SDimitry Andric /*isExtern=*/false); 69bdd1243dSDimitry Andric G->block()->invokeCtor(); 70a7dea167SDimitry Andric Globals.push_back(G); 71a7dea167SDimitry Andric 72a7dea167SDimitry Andric // Construct the string in storage. 73a7dea167SDimitry Andric const Pointer Ptr(G->block()); 74a7dea167SDimitry Andric for (unsigned I = 0, N = S->getLength(); I <= N; ++I) { 75a7dea167SDimitry Andric Pointer Field = Ptr.atIndex(I).narrow(); 76a7dea167SDimitry Andric const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I); 77a7dea167SDimitry Andric switch (CharType) { 78a7dea167SDimitry Andric case PT_Sint8: { 79a7dea167SDimitry Andric using T = PrimConv<PT_Sint8>::T; 80a7dea167SDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth); 81a7dea167SDimitry Andric break; 82a7dea167SDimitry Andric } 83a7dea167SDimitry Andric case PT_Uint16: { 84a7dea167SDimitry Andric using T = PrimConv<PT_Uint16>::T; 85a7dea167SDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth); 86a7dea167SDimitry Andric break; 87a7dea167SDimitry Andric } 88a7dea167SDimitry Andric case PT_Uint32: { 89a7dea167SDimitry Andric using T = PrimConv<PT_Uint32>::T; 90a7dea167SDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth); 91a7dea167SDimitry Andric break; 92a7dea167SDimitry Andric } 93a7dea167SDimitry Andric default: 94a7dea167SDimitry Andric llvm_unreachable("unsupported character type"); 95a7dea167SDimitry Andric } 96a7dea167SDimitry Andric } 97a7dea167SDimitry Andric return I; 98a7dea167SDimitry Andric } 99a7dea167SDimitry Andric 100a7dea167SDimitry Andric Pointer Program::getPtrGlobal(unsigned Idx) { 101a7dea167SDimitry Andric assert(Idx < Globals.size()); 102a7dea167SDimitry Andric return Pointer(Globals[Idx]->block()); 103a7dea167SDimitry Andric } 104a7dea167SDimitry Andric 105bdd1243dSDimitry Andric std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) { 106a7dea167SDimitry Andric auto It = GlobalIndices.find(VD); 107a7dea167SDimitry Andric if (It != GlobalIndices.end()) 108a7dea167SDimitry Andric return It->second; 109a7dea167SDimitry Andric 110349cc55cSDimitry Andric // Find any previous declarations which were already evaluated. 111bdd1243dSDimitry Andric std::optional<unsigned> Index; 112a7dea167SDimitry Andric for (const Decl *P = VD; P; P = P->getPreviousDecl()) { 113a7dea167SDimitry Andric auto It = GlobalIndices.find(P); 114a7dea167SDimitry Andric if (It != GlobalIndices.end()) { 115a7dea167SDimitry Andric Index = It->second; 116a7dea167SDimitry Andric break; 117a7dea167SDimitry Andric } 118a7dea167SDimitry Andric } 119a7dea167SDimitry Andric 120a7dea167SDimitry Andric // Map the decl to the existing index. 121a7dea167SDimitry Andric if (Index) { 122a7dea167SDimitry Andric GlobalIndices[VD] = *Index; 12306c3fb27SDimitry Andric return std::nullopt; 124a7dea167SDimitry Andric } 125a7dea167SDimitry Andric 126a7dea167SDimitry Andric return Index; 127a7dea167SDimitry Andric } 128a7dea167SDimitry Andric 129bdd1243dSDimitry Andric std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD, 130bdd1243dSDimitry Andric const Expr *Init) { 131a7dea167SDimitry Andric if (auto Idx = getGlobal(VD)) 132a7dea167SDimitry Andric return Idx; 133a7dea167SDimitry Andric 134bdd1243dSDimitry Andric if (auto Idx = createGlobal(VD, Init)) { 135a7dea167SDimitry Andric GlobalIndices[VD] = *Idx; 136a7dea167SDimitry Andric return Idx; 137a7dea167SDimitry Andric } 13806c3fb27SDimitry Andric return std::nullopt; 139a7dea167SDimitry Andric } 140a7dea167SDimitry Andric 1415f757f3fSDimitry Andric std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) { 14206c3fb27SDimitry Andric // Dedup blocks since they are immutable and pointers cannot be compared. 1435f757f3fSDimitry Andric if (auto It = DummyParams.find(VD); It != DummyParams.end()) 14406c3fb27SDimitry Andric return It->second; 14506c3fb27SDimitry Andric 1465f757f3fSDimitry Andric // Create dummy descriptor. 1475f757f3fSDimitry Andric Descriptor *Desc = allocateDescriptor(VD, std::nullopt); 1485f757f3fSDimitry Andric // Allocate a block for storage. 1495f757f3fSDimitry Andric unsigned I = Globals.size(); 150a7dea167SDimitry Andric 1515f757f3fSDimitry Andric auto *G = new (Allocator, Desc->getAllocSize()) 1525f757f3fSDimitry Andric Global(getCurrentDecl(), Desc, /*IsStatic=*/true, /*IsExtern=*/false); 1535f757f3fSDimitry Andric G->block()->invokeCtor(); 1545f757f3fSDimitry Andric 1555f757f3fSDimitry Andric Globals.push_back(G); 1565f757f3fSDimitry Andric DummyParams[VD] = I; 1575f757f3fSDimitry Andric return I; 158a7dea167SDimitry Andric } 159a7dea167SDimitry Andric 160bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, 161bdd1243dSDimitry Andric const Expr *Init) { 162bdd1243dSDimitry Andric assert(!getGlobal(VD)); 163a7dea167SDimitry Andric bool IsStatic, IsExtern; 1645f757f3fSDimitry Andric if (const auto *Var = dyn_cast<VarDecl>(VD)) { 16506c3fb27SDimitry Andric IsStatic = Context::shouldBeGloballyIndexed(VD); 166a7dea167SDimitry Andric IsExtern = !Var->getAnyInitializer(); 1675f757f3fSDimitry Andric } else if (isa<UnnamedGlobalConstantDecl>(VD)) { 1685f757f3fSDimitry Andric IsStatic = true; 1695f757f3fSDimitry Andric IsExtern = false; 170a7dea167SDimitry Andric } else { 171a7dea167SDimitry Andric IsStatic = false; 172a7dea167SDimitry Andric IsExtern = true; 173a7dea167SDimitry Andric } 174bdd1243dSDimitry Andric if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) { 175a7dea167SDimitry Andric for (const Decl *P = VD; P; P = P->getPreviousDecl()) 176a7dea167SDimitry Andric GlobalIndices[P] = *Idx; 177a7dea167SDimitry Andric return *Idx; 178a7dea167SDimitry Andric } 17906c3fb27SDimitry Andric return std::nullopt; 180a7dea167SDimitry Andric } 181a7dea167SDimitry Andric 182bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const Expr *E) { 183a7dea167SDimitry Andric return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false); 184a7dea167SDimitry Andric } 185a7dea167SDimitry Andric 186bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, 187bdd1243dSDimitry Andric bool IsStatic, bool IsExtern, 188bdd1243dSDimitry Andric const Expr *Init) { 189a7dea167SDimitry Andric // Create a descriptor for the global. 190a7dea167SDimitry Andric Descriptor *Desc; 191a7dea167SDimitry Andric const bool IsConst = Ty.isConstQualified(); 192a7dea167SDimitry Andric const bool IsTemporary = D.dyn_cast<const Expr *>(); 193a7dea167SDimitry Andric if (auto T = Ctx.classify(Ty)) { 194bdd1243dSDimitry Andric Desc = createDescriptor(D, *T, std::nullopt, IsConst, IsTemporary); 195a7dea167SDimitry Andric } else { 196bdd1243dSDimitry Andric Desc = createDescriptor(D, Ty.getTypePtr(), std::nullopt, IsConst, 197bdd1243dSDimitry Andric IsTemporary); 198a7dea167SDimitry Andric } 199a7dea167SDimitry Andric if (!Desc) 20006c3fb27SDimitry Andric return std::nullopt; 201a7dea167SDimitry Andric 202a7dea167SDimitry Andric // Allocate a block for storage. 203a7dea167SDimitry Andric unsigned I = Globals.size(); 204a7dea167SDimitry Andric 205a7dea167SDimitry Andric auto *G = new (Allocator, Desc->getAllocSize()) 206a7dea167SDimitry Andric Global(getCurrentDecl(), Desc, IsStatic, IsExtern); 207a7dea167SDimitry Andric G->block()->invokeCtor(); 208a7dea167SDimitry Andric 209a7dea167SDimitry Andric Globals.push_back(G); 210a7dea167SDimitry Andric 211a7dea167SDimitry Andric return I; 212a7dea167SDimitry Andric } 213a7dea167SDimitry Andric 214a7dea167SDimitry Andric Function *Program::getFunction(const FunctionDecl *F) { 215bdd1243dSDimitry Andric F = F->getCanonicalDecl(); 216bdd1243dSDimitry Andric assert(F); 217a7dea167SDimitry Andric auto It = Funcs.find(F); 218a7dea167SDimitry Andric return It == Funcs.end() ? nullptr : It->second.get(); 219a7dea167SDimitry Andric } 220a7dea167SDimitry Andric 221a7dea167SDimitry Andric Record *Program::getOrCreateRecord(const RecordDecl *RD) { 222a7dea167SDimitry Andric // Use the actual definition as a key. 223a7dea167SDimitry Andric RD = RD->getDefinition(); 224a7dea167SDimitry Andric if (!RD) 225a7dea167SDimitry Andric return nullptr; 226a7dea167SDimitry Andric 227a7dea167SDimitry Andric // Deduplicate records. 22806c3fb27SDimitry Andric if (auto It = Records.find(RD); It != Records.end()) 229a7dea167SDimitry Andric return It->second; 230a7dea167SDimitry Andric 231bdd1243dSDimitry Andric // We insert nullptr now and replace that later, so recursive calls 232bdd1243dSDimitry Andric // to this function with the same RecordDecl don't run into 233bdd1243dSDimitry Andric // infinite recursion. 234bdd1243dSDimitry Andric Records.insert({RD, nullptr}); 235bdd1243dSDimitry Andric 236a7dea167SDimitry Andric // Number of bytes required by fields and base classes. 237bdd1243dSDimitry Andric unsigned BaseSize = 0; 238a7dea167SDimitry Andric // Number of bytes required by virtual base. 239a7dea167SDimitry Andric unsigned VirtSize = 0; 240a7dea167SDimitry Andric 241a7dea167SDimitry Andric // Helper to get a base descriptor. 242a7dea167SDimitry Andric auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * { 243a7dea167SDimitry Andric if (!BR) 244a7dea167SDimitry Andric return nullptr; 245bdd1243dSDimitry Andric return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false, 246a7dea167SDimitry Andric /*isTemporary=*/false, 247a7dea167SDimitry Andric /*isMutable=*/false); 248a7dea167SDimitry Andric }; 249a7dea167SDimitry Andric 250a7dea167SDimitry Andric // Reserve space for base classes. 251a7dea167SDimitry Andric Record::BaseList Bases; 252a7dea167SDimitry Andric Record::VirtualBaseList VirtBases; 253a7dea167SDimitry Andric if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) { 254a7dea167SDimitry Andric for (const CXXBaseSpecifier &Spec : CD->bases()) { 255a7dea167SDimitry Andric if (Spec.isVirtual()) 256a7dea167SDimitry Andric continue; 257a7dea167SDimitry Andric 258a7dea167SDimitry Andric const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl(); 259a7dea167SDimitry Andric Record *BR = getOrCreateRecord(BD); 260a7dea167SDimitry Andric if (Descriptor *Desc = GetBaseDesc(BD, BR)) { 261bdd1243dSDimitry Andric BaseSize += align(sizeof(InlineDescriptor)); 262bdd1243dSDimitry Andric Bases.push_back({BD, BaseSize, Desc, BR}); 263bdd1243dSDimitry Andric BaseSize += align(BR->getSize()); 264a7dea167SDimitry Andric continue; 265a7dea167SDimitry Andric } 266a7dea167SDimitry Andric return nullptr; 267a7dea167SDimitry Andric } 268a7dea167SDimitry Andric 269a7dea167SDimitry Andric for (const CXXBaseSpecifier &Spec : CD->vbases()) { 270a7dea167SDimitry Andric const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl(); 271a7dea167SDimitry Andric Record *BR = getOrCreateRecord(BD); 272a7dea167SDimitry Andric 273a7dea167SDimitry Andric if (Descriptor *Desc = GetBaseDesc(BD, BR)) { 274a7dea167SDimitry Andric VirtSize += align(sizeof(InlineDescriptor)); 275a7dea167SDimitry Andric VirtBases.push_back({BD, VirtSize, Desc, BR}); 276a7dea167SDimitry Andric VirtSize += align(BR->getSize()); 277a7dea167SDimitry Andric continue; 278a7dea167SDimitry Andric } 279a7dea167SDimitry Andric return nullptr; 280a7dea167SDimitry Andric } 281a7dea167SDimitry Andric } 282a7dea167SDimitry Andric 283a7dea167SDimitry Andric // Reserve space for fields. 284a7dea167SDimitry Andric Record::FieldList Fields; 285a7dea167SDimitry Andric for (const FieldDecl *FD : RD->fields()) { 286a7dea167SDimitry Andric // Reserve space for the field's descriptor and the offset. 287bdd1243dSDimitry Andric BaseSize += align(sizeof(InlineDescriptor)); 288a7dea167SDimitry Andric 289a7dea167SDimitry Andric // Classify the field and add its metadata. 290a7dea167SDimitry Andric QualType FT = FD->getType(); 291a7dea167SDimitry Andric const bool IsConst = FT.isConstQualified(); 292a7dea167SDimitry Andric const bool IsMutable = FD->isMutable(); 293a7dea167SDimitry Andric Descriptor *Desc; 294bdd1243dSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(FT)) { 295bdd1243dSDimitry Andric Desc = createDescriptor(FD, *T, std::nullopt, IsConst, 296bdd1243dSDimitry Andric /*isTemporary=*/false, IsMutable); 297a7dea167SDimitry Andric } else { 298bdd1243dSDimitry Andric Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst, 299a7dea167SDimitry Andric /*isTemporary=*/false, IsMutable); 300a7dea167SDimitry Andric } 301a7dea167SDimitry Andric if (!Desc) 302a7dea167SDimitry Andric return nullptr; 303bdd1243dSDimitry Andric Fields.push_back({FD, BaseSize, Desc}); 304bdd1243dSDimitry Andric BaseSize += align(Desc->getAllocSize()); 305a7dea167SDimitry Andric } 306a7dea167SDimitry Andric 307a7dea167SDimitry Andric Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), 308bdd1243dSDimitry Andric std::move(VirtBases), VirtSize, BaseSize); 309bdd1243dSDimitry Andric Records[RD] = R; 310a7dea167SDimitry Andric return R; 311a7dea167SDimitry Andric } 312a7dea167SDimitry Andric 313a7dea167SDimitry Andric Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, 314bdd1243dSDimitry Andric Descriptor::MetadataSize MDSize, 315a7dea167SDimitry Andric bool IsConst, bool IsTemporary, 316bdd1243dSDimitry Andric bool IsMutable, const Expr *Init) { 317a7dea167SDimitry Andric // Classes and structures. 318*297eecfbSDimitry Andric if (const auto *RT = Ty->getAs<RecordType>()) { 319*297eecfbSDimitry Andric if (const auto *Record = getOrCreateRecord(RT->getDecl())) 320bdd1243dSDimitry Andric return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, 321bdd1243dSDimitry Andric IsMutable); 322a7dea167SDimitry Andric } 323a7dea167SDimitry Andric 324a7dea167SDimitry Andric // Arrays. 325*297eecfbSDimitry Andric if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) { 326a7dea167SDimitry Andric QualType ElemTy = ArrayType->getElementType(); 327a7dea167SDimitry Andric // Array of well-known bounds. 328a7dea167SDimitry Andric if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) { 329a7dea167SDimitry Andric size_t NumElems = CAT->getSize().getZExtValue(); 330bdd1243dSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 331a7dea167SDimitry Andric // Arrays of primitives. 332a7dea167SDimitry Andric unsigned ElemSize = primSize(*T); 333a7dea167SDimitry Andric if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { 334a7dea167SDimitry Andric return {}; 335a7dea167SDimitry Andric } 336bdd1243dSDimitry Andric return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, 337a7dea167SDimitry Andric IsMutable); 338a7dea167SDimitry Andric } else { 339a7dea167SDimitry Andric // Arrays of composites. In this case, the array is a list of pointers, 340a7dea167SDimitry Andric // followed by the actual elements. 341*297eecfbSDimitry Andric const Descriptor *ElemDesc = createDescriptor( 342bdd1243dSDimitry Andric D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); 343bdd1243dSDimitry Andric if (!ElemDesc) 344a7dea167SDimitry Andric return nullptr; 34506c3fb27SDimitry Andric unsigned ElemSize = 346bdd1243dSDimitry Andric ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 347a7dea167SDimitry Andric if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) 348a7dea167SDimitry Andric return {}; 349bdd1243dSDimitry Andric return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst, 350bdd1243dSDimitry Andric IsTemporary, IsMutable); 351a7dea167SDimitry Andric } 352a7dea167SDimitry Andric } 353a7dea167SDimitry Andric 354a7dea167SDimitry Andric // Array of unknown bounds - cannot be accessed and pointer arithmetic 355a7dea167SDimitry Andric // is forbidden on pointers to such objects. 356a7dea167SDimitry Andric if (isa<IncompleteArrayType>(ArrayType)) { 357bdd1243dSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 358a7dea167SDimitry Andric return allocateDescriptor(D, *T, IsTemporary, 359a7dea167SDimitry Andric Descriptor::UnknownSize{}); 360a7dea167SDimitry Andric } else { 361*297eecfbSDimitry Andric const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), 362*297eecfbSDimitry Andric MDSize, IsConst, IsTemporary); 363a7dea167SDimitry Andric if (!Desc) 364a7dea167SDimitry Andric return nullptr; 365a7dea167SDimitry Andric return allocateDescriptor(D, Desc, IsTemporary, 366a7dea167SDimitry Andric Descriptor::UnknownSize{}); 367a7dea167SDimitry Andric } 368a7dea167SDimitry Andric } 369a7dea167SDimitry Andric } 370a7dea167SDimitry Andric 371a7dea167SDimitry Andric // Atomic types. 372*297eecfbSDimitry Andric if (const auto *AT = Ty->getAs<AtomicType>()) { 373a7dea167SDimitry Andric const Type *InnerTy = AT->getValueType().getTypePtr(); 374bdd1243dSDimitry Andric return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary, 375bdd1243dSDimitry Andric IsMutable); 376a7dea167SDimitry Andric } 377a7dea167SDimitry Andric 378a7dea167SDimitry Andric // Complex types - represented as arrays of elements. 379*297eecfbSDimitry Andric if (const auto *CT = Ty->getAs<ComplexType>()) { 380a7dea167SDimitry Andric PrimType ElemTy = *Ctx.classify(CT->getElementType()); 381bdd1243dSDimitry Andric return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary, 382bdd1243dSDimitry Andric IsMutable); 383a7dea167SDimitry Andric } 384a7dea167SDimitry Andric 385a7dea167SDimitry Andric return nullptr; 386a7dea167SDimitry Andric } 387