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