| //===--- DIBuilder.cpp - Debug Information Builder ------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the DIBuilder. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/IR/DIBuilder.h" | |
| #include "LLVMContextImpl.h" | |
| #include "llvm/ADT/APInt.h" | |
| #include "llvm/ADT/APSInt.h" | |
| #include "llvm/BinaryFormat/Dwarf.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/DebugInfo.h" | |
| #include "llvm/IR/Module.h" | |
| #include <optional> | |
| using namespace llvm; | |
| using namespace llvm::dwarf; | |
| DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU) | |
| : M(m), VMContext(M.getContext()), CUNode(CU), | |
| AllowUnresolvedNodes(AllowUnresolvedNodes) { | |
| if (CUNode) { | |
| if (const auto &ETs = CUNode->getEnumTypes()) | |
| EnumTypes.assign(ETs.begin(), ETs.end()); | |
| if (const auto &RTs = CUNode->getRetainedTypes()) | |
| AllRetainTypes.assign(RTs.begin(), RTs.end()); | |
| if (const auto &GVs = CUNode->getGlobalVariables()) | |
| Globals.assign(GVs.begin(), GVs.end()); | |
| if (const auto &IMs = CUNode->getImportedEntities()) | |
| ImportedModules.assign(IMs.begin(), IMs.end()); | |
| if (const auto &MNs = CUNode->getMacros()) | |
| AllMacrosPerParent.insert({nullptr, {llvm::from_range, MNs}}); | |
| } | |
| } | |
| void DIBuilder::trackIfUnresolved(MDNode *N) { | |
| if (!N) | |
| return; | |
| if (N->isResolved()) | |
| return; | |
| assert(AllowUnresolvedNodes && "Cannot handle unresolved nodes"); | |
| UnresolvedNodes.emplace_back(N); | |
| } | |
| void DIBuilder::finalizeSubprogram(DISubprogram *SP) { | |
| auto PN = SubprogramTrackedNodes.find(SP); | |
| if (PN == SubprogramTrackedNodes.end()) | |
| return; | |
| SetVector<Metadata *> RetainedNodes; | |
| for (MDNode *N : llvm::concat<MDNode *>(SP->getRetainedNodes(), PN->second)) { | |
| // If the tracked node N was temporary, and the DIBuilder user replaced it | |
| // with a node that does not belong to SP or is non-local, do not add N to | |
| // SP's retainedNodes list. | |
| DILocalScope *Scope = dyn_cast_or_null<DILocalScope>( | |
| DISubprogram::getRawRetainedNodeScope(N)); | |
| if (Scope && Scope->getSubprogram() == SP) | |
| RetainedNodes.insert(N); | |
| } | |
| SP->replaceRetainedNodes( | |
| MDTuple::get(VMContext, RetainedNodes.getArrayRef())); | |
| } | |
| void DIBuilder::finalize() { | |
| if (!CUNode) { | |
| assert(!AllowUnresolvedNodes && | |
| "creating type nodes without a CU is not supported"); | |
| return; | |
| } | |
| if (!EnumTypes.empty()) | |
| CUNode->replaceEnumTypes( | |
| MDTuple::get(VMContext, SmallVector<Metadata *, 16>(EnumTypes.begin(), | |
| EnumTypes.end()))); | |
| SmallVector<Metadata *, 16> RetainValues; | |
| // Declarations and definitions of the same type may be retained. Some | |
| // clients RAUW these pairs, leaving duplicates in the retained types | |
| // list. Use a set to remove the duplicates while we transform the | |
| // TrackingVHs back into Values. | |
| SmallPtrSet<Metadata *, 16> RetainSet; | |
| for (const TrackingMDNodeRef &N : AllRetainTypes) | |
| if (RetainSet.insert(N).second) | |
| RetainValues.push_back(N); | |
| if (!RetainValues.empty()) | |
| CUNode->replaceRetainedTypes(MDTuple::get(VMContext, RetainValues)); | |
| for (auto *SP : AllSubprograms) | |
| finalizeSubprogram(SP); | |
| for (auto *N : RetainValues) | |
| if (auto *SP = dyn_cast<DISubprogram>(N)) | |
| finalizeSubprogram(SP); | |
| if (!Globals.empty()) | |
| CUNode->replaceGlobalVariables(MDTuple::get(VMContext, Globals)); | |
| if (!ImportedModules.empty()) | |
| CUNode->replaceImportedEntities(MDTuple::get( | |
| VMContext, SmallVector<Metadata *, 16>(ImportedModules.begin(), | |
| ImportedModules.end()))); | |
| for (const auto &I : AllMacrosPerParent) { | |
| // DIMacroNode's with nullptr parent are DICompileUnit direct children. | |
| if (!I.first) { | |
| CUNode->replaceMacros(MDTuple::get(VMContext, I.second.getArrayRef())); | |
| continue; | |
| } | |
| // Otherwise, it must be a temporary DIMacroFile that need to be resolved. | |
| auto *TMF = cast<DIMacroFile>(I.first); | |
| auto *MF = DIMacroFile::get(VMContext, dwarf::DW_MACINFO_start_file, | |
| TMF->getLine(), TMF->getFile(), | |
| getOrCreateMacroArray(I.second.getArrayRef())); | |
| replaceTemporary(llvm::TempDIMacroNode(TMF), MF); | |
| } | |
| // Now that all temp nodes have been replaced or deleted, resolve remaining | |
| // cycles. | |
| for (const auto &N : UnresolvedNodes) | |
| if (N && !N->isResolved()) | |
| N->resolveCycles(); | |
| UnresolvedNodes.clear(); | |
| // Can't handle unresolved nodes anymore. | |
| AllowUnresolvedNodes = false; | |
| } | |
| /// If N is compile unit return NULL otherwise return N. | |
| static DIScope *getNonCompileUnitScope(DIScope *N) { | |
| if (!N || isa<DICompileUnit>(N)) | |
| return nullptr; | |
| return cast<DIScope>(N); | |
| } | |
| DICompileUnit *DIBuilder::createCompileUnit( | |
| DISourceLanguageName Lang, DIFile *File, StringRef Producer, | |
| bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName, | |
| DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, | |
| bool SplitDebugInlining, bool DebugInfoForProfiling, | |
| DICompileUnit::DebugNameTableKind NameTableKind, bool RangesBaseAddress, | |
| StringRef SysRoot, StringRef SDK) { | |
| assert(!CUNode && "Can only make one compile unit per DIBuilder instance"); | |
| CUNode = DICompileUnit::getDistinct( | |
| VMContext, Lang, File, Producer, isOptimized, Flags, RunTimeVer, | |
| SplitName, Kind, nullptr, nullptr, nullptr, nullptr, nullptr, DWOId, | |
| SplitDebugInlining, DebugInfoForProfiling, NameTableKind, | |
| RangesBaseAddress, SysRoot, SDK); | |
| // Create a named metadata so that it is easier to find cu in a module. | |
| NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); | |
| NMD->addOperand(CUNode); | |
| trackIfUnresolved(CUNode); | |
| return CUNode; | |
| } | |
| static DIImportedEntity * | |
| createImportedModule(LLVMContext &C, dwarf::Tag Tag, DIScope *Context, | |
| Metadata *NS, DIFile *File, unsigned Line, StringRef Name, | |
| DINodeArray Elements, | |
| SmallVectorImpl<TrackingMDNodeRef> &ImportedModules) { | |
| if (Line) | |
| assert(File && "Source location has line number but no file"); | |
| unsigned EntitiesCount = C.pImpl->DIImportedEntitys.size(); | |
| auto *M = DIImportedEntity::get(C, Tag, Context, cast_or_null<DINode>(NS), | |
| File, Line, Name, Elements); | |
| if (EntitiesCount < C.pImpl->DIImportedEntitys.size()) | |
| // A new Imported Entity was just added to the context. | |
| // Add it to the Imported Modules list. | |
| ImportedModules.emplace_back(M); | |
| return M; | |
| } | |
| DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, | |
| DINamespace *NS, DIFile *File, | |
| unsigned Line, | |
| DINodeArray Elements) { | |
| return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module, | |
| Context, NS, File, Line, StringRef(), Elements, | |
| getImportTrackingVector(Context)); | |
| } | |
| DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, | |
| DIImportedEntity *NS, | |
| DIFile *File, unsigned Line, | |
| DINodeArray Elements) { | |
| return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module, | |
| Context, NS, File, Line, StringRef(), Elements, | |
| getImportTrackingVector(Context)); | |
| } | |
| DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, DIModule *M, | |
| DIFile *File, unsigned Line, | |
| DINodeArray Elements) { | |
| return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module, | |
| Context, M, File, Line, StringRef(), Elements, | |
| getImportTrackingVector(Context)); | |
| } | |
| DIImportedEntity * | |
| DIBuilder::createImportedDeclaration(DIScope *Context, DINode *Decl, | |
| DIFile *File, unsigned Line, | |
| StringRef Name, DINodeArray Elements) { | |
| // Make sure to use the unique identifier based metadata reference for | |
| // types that have one. | |
| return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_declaration, | |
| Context, Decl, File, Line, Name, Elements, | |
| getImportTrackingVector(Context)); | |
| } | |
| DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory, | |
| std::optional<DIFile::ChecksumInfo<StringRef>> CS, | |
| std::optional<StringRef> Source) { | |
| return DIFile::get(VMContext, Filename, Directory, CS, Source); | |
| } | |
| DIMacro *DIBuilder::createMacro(DIMacroFile *Parent, unsigned LineNumber, | |
| unsigned MacroType, StringRef Name, | |
| StringRef Value) { | |
| assert(!Name.empty() && "Unable to create macro without name"); | |
| assert((MacroType == dwarf::DW_MACINFO_undef || | |
| MacroType == dwarf::DW_MACINFO_define) && | |
| "Unexpected macro type"); | |
| auto *M = DIMacro::get(VMContext, MacroType, LineNumber, Name, Value); | |
| AllMacrosPerParent[Parent].insert(M); | |
| return M; | |
| } | |
| DIMacroFile *DIBuilder::createTempMacroFile(DIMacroFile *Parent, | |
| unsigned LineNumber, DIFile *File) { | |
| auto *MF = DIMacroFile::getTemporary(VMContext, dwarf::DW_MACINFO_start_file, | |
| LineNumber, File, DIMacroNodeArray()) | |
| .release(); | |
| AllMacrosPerParent[Parent].insert(MF); | |
| // Add the new temporary DIMacroFile to the macro per parent map as a parent. | |
| // This is needed to assure DIMacroFile with no children to have an entry in | |
| // the map. Otherwise, it will not be resolved in DIBuilder::finalize(). | |
| AllMacrosPerParent.insert({MF, {}}); | |
| return MF; | |
| } | |
| DIEnumerator *DIBuilder::createEnumerator(StringRef Name, uint64_t Val, | |
| bool IsUnsigned) { | |
| assert(!Name.empty() && "Unable to create enumerator without name"); | |
| return DIEnumerator::get(VMContext, APInt(64, Val, !IsUnsigned), IsUnsigned, | |
| Name); | |
| } | |
| DIEnumerator *DIBuilder::createEnumerator(StringRef Name, const APSInt &Value) { | |
| assert(!Name.empty() && "Unable to create enumerator without name"); | |
| return DIEnumerator::get(VMContext, APInt(Value), Value.isUnsigned(), Name); | |
| } | |
| DIBasicType *DIBuilder::createUnspecifiedType(StringRef Name) { | |
| assert(!Name.empty() && "Unable to create type without name"); | |
| return DIBasicType::get(VMContext, dwarf::DW_TAG_unspecified_type, Name); | |
| } | |
| DIBasicType *DIBuilder::createNullPtrType() { | |
| return createUnspecifiedType("decltype(nullptr)"); | |
| } | |
| DIBasicType *DIBuilder::createBasicType(StringRef Name, uint64_t SizeInBits, | |
| unsigned Encoding, | |
| DINode::DIFlags Flags, | |
| uint32_t NumExtraInhabitants, | |
| uint32_t DataSizeInBits) { | |
| return DIBasicType::get(VMContext, dwarf::DW_TAG_base_type, Name, nullptr, 0, | |
| nullptr, SizeInBits, 0, Encoding, NumExtraInhabitants, | |
| DataSizeInBits, Flags); | |
| } | |
| DIBasicType *DIBuilder::createBasicType(StringRef Name, DIFile *File, | |
| unsigned LineNo, DIScope *Context, | |
| uint64_t SizeInBits, unsigned Encoding, | |
| DINode::DIFlags Flags, | |
| uint32_t NumExtraInhabitants, | |
| uint32_t DataSizeInBits) { | |
| auto *R = DIBasicType::get(VMContext, dwarf::DW_TAG_base_type, Name, File, | |
| LineNo, Context, SizeInBits, 0, Encoding, | |
| NumExtraInhabitants, DataSizeInBits, Flags); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| trackIfUnresolved(R); | |
| return R; | |
| } | |
| DIFixedPointType *DIBuilder::createBinaryFixedPointType( | |
| StringRef Name, DIFile *File, unsigned LineNo, DIScope *Context, | |
| uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, | |
| DINode::DIFlags Flags, int Factor) { | |
| auto *R = DIFixedPointType::get( | |
| VMContext, dwarf::DW_TAG_base_type, Name, File, LineNo, Context, | |
| SizeInBits, AlignInBits, Encoding, Flags, | |
| DIFixedPointType::FixedPointBinary, Factor, APInt(), APInt()); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| trackIfUnresolved(R); | |
| return R; | |
| } | |
| DIFixedPointType *DIBuilder::createDecimalFixedPointType( | |
| StringRef Name, DIFile *File, unsigned LineNo, DIScope *Context, | |
| uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, | |
| DINode::DIFlags Flags, int Factor) { | |
| auto *R = DIFixedPointType::get( | |
| VMContext, dwarf::DW_TAG_base_type, Name, File, LineNo, Context, | |
| SizeInBits, AlignInBits, Encoding, Flags, | |
| DIFixedPointType::FixedPointDecimal, Factor, APInt(), APInt()); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| trackIfUnresolved(R); | |
| return R; | |
| } | |
| DIFixedPointType *DIBuilder::createRationalFixedPointType( | |
| StringRef Name, DIFile *File, unsigned LineNo, DIScope *Context, | |
| uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, | |
| DINode::DIFlags Flags, APInt Numerator, APInt Denominator) { | |
| auto *R = DIFixedPointType::get( | |
| VMContext, dwarf::DW_TAG_base_type, Name, File, LineNo, Context, | |
| SizeInBits, AlignInBits, Encoding, Flags, | |
| DIFixedPointType::FixedPointRational, 0, Numerator, Denominator); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| trackIfUnresolved(R); | |
| return R; | |
| } | |
| DIStringType *DIBuilder::createStringType(StringRef Name, uint64_t SizeInBits) { | |
| assert(!Name.empty() && "Unable to create type without name"); | |
| return DIStringType::get(VMContext, dwarf::DW_TAG_string_type, Name, | |
| SizeInBits, 0); | |
| } | |
| DIStringType *DIBuilder::createStringType(StringRef Name, | |
| DIVariable *StringLength, | |
| DIExpression *StrLocationExp) { | |
| assert(!Name.empty() && "Unable to create type without name"); | |
| return DIStringType::get(VMContext, dwarf::DW_TAG_string_type, Name, | |
| StringLength, nullptr, StrLocationExp, 0, 0, 0); | |
| } | |
| DIStringType *DIBuilder::createStringType(StringRef Name, | |
| DIExpression *StringLengthExp, | |
| DIExpression *StrLocationExp) { | |
| assert(!Name.empty() && "Unable to create type without name"); | |
| return DIStringType::get(VMContext, dwarf::DW_TAG_string_type, Name, nullptr, | |
| StringLengthExp, StrLocationExp, 0, 0, 0); | |
| } | |
| DIDerivedType *DIBuilder::createQualifiedType(unsigned Tag, DIType *FromTy) { | |
| return DIDerivedType::get(VMContext, Tag, "", nullptr, 0, nullptr, FromTy, | |
| (uint64_t)0, 0, (uint64_t)0, std::nullopt, | |
| std::nullopt, DINode::FlagZero); | |
| } | |
| DIDerivedType *DIBuilder::createPtrAuthQualifiedType( | |
| DIType *FromTy, unsigned Key, bool IsAddressDiscriminated, | |
| unsigned ExtraDiscriminator, bool IsaPointer, | |
| bool AuthenticatesNullValues) { | |
| return DIDerivedType::get( | |
| VMContext, dwarf::DW_TAG_LLVM_ptrauth_type, "", nullptr, 0, nullptr, | |
| FromTy, (uint64_t)0, 0, (uint64_t)0, std::nullopt, | |
| std::optional<DIDerivedType::PtrAuthData>( | |
| std::in_place, Key, IsAddressDiscriminated, ExtraDiscriminator, | |
| IsaPointer, AuthenticatesNullValues), | |
| DINode::FlagZero); | |
| } | |
| DIDerivedType * | |
| DIBuilder::createPointerType(DIType *PointeeTy, uint64_t SizeInBits, | |
| uint32_t AlignInBits, | |
| std::optional<unsigned> DWARFAddressSpace, | |
| StringRef Name, DINodeArray Annotations) { | |
| // FIXME: Why is there a name here? | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_pointer_type, Name, | |
| nullptr, 0, nullptr, PointeeTy, SizeInBits, | |
| AlignInBits, 0, DWARFAddressSpace, std::nullopt, | |
| DINode::FlagZero, nullptr, Annotations); | |
| } | |
| DIDerivedType *DIBuilder::createMemberPointerType(DIType *PointeeTy, | |
| DIType *Base, | |
| uint64_t SizeInBits, | |
| uint32_t AlignInBits, | |
| DINode::DIFlags Flags) { | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_ptr_to_member_type, "", | |
| nullptr, 0, nullptr, PointeeTy, SizeInBits, | |
| AlignInBits, 0, std::nullopt, std::nullopt, Flags, | |
| Base); | |
| } | |
| DIDerivedType * | |
| DIBuilder::createReferenceType(unsigned Tag, DIType *RTy, uint64_t SizeInBits, | |
| uint32_t AlignInBits, | |
| std::optional<unsigned> DWARFAddressSpace) { | |
| assert(RTy && "Unable to create reference type"); | |
| return DIDerivedType::get(VMContext, Tag, "", nullptr, 0, nullptr, RTy, | |
| SizeInBits, AlignInBits, 0, DWARFAddressSpace, {}, | |
| DINode::FlagZero); | |
| } | |
| DIDerivedType *DIBuilder::createTypedef(DIType *Ty, StringRef Name, | |
| DIFile *File, unsigned LineNo, | |
| DIScope *Context, uint32_t AlignInBits, | |
| DINode::DIFlags Flags, | |
| DINodeArray Annotations) { | |
| auto *T = DIDerivedType::get( | |
| VMContext, dwarf::DW_TAG_typedef, Name, File, LineNo, | |
| getNonCompileUnitScope(Context), Ty, (uint64_t)0, AlignInBits, | |
| (uint64_t)0, std::nullopt, std::nullopt, Flags, nullptr, Annotations); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(T); | |
| return T; | |
| } | |
| DIDerivedType * | |
| DIBuilder::createTemplateAlias(DIType *Ty, StringRef Name, DIFile *File, | |
| unsigned LineNo, DIScope *Context, | |
| DINodeArray TParams, uint32_t AlignInBits, | |
| DINode::DIFlags Flags, DINodeArray Annotations) { | |
| auto *T = | |
| DIDerivedType::get(VMContext, dwarf::DW_TAG_template_alias, Name, File, | |
| LineNo, getNonCompileUnitScope(Context), Ty, | |
| (uint64_t)0, AlignInBits, (uint64_t)0, std::nullopt, | |
| std::nullopt, Flags, TParams.get(), Annotations); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(T); | |
| return T; | |
| } | |
| DIDerivedType *DIBuilder::createFriend(DIType *Ty, DIType *FriendTy) { | |
| assert(Ty && "Invalid type!"); | |
| assert(FriendTy && "Invalid friend type!"); | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_friend, "", nullptr, 0, Ty, | |
| FriendTy, (uint64_t)0, 0, (uint64_t)0, std::nullopt, | |
| std::nullopt, DINode::FlagZero); | |
| } | |
| DIDerivedType *DIBuilder::createInheritance(DIType *Ty, DIType *BaseTy, | |
| uint64_t BaseOffset, | |
| uint32_t VBPtrOffset, | |
| DINode::DIFlags Flags) { | |
| assert(Ty && "Unable to create inheritance"); | |
| Metadata *ExtraData = ConstantAsMetadata::get( | |
| ConstantInt::get(IntegerType::get(VMContext, 32), VBPtrOffset)); | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_inheritance, "", nullptr, | |
| 0, Ty, BaseTy, 0, 0, BaseOffset, std::nullopt, | |
| std::nullopt, Flags, ExtraData); | |
| } | |
| DIDerivedType *DIBuilder::createMemberType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, | |
| DINode::DIFlags Flags, DIType *Ty, DINodeArray Annotations) { | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File, | |
| LineNumber, getNonCompileUnitScope(Scope), Ty, | |
| SizeInBits, AlignInBits, OffsetInBits, std::nullopt, | |
| std::nullopt, Flags, nullptr, Annotations); | |
| } | |
| DIDerivedType *DIBuilder::createMemberType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| Metadata *SizeInBits, uint32_t AlignInBits, Metadata *OffsetInBits, | |
| DINode::DIFlags Flags, DIType *Ty, DINodeArray Annotations) { | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File, | |
| LineNumber, getNonCompileUnitScope(Scope), Ty, | |
| SizeInBits, AlignInBits, OffsetInBits, std::nullopt, | |
| std::nullopt, Flags, nullptr, Annotations); | |
| } | |
| static ConstantAsMetadata *getConstantOrNull(Constant *C) { | |
| if (C) | |
| return ConstantAsMetadata::get(C); | |
| return nullptr; | |
| } | |
| DIDerivedType *DIBuilder::createVariantMemberType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, | |
| Constant *Discriminant, DINode::DIFlags Flags, DIType *Ty) { | |
| // "ExtraData" is overloaded for bit fields and for variants, so | |
| // make sure to disallow this. | |
| assert((Flags & DINode::FlagBitField) == 0); | |
| return DIDerivedType::get( | |
| VMContext, dwarf::DW_TAG_member, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), Ty, SizeInBits, AlignInBits, OffsetInBits, | |
| std::nullopt, std::nullopt, Flags, getConstantOrNull(Discriminant)); | |
| } | |
| DIDerivedType *DIBuilder::createVariantMemberType(DIScope *Scope, | |
| DINodeArray Elements, | |
| Constant *Discriminant, | |
| DIType *Ty) { | |
| auto *V = DICompositeType::get(VMContext, dwarf::DW_TAG_variant, {}, nullptr, | |
| 0, getNonCompileUnitScope(Scope), {}, | |
| (uint64_t)0, 0, (uint64_t)0, DINode::FlagZero, | |
| Elements, 0, {}, nullptr); | |
| trackIfUnresolved(V); | |
| return createVariantMemberType(Scope, {}, nullptr, 0, 0, 0, 0, Discriminant, | |
| DINode::FlagZero, V); | |
| } | |
| DIDerivedType *DIBuilder::createBitFieldMemberType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| Metadata *SizeInBits, Metadata *OffsetInBits, uint64_t StorageOffsetInBits, | |
| DINode::DIFlags Flags, DIType *Ty, DINodeArray Annotations) { | |
| Flags |= DINode::FlagBitField; | |
| return DIDerivedType::get( | |
| VMContext, dwarf::DW_TAG_member, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), Ty, SizeInBits, /*AlignInBits=*/0, | |
| OffsetInBits, std::nullopt, std::nullopt, Flags, | |
| ConstantAsMetadata::get(ConstantInt::get(IntegerType::get(VMContext, 64), | |
| StorageOffsetInBits)), | |
| Annotations); | |
| } | |
| DIDerivedType *DIBuilder::createBitFieldMemberType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits, | |
| DINode::DIFlags Flags, DIType *Ty, DINodeArray Annotations) { | |
| Flags |= DINode::FlagBitField; | |
| return DIDerivedType::get( | |
| VMContext, dwarf::DW_TAG_member, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), Ty, SizeInBits, /*AlignInBits=*/0, | |
| OffsetInBits, std::nullopt, std::nullopt, Flags, | |
| ConstantAsMetadata::get(ConstantInt::get(IntegerType::get(VMContext, 64), | |
| StorageOffsetInBits)), | |
| Annotations); | |
| } | |
| DIDerivedType * | |
| DIBuilder::createStaticMemberType(DIScope *Scope, StringRef Name, DIFile *File, | |
| unsigned LineNumber, DIType *Ty, | |
| DINode::DIFlags Flags, llvm::Constant *Val, | |
| unsigned Tag, uint32_t AlignInBits) { | |
| Flags |= DINode::FlagStaticMember; | |
| return DIDerivedType::get(VMContext, Tag, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), Ty, (uint64_t)0, | |
| AlignInBits, (uint64_t)0, std::nullopt, | |
| std::nullopt, Flags, getConstantOrNull(Val)); | |
| } | |
| DIDerivedType * | |
| DIBuilder::createObjCIVar(StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, | |
| uint64_t OffsetInBits, DINode::DIFlags Flags, | |
| DIType *Ty, MDNode *PropertyNode) { | |
| return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File, | |
| LineNumber, getNonCompileUnitScope(File), Ty, | |
| SizeInBits, AlignInBits, OffsetInBits, std::nullopt, | |
| std::nullopt, Flags, PropertyNode); | |
| } | |
| DIObjCProperty * | |
| DIBuilder::createObjCProperty(StringRef Name, DIFile *File, unsigned LineNumber, | |
| StringRef GetterName, StringRef SetterName, | |
| unsigned PropertyAttributes, DIType *Ty) { | |
| return DIObjCProperty::get(VMContext, Name, File, LineNumber, GetterName, | |
| SetterName, PropertyAttributes, Ty); | |
| } | |
| DIProperty *DIBuilder::createProperty(StringRef Name, DIFile *File, | |
| unsigned LineNumber, DIType *Ty, | |
| DIDerivedType *BackingStorage) { | |
| return DIProperty::get(VMContext, Name, File, LineNumber, Ty, BackingStorage); | |
| } | |
| DITemplateTypeParameter * | |
| DIBuilder::createTemplateTypeParameter(DIScope *Context, StringRef Name, | |
| DIType *Ty, bool isDefault) { | |
| assert((!Context || isa<DICompileUnit>(Context)) && "Expected compile unit"); | |
| return DITemplateTypeParameter::get(VMContext, Name, Ty, isDefault); | |
| } | |
| static DITemplateValueParameter * | |
| createTemplateValueParameterHelper(LLVMContext &VMContext, unsigned Tag, | |
| DIScope *Context, StringRef Name, DIType *Ty, | |
| bool IsDefault, Metadata *MD) { | |
| assert((!Context || isa<DICompileUnit>(Context)) && "Expected compile unit"); | |
| return DITemplateValueParameter::get(VMContext, Tag, Name, Ty, IsDefault, MD); | |
| } | |
| DITemplateValueParameter * | |
| DIBuilder::createTemplateValueParameter(DIScope *Context, StringRef Name, | |
| DIType *Ty, bool isDefault, | |
| Constant *Val) { | |
| return createTemplateValueParameterHelper( | |
| VMContext, dwarf::DW_TAG_template_value_parameter, Context, Name, Ty, | |
| isDefault, getConstantOrNull(Val)); | |
| } | |
| DITemplateValueParameter * | |
| DIBuilder::createTemplateTemplateParameter(DIScope *Context, StringRef Name, | |
| DIType *Ty, StringRef Val, | |
| bool IsDefault) { | |
| return createTemplateValueParameterHelper( | |
| VMContext, dwarf::DW_TAG_GNU_template_template_param, Context, Name, Ty, | |
| IsDefault, MDString::get(VMContext, Val)); | |
| } | |
| DITemplateValueParameter * | |
| DIBuilder::createTemplateParameterPack(DIScope *Context, StringRef Name, | |
| DIType *Ty, DINodeArray Val) { | |
| return createTemplateValueParameterHelper( | |
| VMContext, dwarf::DW_TAG_GNU_template_parameter_pack, Context, Name, Ty, | |
| false, Val.get()); | |
| } | |
| DICompositeType *DIBuilder::createClassType( | |
| DIScope *Context, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, | |
| DINode::DIFlags Flags, DIType *DerivedFrom, DINodeArray Elements, | |
| unsigned RunTimeLang, DIType *VTableHolder, MDNode *TemplateParams, | |
| StringRef UniqueIdentifier, DINodeArray Annotations) { | |
| assert((!Context || isa<DIScope>(Context)) && | |
| "createClassType should be called with a valid Context"); | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_class_type, Name, File, LineNumber, | |
| getNonCompileUnitScope(Context), DerivedFrom, SizeInBits, AlignInBits, | |
| OffsetInBits, Flags, Elements, RunTimeLang, /*EnumKind=*/std::nullopt, | |
| VTableHolder, cast_or_null<MDTuple>(TemplateParams), UniqueIdentifier, | |
| nullptr, nullptr, nullptr, nullptr, nullptr, Annotations); | |
| trackIfUnresolved(R); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| return R; | |
| } | |
| DICompositeType *DIBuilder::createStructType( | |
| DIScope *Context, StringRef Name, DIFile *File, unsigned LineNumber, | |
| Metadata *SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, | |
| DIType *DerivedFrom, DINodeArray Elements, unsigned RunTimeLang, | |
| DIType *VTableHolder, StringRef UniqueIdentifier, DIType *Specification, | |
| uint32_t NumExtraInhabitants, DINodeArray Annotations) { | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_structure_type, Name, File, LineNumber, | |
| getNonCompileUnitScope(Context), DerivedFrom, SizeInBits, AlignInBits, 0, | |
| Flags, Elements, RunTimeLang, /*EnumKind=*/std::nullopt, VTableHolder, | |
| nullptr, UniqueIdentifier, nullptr, nullptr, nullptr, nullptr, nullptr, | |
| Annotations, Specification, NumExtraInhabitants); | |
| trackIfUnresolved(R); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| return R; | |
| } | |
| DICompositeType *DIBuilder::createStructType( | |
| DIScope *Context, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, | |
| DIType *DerivedFrom, DINodeArray Elements, unsigned RunTimeLang, | |
| DIType *VTableHolder, StringRef UniqueIdentifier, DIType *Specification, | |
| uint32_t NumExtraInhabitants, DINodeArray Annotations) { | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_structure_type, Name, File, LineNumber, | |
| getNonCompileUnitScope(Context), DerivedFrom, SizeInBits, AlignInBits, 0, | |
| Flags, Elements, RunTimeLang, /*EnumKind=*/std::nullopt, VTableHolder, | |
| nullptr, UniqueIdentifier, nullptr, nullptr, nullptr, nullptr, nullptr, | |
| Annotations, Specification, NumExtraInhabitants); | |
| trackIfUnresolved(R); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(R); | |
| return R; | |
| } | |
| DICompositeType *DIBuilder::createUnionType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, | |
| DINodeArray Elements, unsigned RunTimeLang, StringRef UniqueIdentifier, | |
| DINodeArray Annotations) { | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_union_type, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), nullptr, SizeInBits, AlignInBits, 0, Flags, | |
| Elements, RunTimeLang, /*EnumKind=*/std::nullopt, nullptr, nullptr, | |
| UniqueIdentifier, nullptr, nullptr, nullptr, nullptr, nullptr, | |
| Annotations); | |
| trackIfUnresolved(R); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(R); | |
| return R; | |
| } | |
| DICompositeType * | |
| DIBuilder::createVariantPart(DIScope *Scope, StringRef Name, DIFile *File, | |
| unsigned LineNumber, uint64_t SizeInBits, | |
| uint32_t AlignInBits, DINode::DIFlags Flags, | |
| DIDerivedType *Discriminator, DINodeArray Elements, | |
| StringRef UniqueIdentifier) { | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_variant_part, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), nullptr, SizeInBits, AlignInBits, 0, Flags, | |
| Elements, 0, /*EnumKind=*/std::nullopt, nullptr, nullptr, | |
| UniqueIdentifier, Discriminator); | |
| trackIfUnresolved(R); | |
| return R; | |
| } | |
| DISubroutineType *DIBuilder::createSubroutineType(DITypeArray ParameterTypes, | |
| DINode::DIFlags Flags, | |
| unsigned CC) { | |
| return DISubroutineType::get(VMContext, Flags, CC, ParameterTypes); | |
| } | |
| DICompositeType *DIBuilder::createEnumerationType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t SizeInBits, uint32_t AlignInBits, DINodeArray Elements, | |
| DIType *UnderlyingType, unsigned RunTimeLang, StringRef UniqueIdentifier, | |
| bool IsScoped, std::optional<uint32_t> EnumKind) { | |
| auto *CTy = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_enumeration_type, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), UnderlyingType, SizeInBits, AlignInBits, 0, | |
| IsScoped ? DINode::FlagEnumClass : DINode::FlagZero, Elements, | |
| RunTimeLang, EnumKind, nullptr, nullptr, UniqueIdentifier); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(CTy); | |
| else | |
| EnumTypes.emplace_back(CTy); | |
| trackIfUnresolved(CTy); | |
| return CTy; | |
| } | |
| DIDerivedType *DIBuilder::createSetType(DIScope *Scope, StringRef Name, | |
| DIFile *File, unsigned LineNo, | |
| uint64_t SizeInBits, | |
| uint32_t AlignInBits, DIType *Ty) { | |
| auto *R = DIDerivedType::get(VMContext, dwarf::DW_TAG_set_type, Name, File, | |
| LineNo, getNonCompileUnitScope(Scope), Ty, | |
| SizeInBits, AlignInBits, 0, std::nullopt, | |
| std::nullopt, DINode::FlagZero); | |
| trackIfUnresolved(R); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(R); | |
| return R; | |
| } | |
| DICompositeType * | |
| DIBuilder::createArrayType(uint64_t Size, uint32_t AlignInBits, DIType *Ty, | |
| DINodeArray Subscripts, | |
| PointerUnion<DIExpression *, DIVariable *> DL, | |
| PointerUnion<DIExpression *, DIVariable *> AS, | |
| PointerUnion<DIExpression *, DIVariable *> AL, | |
| PointerUnion<DIExpression *, DIVariable *> RK) { | |
| return createArrayType(nullptr, StringRef(), nullptr, 0, Size, AlignInBits, | |
| Ty, Subscripts, DL, AS, AL, RK); | |
| } | |
| DICompositeType *DIBuilder::createArrayType( | |
| DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, | |
| uint64_t Size, uint32_t AlignInBits, DIType *Ty, DINodeArray Subscripts, | |
| PointerUnion<DIExpression *, DIVariable *> DL, | |
| PointerUnion<DIExpression *, DIVariable *> AS, | |
| PointerUnion<DIExpression *, DIVariable *> AL, | |
| PointerUnion<DIExpression *, DIVariable *> RK, Metadata *BitStride) { | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_array_type, Name, File, LineNumber, | |
| getNonCompileUnitScope(Scope), Ty, Size, AlignInBits, 0, DINode::FlagZero, | |
| Subscripts, 0, /*EnumKind=*/std::nullopt, nullptr, nullptr, "", nullptr, | |
| isa<DIExpression *>(DL) ? (Metadata *)cast<DIExpression *>(DL) | |
| : (Metadata *)cast<DIVariable *>(DL), | |
| isa<DIExpression *>(AS) ? (Metadata *)cast<DIExpression *>(AS) | |
| : (Metadata *)cast<DIVariable *>(AS), | |
| isa<DIExpression *>(AL) ? (Metadata *)cast<DIExpression *>(AL) | |
| : (Metadata *)cast<DIVariable *>(AL), | |
| isa<DIExpression *>(RK) ? (Metadata *)cast<DIExpression *>(RK) | |
| : (Metadata *)cast<DIVariable *>(RK), | |
| nullptr, nullptr, 0, BitStride); | |
| trackIfUnresolved(R); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(R); | |
| return R; | |
| } | |
| DICompositeType *DIBuilder::createVectorType(uint64_t Size, | |
| uint32_t AlignInBits, DIType *Ty, | |
| DINodeArray Subscripts, | |
| Metadata *BitStride) { | |
| auto *R = DICompositeType::get( | |
| VMContext, dwarf::DW_TAG_array_type, /*Name=*/"", | |
| /*File=*/nullptr, /*Line=*/0, /*Scope=*/nullptr, /*BaseType=*/Ty, | |
| /*SizeInBits=*/Size, /*AlignInBits=*/AlignInBits, /*OffsetInBits=*/0, | |
| /*Flags=*/DINode::FlagVector, /*Elements=*/Subscripts, | |
| /*RuntimeLang=*/0, /*EnumKind=*/std::nullopt, /*VTableHolder=*/nullptr, | |
| /*TemplateParams=*/nullptr, /*Identifier=*/"", | |
| /*Discriminator=*/nullptr, /*DataLocation=*/nullptr, | |
| /*Associated=*/nullptr, /*Allocated=*/nullptr, /*Rank=*/nullptr, | |
| /*Annotations=*/nullptr, /*Specification=*/nullptr, | |
| /*NumExtraInhabitants=*/0, | |
| /*BitStride=*/BitStride); | |
| trackIfUnresolved(R); | |
| return R; | |
| } | |
| DISubprogram *DIBuilder::createArtificialSubprogram(DISubprogram *SP) { | |
| auto NewSP = SP->cloneWithFlags(SP->getFlags() | DINode::FlagArtificial); | |
| return MDNode::replaceWithDistinct(std::move(NewSP)); | |
| } | |
| static DIType *createTypeWithFlags(const DIType *Ty, | |
| DINode::DIFlags FlagsToSet) { | |
| auto NewTy = Ty->cloneWithFlags(Ty->getFlags() | FlagsToSet); | |
| return MDNode::replaceWithUniqued(std::move(NewTy)); | |
| } | |
| DIType *DIBuilder::createArtificialType(DIType *Ty) { | |
| // FIXME: Restrict this to the nodes where it's valid. | |
| if (Ty->isArtificial()) | |
| return Ty; | |
| return createTypeWithFlags(Ty, DINode::FlagArtificial); | |
| } | |
| DIType *DIBuilder::createObjectPointerType(DIType *Ty, bool Implicit) { | |
| // FIXME: Restrict this to the nodes where it's valid. | |
| if (Ty->isObjectPointer()) | |
| return Ty; | |
| DINode::DIFlags Flags = DINode::FlagObjectPointer; | |
| if (Implicit) | |
| Flags |= DINode::FlagArtificial; | |
| return createTypeWithFlags(Ty, Flags); | |
| } | |
| void DIBuilder::retainType(DIScope *T) { | |
| assert(T && "Expected non-null type"); | |
| assert((isa<DIType>(T) || (isa<DISubprogram>(T) && | |
| cast<DISubprogram>(T)->isDefinition() == false)) && | |
| "Expected type or subprogram declaration"); | |
| if (!isa_and_nonnull<DILocalScope>(T->getScope())) | |
| AllRetainTypes.emplace_back(T); | |
| } | |
| DIBasicType *DIBuilder::createUnspecifiedParameter() { return nullptr; } | |
| DICompositeType *DIBuilder::createForwardDecl( | |
| unsigned Tag, StringRef Name, DIScope *Scope, DIFile *F, unsigned Line, | |
| unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, | |
| StringRef UniqueIdentifier, std::optional<uint32_t> EnumKind) { | |
| // FIXME: Define in terms of createReplaceableForwardDecl() by calling | |
| // replaceWithUniqued(). | |
| auto *RetTy = DICompositeType::get( | |
| VMContext, Tag, Name, F, Line, getNonCompileUnitScope(Scope), nullptr, | |
| SizeInBits, AlignInBits, 0, DINode::FlagFwdDecl, nullptr, RuntimeLang, | |
| /*EnumKind=*/EnumKind, nullptr, nullptr, UniqueIdentifier); | |
| trackIfUnresolved(RetTy); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(RetTy); | |
| return RetTy; | |
| } | |
| DICompositeType *DIBuilder::createReplaceableCompositeType( | |
| unsigned Tag, StringRef Name, DIScope *Scope, DIFile *F, unsigned Line, | |
| unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, | |
| DINode::DIFlags Flags, StringRef UniqueIdentifier, DINodeArray Annotations, | |
| std::optional<uint32_t> EnumKind) { | |
| auto *RetTy = | |
| DICompositeType::getTemporary( | |
| VMContext, Tag, Name, F, Line, getNonCompileUnitScope(Scope), nullptr, | |
| SizeInBits, AlignInBits, 0, Flags, nullptr, RuntimeLang, EnumKind, | |
| nullptr, nullptr, UniqueIdentifier, nullptr, nullptr, nullptr, | |
| nullptr, nullptr, Annotations) | |
| .release(); | |
| trackIfUnresolved(RetTy); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(RetTy); | |
| return RetTy; | |
| } | |
| DINodeArray DIBuilder::getOrCreateArray(ArrayRef<Metadata *> Elements) { | |
| return MDTuple::get(VMContext, Elements); | |
| } | |
| DIMacroNodeArray | |
| DIBuilder::getOrCreateMacroArray(ArrayRef<Metadata *> Elements) { | |
| return MDTuple::get(VMContext, Elements); | |
| } | |
| DITypeArray DIBuilder::getOrCreateTypeArray(ArrayRef<Metadata *> Elements) { | |
| SmallVector<llvm::Metadata *, 16> Elts; | |
| for (Metadata *E : Elements) { | |
| if (isa_and_nonnull<MDNode>(E)) | |
| Elts.push_back(cast<DIType>(E)); | |
| else | |
| Elts.push_back(E); | |
| } | |
| return DITypeArray(MDNode::get(VMContext, Elts)); | |
| } | |
| DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, int64_t Count) { | |
| auto *LB = ConstantAsMetadata::get( | |
| ConstantInt::getSigned(Type::getInt64Ty(VMContext), Lo)); | |
| auto *CountNode = ConstantAsMetadata::get( | |
| ConstantInt::getSigned(Type::getInt64Ty(VMContext), Count)); | |
| return DISubrange::get(VMContext, CountNode, LB, nullptr, nullptr); | |
| } | |
| DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, Metadata *CountNode) { | |
| auto *LB = ConstantAsMetadata::get( | |
| ConstantInt::getSigned(Type::getInt64Ty(VMContext), Lo)); | |
| return DISubrange::get(VMContext, CountNode, LB, nullptr, nullptr); | |
| } | |
| DISubrange *DIBuilder::getOrCreateSubrange(Metadata *CountNode, Metadata *LB, | |
| Metadata *UB, Metadata *Stride) { | |
| return DISubrange::get(VMContext, CountNode, LB, UB, Stride); | |
| } | |
| DIGenericSubrange *DIBuilder::getOrCreateGenericSubrange( | |
| DIGenericSubrange::BoundType CountNode, DIGenericSubrange::BoundType LB, | |
| DIGenericSubrange::BoundType UB, DIGenericSubrange::BoundType Stride) { | |
| auto ConvToMetadata = [&](DIGenericSubrange::BoundType Bound) -> Metadata * { | |
| return isa<DIExpression *>(Bound) ? (Metadata *)cast<DIExpression *>(Bound) | |
| : (Metadata *)cast<DIVariable *>(Bound); | |
| }; | |
| return DIGenericSubrange::get(VMContext, ConvToMetadata(CountNode), | |
| ConvToMetadata(LB), ConvToMetadata(UB), | |
| ConvToMetadata(Stride)); | |
| } | |
| DISubrangeType *DIBuilder::createSubrangeType( | |
| StringRef Name, DIFile *File, unsigned LineNo, DIScope *Scope, | |
| uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, | |
| DIType *Ty, Metadata *LowerBound, Metadata *UpperBound, Metadata *Stride, | |
| Metadata *Bias) { | |
| auto *T = DISubrangeType::get(VMContext, Name, File, LineNo, Scope, | |
| SizeInBits, AlignInBits, Flags, Ty, LowerBound, | |
| UpperBound, Stride, Bias); | |
| if (isa_and_nonnull<DILocalScope>(Scope)) | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(T); | |
| return T; | |
| } | |
| static void checkGlobalVariableScope(DIScope *Context) { | |
| #ifndef NDEBUG | |
| if (auto *CT = | |
| dyn_cast_or_null<DICompositeType>(getNonCompileUnitScope(Context))) | |
| assert(CT->getIdentifier().empty() && | |
| "Context of a global variable should not be a type with identifier"); | |
| #endif | |
| } | |
| DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression( | |
| DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, | |
| unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, bool isDefined, | |
| DIExpression *Expr, MDNode *Decl, MDTuple *TemplateParams, | |
| uint32_t AlignInBits, DINodeArray Annotations) { | |
| checkGlobalVariableScope(Context); | |
| auto *GV = DIGlobalVariable::getDistinct( | |
| VMContext, cast_or_null<DIScope>(Context), Name, LinkageName, F, | |
| LineNumber, Ty, IsLocalToUnit, isDefined, | |
| cast_or_null<DIDerivedType>(Decl), TemplateParams, AlignInBits, | |
| Annotations); | |
| if (!Expr) | |
| Expr = createExpression(); | |
| auto *N = DIGlobalVariableExpression::get(VMContext, GV, Expr); | |
| if (isa_and_nonnull<DILocalScope>(Context)) | |
| getSubprogramNodesTrackingVector(Context).emplace_back(N); | |
| else | |
| Globals.push_back(N); | |
| return N; | |
| } | |
| DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( | |
| DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, | |
| unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, MDNode *Decl, | |
| MDTuple *TemplateParams, uint32_t AlignInBits) { | |
| checkGlobalVariableScope(Context); | |
| return DIGlobalVariable::getTemporary( | |
| VMContext, cast_or_null<DIScope>(Context), Name, LinkageName, F, | |
| LineNumber, Ty, IsLocalToUnit, false, | |
| cast_or_null<DIDerivedType>(Decl), TemplateParams, AlignInBits, | |
| nullptr) | |
| .release(); | |
| } | |
| static DILocalVariable *createLocalVariable( | |
| LLVMContext &VMContext, | |
| SmallVectorImpl<TrackingMDNodeRef> &PreservedNodes, | |
| DIScope *Context, StringRef Name, unsigned ArgNo, DIFile *File, | |
| unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, | |
| uint32_t AlignInBits, DINodeArray Annotations = nullptr) { | |
| // FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT | |
| // the only valid scopes)? | |
| auto *Scope = cast<DILocalScope>(Context); | |
| auto *Node = DILocalVariable::get(VMContext, Scope, Name, File, LineNo, Ty, | |
| ArgNo, Flags, AlignInBits, Annotations); | |
| if (AlwaysPreserve) { | |
| // The optimizer may remove local variables. If there is an interest | |
| // to preserve variable info in such situation then stash it in a | |
| // named mdnode. | |
| PreservedNodes.emplace_back(Node); | |
| } | |
| return Node; | |
| } | |
| DILocalVariable *DIBuilder::createAutoVariable(DIScope *Scope, StringRef Name, | |
| DIFile *File, unsigned LineNo, | |
| DIType *Ty, bool AlwaysPreserve, | |
| DINode::DIFlags Flags, | |
| uint32_t AlignInBits) { | |
| assert(Scope && isa<DILocalScope>(Scope) && | |
| "Unexpected scope for a local variable."); | |
| return createLocalVariable( | |
| VMContext, getSubprogramNodesTrackingVector(Scope), Scope, Name, | |
| /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, Flags, AlignInBits); | |
| } | |
| DILocalVariable *DIBuilder::createParameterVariable( | |
| DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File, | |
| unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, | |
| DINodeArray Annotations) { | |
| assert(ArgNo && "Expected non-zero argument number for parameter"); | |
| assert(Scope && isa<DILocalScope>(Scope) && | |
| "Unexpected scope for a local variable."); | |
| return createLocalVariable( | |
| VMContext, getSubprogramNodesTrackingVector(Scope), Scope, Name, ArgNo, | |
| File, LineNo, Ty, AlwaysPreserve, Flags, /*AlignInBits=*/0, Annotations); | |
| } | |
| DILabel *DIBuilder::createLabel(DIScope *Context, StringRef Name, DIFile *File, | |
| unsigned LineNo, unsigned Column, | |
| bool IsArtificial, | |
| std::optional<unsigned> CoroSuspendIdx, | |
| bool AlwaysPreserve) { | |
| auto *Scope = cast<DILocalScope>(Context); | |
| auto *Node = DILabel::get(VMContext, Scope, Name, File, LineNo, Column, | |
| IsArtificial, CoroSuspendIdx); | |
| if (AlwaysPreserve) { | |
| /// The optimizer may remove labels. If there is an interest | |
| /// to preserve label info in such situation then append it to | |
| /// the list of retained nodes of the DISubprogram. | |
| getSubprogramNodesTrackingVector(Scope).emplace_back(Node); | |
| } | |
| return Node; | |
| } | |
| DIExpression *DIBuilder::createExpression(ArrayRef<uint64_t> Addr) { | |
| return DIExpression::get(VMContext, Addr); | |
| } | |
| template <class... Ts> | |
| static DISubprogram *getSubprogram(bool IsDistinct, Ts &&...Args) { | |
| if (IsDistinct) | |
| return DISubprogram::getDistinct(std::forward<Ts>(Args)...); | |
| return DISubprogram::get(std::forward<Ts>(Args)...); | |
| } | |
| DISubprogram *DIBuilder::createFunction( | |
| DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, | |
| unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, | |
| DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, | |
| DITemplateParameterArray TParams, DISubprogram *Decl, | |
| DITypeArray ThrownTypes, DINodeArray Annotations, StringRef TargetFuncName, | |
| bool UseKeyInstructions) { | |
| bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; | |
| auto *Node = getSubprogram( | |
| /*IsDistinct=*/IsDefinition, VMContext, getNonCompileUnitScope(Context), | |
| Name, LinkageName, File, LineNo, Ty, ScopeLine, nullptr, 0, 0, Flags, | |
| SPFlags, IsDefinition ? CUNode : nullptr, TParams, Decl, nullptr, | |
| ThrownTypes, Annotations, TargetFuncName, UseKeyInstructions); | |
| AllSubprograms.push_back(Node); | |
| trackIfUnresolved(Node); | |
| return Node; | |
| } | |
| DISubprogram *DIBuilder::createTempFunctionFwdDecl( | |
| DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, | |
| unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, | |
| DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, | |
| DITemplateParameterArray TParams, DISubprogram *Decl, | |
| DITypeArray ThrownTypes) { | |
| bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; | |
| return DISubprogram::getTemporary(VMContext, getNonCompileUnitScope(Context), | |
| Name, LinkageName, File, LineNo, Ty, | |
| ScopeLine, nullptr, 0, 0, Flags, SPFlags, | |
| IsDefinition ? CUNode : nullptr, TParams, | |
| Decl, nullptr, ThrownTypes) | |
| .release(); | |
| } | |
| DISubprogram *DIBuilder::createMethod( | |
| DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, | |
| unsigned LineNo, DISubroutineType *Ty, unsigned VIndex, int ThisAdjustment, | |
| DIType *VTableHolder, DINode::DIFlags Flags, | |
| DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams, | |
| DITypeArray ThrownTypes, bool UseKeyInstructions) { | |
| assert(getNonCompileUnitScope(Context) && | |
| "Methods should have both a Context and a context that isn't " | |
| "the compile unit."); | |
| // FIXME: Do we want to use different scope/lines? | |
| bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; | |
| auto *SP = getSubprogram( | |
| /*IsDistinct=*/IsDefinition, VMContext, cast<DIScope>(Context), Name, | |
| LinkageName, F, LineNo, Ty, LineNo, VTableHolder, VIndex, ThisAdjustment, | |
| Flags, SPFlags, IsDefinition ? CUNode : nullptr, TParams, nullptr, | |
| nullptr, ThrownTypes, nullptr, "", IsDefinition && UseKeyInstructions); | |
| AllSubprograms.push_back(SP); | |
| trackIfUnresolved(SP); | |
| return SP; | |
| } | |
| DICommonBlock *DIBuilder::createCommonBlock(DIScope *Scope, | |
| DIGlobalVariable *Decl, | |
| StringRef Name, DIFile *File, | |
| unsigned LineNo) { | |
| return DICommonBlock::get(VMContext, Scope, Decl, Name, File, LineNo); | |
| } | |
| DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name, | |
| bool ExportSymbols) { | |
| // It is okay to *not* make anonymous top-level namespaces distinct, because | |
| // all nodes that have an anonymous namespace as their parent scope are | |
| // guaranteed to be unique and/or are linked to their containing | |
| // DICompileUnit. This decision is an explicit tradeoff of link time versus | |
| // memory usage versus code simplicity and may get revisited in the future. | |
| return DINamespace::get(VMContext, getNonCompileUnitScope(Scope), Name, | |
| ExportSymbols); | |
| } | |
| DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, | |
| StringRef ConfigurationMacros, | |
| StringRef IncludePath, StringRef APINotesFile, | |
| DIFile *File, unsigned LineNo, bool IsDecl) { | |
| return DIModule::get(VMContext, File, getNonCompileUnitScope(Scope), Name, | |
| ConfigurationMacros, IncludePath, APINotesFile, LineNo, | |
| IsDecl); | |
| } | |
| DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, | |
| DIFile *File, | |
| unsigned Discriminator) { | |
| return DILexicalBlockFile::get(VMContext, Scope, File, Discriminator); | |
| } | |
| DILexicalBlock *DIBuilder::createLexicalBlock(DIScope *Scope, DIFile *File, | |
| unsigned Line, unsigned Col) { | |
| // Make these distinct, to avoid merging two lexical blocks on the same | |
| // file/line/column. | |
| return DILexicalBlock::getDistinct(VMContext, getNonCompileUnitScope(Scope), | |
| File, Line, Col); | |
| } | |
| DbgRecord *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, | |
| DIExpression *Expr, const DILocation *DL, | |
| BasicBlock *InsertAtEnd) { | |
| // If this block already has a terminator then insert this record before | |
| // the terminator. Otherwise, put it at the end of the block. | |
| Instruction *InsertBefore = InsertAtEnd->getTerminatorOrNull(); | |
| return insertDeclare(Storage, VarInfo, Expr, DL, | |
| InsertBefore ? InsertBefore->getIterator() | |
| : InsertAtEnd->end()); | |
| } | |
| DbgRecord *DIBuilder::insertDbgAssign(Instruction *LinkedInstr, Value *Val, | |
| DILocalVariable *SrcVar, | |
| DIExpression *ValExpr, Value *Addr, | |
| DIExpression *AddrExpr, | |
| const DILocation *DL) { | |
| auto *Link = cast_or_null<DIAssignID>( | |
| LinkedInstr->getMetadata(LLVMContext::MD_DIAssignID)); | |
| assert(Link && "Linked instruction must have DIAssign metadata attached"); | |
| DbgVariableRecord *DVR = DbgVariableRecord::createDVRAssign( | |
| Val, SrcVar, ValExpr, Link, Addr, AddrExpr, DL); | |
| // Insert after LinkedInstr. | |
| BasicBlock::iterator NextIt = std::next(LinkedInstr->getIterator()); | |
| NextIt.setHeadBit(true); | |
| insertDbgVariableRecord(DVR, NextIt); | |
| return DVR; | |
| } | |
| DbgRecord *DIBuilder::insertDbgValue(Value *Val, DILocalVariable *VarInfo, | |
| DIExpression *Expr, const DILocation *DL, | |
| InsertPosition InsertPt) { | |
| DbgVariableRecord *DVR = | |
| DbgVariableRecord::createDbgVariableRecord(Val, VarInfo, Expr, DL); | |
| insertDbgVariableRecord(DVR, InsertPt); | |
| return DVR; | |
| } | |
| DbgRecord *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, | |
| DIExpression *Expr, const DILocation *DL, | |
| InsertPosition InsertPt) { | |
| assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.declare"); | |
| assert(DL && "Expected debug loc"); | |
| assert(DL->getScope()->getSubprogram() == | |
| VarInfo->getScope()->getSubprogram() && | |
| "Expected matching subprograms"); | |
| DbgVariableRecord *DVR = | |
| DbgVariableRecord::createDVRDeclare(Storage, VarInfo, Expr, DL); | |
| insertDbgVariableRecord(DVR, InsertPt); | |
| return DVR; | |
| } | |
| DbgRecord *DIBuilder::insertDeclareValue(Value *Storage, | |
| DILocalVariable *VarInfo, | |
| DIExpression *Expr, | |
| const DILocation *DL, | |
| InsertPosition InsertPt) { | |
| assert(VarInfo && | |
| "empty or invalid DILocalVariable* passed to dbg.declare_value"); | |
| assert(DL && "Expected debug loc"); | |
| assert(DL->getScope()->getSubprogram() == | |
| VarInfo->getScope()->getSubprogram() && | |
| "Expected matching subprograms"); | |
| DbgVariableRecord *DVR = | |
| DbgVariableRecord::createDVRDeclareValue(Storage, VarInfo, Expr, DL); | |
| insertDbgVariableRecord(DVR, InsertPt); | |
| return DVR; | |
| } | |
| void DIBuilder::insertDbgVariableRecord(DbgVariableRecord *DVR, | |
| InsertPosition InsertPt) { | |
| assert(InsertPt.isValid()); | |
| trackIfUnresolved(DVR->getVariable()); | |
| trackIfUnresolved(DVR->getExpression()); | |
| if (DVR->isDbgAssign()) | |
| trackIfUnresolved(DVR->getAddressExpression()); | |
| auto *BB = InsertPt.getBasicBlock(); | |
| BB->insertDbgRecordBefore(DVR, InsertPt); | |
| } | |
| DbgRecord *DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL, | |
| InsertPosition InsertPt) { | |
| assert(LabelInfo && "empty or invalid DILabel* passed to dbg.label"); | |
| assert(DL && "Expected debug loc"); | |
| assert(DL->getScope()->getSubprogram() == | |
| LabelInfo->getScope()->getSubprogram() && | |
| "Expected matching subprograms"); | |
| trackIfUnresolved(LabelInfo); | |
| DbgLabelRecord *DLR = new DbgLabelRecord(LabelInfo, DL); | |
| if (InsertPt.isValid()) { | |
| auto *BB = InsertPt.getBasicBlock(); | |
| BB->insertDbgRecordBefore(DLR, InsertPt); | |
| } | |
| return DLR; | |
| } | |
| void DIBuilder::replaceVTableHolder(DICompositeType *&T, DIType *VTableHolder) { | |
| { | |
| TypedTrackingMDRef<DICompositeType> N(T); | |
| N->replaceVTableHolder(VTableHolder); | |
| T = N.get(); | |
| } | |
| // If this didn't create a self-reference, just return. | |
| if (T != VTableHolder) | |
| return; | |
| // Look for unresolved operands. T will drop RAUW support, orphaning any | |
| // cycles underneath it. | |
| if (T->isResolved()) | |
| for (const MDOperand &O : T->operands()) | |
| if (auto *N = dyn_cast_or_null<MDNode>(O)) | |
| trackIfUnresolved(N); | |
| } | |
| void DIBuilder::replaceArrays(DICompositeType *&T, DINodeArray Elements, | |
| DINodeArray TParams) { | |
| { | |
| TypedTrackingMDRef<DICompositeType> N(T); | |
| if (Elements) | |
| N->replaceElements(Elements); | |
| if (TParams) | |
| N->replaceTemplateParams(DITemplateParameterArray(TParams)); | |
| T = N.get(); | |
| } | |
| // If T isn't resolved, there's no problem. | |
| if (!T->isResolved()) | |
| return; | |
| // If T is resolved, it may be due to a self-reference cycle. Track the | |
| // arrays explicitly if they're unresolved, or else the cycles will be | |
| // orphaned. | |
| if (Elements) | |
| trackIfUnresolved(Elements.get()); | |
| if (TParams) | |
| trackIfUnresolved(TParams.get()); | |
| } |