1 | //===--- DIBuilder.cpp - Debug Information Builder ------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the DIBuilder. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/IR/DIBuilder.h" |
14 | #include "LLVMContextImpl.h" |
15 | #include "llvm/ADT/APInt.h" |
16 | #include "llvm/ADT/APSInt.h" |
17 | #include "llvm/BinaryFormat/Dwarf.h" |
18 | #include "llvm/IR/Constants.h" |
19 | #include "llvm/IR/DebugInfo.h" |
20 | #include "llvm/IR/IRBuilder.h" |
21 | #include "llvm/IR/Module.h" |
22 | #include "llvm/Support/CommandLine.h" |
23 | #include <optional> |
24 | |
25 | using namespace llvm; |
26 | using namespace llvm::dwarf; |
27 | |
28 | DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU) |
29 | : M(m), VMContext(M.getContext()), CUNode(CU), DeclareFn(nullptr), |
30 | ValueFn(nullptr), LabelFn(nullptr), AssignFn(nullptr), |
31 | AllowUnresolvedNodes(AllowUnresolvedNodes) { |
32 | if (CUNode) { |
33 | if (const auto &ETs = CUNode->getEnumTypes()) |
34 | AllEnumTypes.assign(in_start: ETs.begin(), in_end: ETs.end()); |
35 | if (const auto &RTs = CUNode->getRetainedTypes()) |
36 | AllRetainTypes.assign(in_start: RTs.begin(), in_end: RTs.end()); |
37 | if (const auto &GVs = CUNode->getGlobalVariables()) |
38 | AllGVs.assign(in_start: GVs.begin(), in_end: GVs.end()); |
39 | if (const auto &IMs = CUNode->getImportedEntities()) |
40 | ImportedModules.assign(in_start: IMs.begin(), in_end: IMs.end()); |
41 | if (const auto &MNs = CUNode->getMacros()) |
42 | AllMacrosPerParent.insert(KV: {nullptr, {MNs.begin(), MNs.end()}}); |
43 | } |
44 | } |
45 | |
46 | void DIBuilder::trackIfUnresolved(MDNode *N) { |
47 | if (!N) |
48 | return; |
49 | if (N->isResolved()) |
50 | return; |
51 | |
52 | assert(AllowUnresolvedNodes && "Cannot handle unresolved nodes" ); |
53 | UnresolvedNodes.emplace_back(Args&: N); |
54 | } |
55 | |
56 | void DIBuilder::finalizeSubprogram(DISubprogram *SP) { |
57 | auto PN = SubprogramTrackedNodes.find(Val: SP); |
58 | if (PN != SubprogramTrackedNodes.end()) |
59 | SP->replaceRetainedNodes( |
60 | N: MDTuple::get(Context&: VMContext, MDs: SmallVector<Metadata *, 16>(PN->second.begin(), |
61 | PN->second.end()))); |
62 | } |
63 | |
64 | void DIBuilder::finalize() { |
65 | if (!CUNode) { |
66 | assert(!AllowUnresolvedNodes && |
67 | "creating type nodes without a CU is not supported" ); |
68 | return; |
69 | } |
70 | |
71 | if (!AllEnumTypes.empty()) |
72 | CUNode->replaceEnumTypes(N: MDTuple::get( |
73 | Context&: VMContext, MDs: SmallVector<Metadata *, 16>(AllEnumTypes.begin(), |
74 | AllEnumTypes.end()))); |
75 | |
76 | SmallVector<Metadata *, 16> RetainValues; |
77 | // Declarations and definitions of the same type may be retained. Some |
78 | // clients RAUW these pairs, leaving duplicates in the retained types |
79 | // list. Use a set to remove the duplicates while we transform the |
80 | // TrackingVHs back into Values. |
81 | SmallPtrSet<Metadata *, 16> RetainSet; |
82 | for (const TrackingMDNodeRef &N : AllRetainTypes) |
83 | if (RetainSet.insert(Ptr: N).second) |
84 | RetainValues.push_back(Elt: N); |
85 | |
86 | if (!RetainValues.empty()) |
87 | CUNode->replaceRetainedTypes(N: MDTuple::get(Context&: VMContext, MDs: RetainValues)); |
88 | |
89 | for (auto *SP : AllSubprograms) |
90 | finalizeSubprogram(SP); |
91 | for (auto *N : RetainValues) |
92 | if (auto *SP = dyn_cast<DISubprogram>(Val: N)) |
93 | finalizeSubprogram(SP); |
94 | |
95 | if (!AllGVs.empty()) |
96 | CUNode->replaceGlobalVariables(N: MDTuple::get(Context&: VMContext, MDs: AllGVs)); |
97 | |
98 | if (!ImportedModules.empty()) |
99 | CUNode->replaceImportedEntities(N: MDTuple::get( |
100 | Context&: VMContext, MDs: SmallVector<Metadata *, 16>(ImportedModules.begin(), |
101 | ImportedModules.end()))); |
102 | |
103 | for (const auto &I : AllMacrosPerParent) { |
104 | // DIMacroNode's with nullptr parent are DICompileUnit direct children. |
105 | if (!I.first) { |
106 | CUNode->replaceMacros(N: MDTuple::get(Context&: VMContext, MDs: I.second.getArrayRef())); |
107 | continue; |
108 | } |
109 | // Otherwise, it must be a temporary DIMacroFile that need to be resolved. |
110 | auto *TMF = cast<DIMacroFile>(Val: I.first); |
111 | auto *MF = DIMacroFile::get(Context&: VMContext, MIType: dwarf::DW_MACINFO_start_file, |
112 | Line: TMF->getLine(), File: TMF->getFile(), |
113 | Elements: getOrCreateMacroArray(Elements: I.second.getArrayRef())); |
114 | replaceTemporary(N: llvm::TempDIMacroNode(TMF), Replacement: MF); |
115 | } |
116 | |
117 | // Now that all temp nodes have been replaced or deleted, resolve remaining |
118 | // cycles. |
119 | for (const auto &N : UnresolvedNodes) |
120 | if (N && !N->isResolved()) |
121 | N->resolveCycles(); |
122 | UnresolvedNodes.clear(); |
123 | |
124 | // Can't handle unresolved nodes anymore. |
125 | AllowUnresolvedNodes = false; |
126 | } |
127 | |
128 | /// If N is compile unit return NULL otherwise return N. |
129 | static DIScope *getNonCompileUnitScope(DIScope *N) { |
130 | if (!N || isa<DICompileUnit>(Val: N)) |
131 | return nullptr; |
132 | return cast<DIScope>(Val: N); |
133 | } |
134 | |
135 | DICompileUnit *DIBuilder::createCompileUnit( |
136 | unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, |
137 | StringRef Flags, unsigned RunTimeVer, StringRef SplitName, |
138 | DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, |
139 | bool SplitDebugInlining, bool DebugInfoForProfiling, |
140 | DICompileUnit::DebugNameTableKind NameTableKind, bool RangesBaseAddress, |
141 | StringRef SysRoot, StringRef SDK) { |
142 | |
143 | assert(((Lang <= dwarf::DW_LANG_Mojo && Lang >= dwarf::DW_LANG_C89) || |
144 | (Lang <= dwarf::DW_LANG_hi_user && Lang >= dwarf::DW_LANG_lo_user)) && |
145 | "Invalid Language tag" ); |
146 | |
147 | assert(!CUNode && "Can only make one compile unit per DIBuilder instance" ); |
148 | CUNode = DICompileUnit::getDistinct( |
149 | Context&: VMContext, SourceLanguage: Lang, File, Producer, IsOptimized: isOptimized, Flags, RuntimeVersion: RunTimeVer, |
150 | SplitDebugFilename: SplitName, EmissionKind: Kind, EnumTypes: nullptr, RetainedTypes: nullptr, GlobalVariables: nullptr, ImportedEntities: nullptr, Macros: nullptr, DWOId, |
151 | SplitDebugInlining, DebugInfoForProfiling, NameTableKind, |
152 | RangesBaseAddress, SysRoot, SDK); |
153 | |
154 | // Create a named metadata so that it is easier to find cu in a module. |
155 | NamedMDNode *NMD = M.getOrInsertNamedMetadata(Name: "llvm.dbg.cu" ); |
156 | NMD->addOperand(M: CUNode); |
157 | trackIfUnresolved(N: CUNode); |
158 | return CUNode; |
159 | } |
160 | |
161 | static DIImportedEntity * |
162 | createImportedModule(LLVMContext &C, dwarf::Tag Tag, DIScope *Context, |
163 | Metadata *NS, DIFile *File, unsigned Line, StringRef Name, |
164 | DINodeArray Elements, |
165 | SmallVectorImpl<TrackingMDNodeRef> &ImportedModules) { |
166 | if (Line) |
167 | assert(File && "Source location has line number but no file" ); |
168 | unsigned EntitiesCount = C.pImpl->DIImportedEntitys.size(); |
169 | auto *M = DIImportedEntity::get(Context&: C, Tag, Scope: Context, Entity: cast_or_null<DINode>(Val: NS), |
170 | File, Line, Name, Elements); |
171 | if (EntitiesCount < C.pImpl->DIImportedEntitys.size()) |
172 | // A new Imported Entity was just added to the context. |
173 | // Add it to the Imported Modules list. |
174 | ImportedModules.emplace_back(Args&: M); |
175 | return M; |
176 | } |
177 | |
178 | DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, |
179 | DINamespace *NS, DIFile *File, |
180 | unsigned Line, |
181 | DINodeArray Elements) { |
182 | return ::createImportedModule(C&: VMContext, Tag: dwarf::DW_TAG_imported_module, |
183 | Context, NS, File, Line, Name: StringRef(), Elements, |
184 | ImportedModules&: getImportTrackingVector(S: Context)); |
185 | } |
186 | |
187 | DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, |
188 | DIImportedEntity *NS, |
189 | DIFile *File, unsigned Line, |
190 | DINodeArray Elements) { |
191 | return ::createImportedModule(C&: VMContext, Tag: dwarf::DW_TAG_imported_module, |
192 | Context, NS, File, Line, Name: StringRef(), Elements, |
193 | ImportedModules&: getImportTrackingVector(S: Context)); |
194 | } |
195 | |
196 | DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, DIModule *M, |
197 | DIFile *File, unsigned Line, |
198 | DINodeArray Elements) { |
199 | return ::createImportedModule(C&: VMContext, Tag: dwarf::DW_TAG_imported_module, |
200 | Context, NS: M, File, Line, Name: StringRef(), Elements, |
201 | ImportedModules&: getImportTrackingVector(S: Context)); |
202 | } |
203 | |
204 | DIImportedEntity * |
205 | DIBuilder::createImportedDeclaration(DIScope *Context, DINode *Decl, |
206 | DIFile *File, unsigned Line, |
207 | StringRef Name, DINodeArray Elements) { |
208 | // Make sure to use the unique identifier based metadata reference for |
209 | // types that have one. |
210 | return ::createImportedModule(C&: VMContext, Tag: dwarf::DW_TAG_imported_declaration, |
211 | Context, NS: Decl, File, Line, Name, Elements, |
212 | ImportedModules&: getImportTrackingVector(S: Context)); |
213 | } |
214 | |
215 | DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory, |
216 | std::optional<DIFile::ChecksumInfo<StringRef>> CS, |
217 | std::optional<StringRef> Source) { |
218 | return DIFile::get(Context&: VMContext, Filename, Directory, CS, Source); |
219 | } |
220 | |
221 | DIMacro *DIBuilder::createMacro(DIMacroFile *Parent, unsigned LineNumber, |
222 | unsigned MacroType, StringRef Name, |
223 | StringRef Value) { |
224 | assert(!Name.empty() && "Unable to create macro without name" ); |
225 | assert((MacroType == dwarf::DW_MACINFO_undef || |
226 | MacroType == dwarf::DW_MACINFO_define) && |
227 | "Unexpected macro type" ); |
228 | auto *M = DIMacro::get(Context&: VMContext, MIType: MacroType, Line: LineNumber, Name, Value); |
229 | AllMacrosPerParent[Parent].insert(X: M); |
230 | return M; |
231 | } |
232 | |
233 | DIMacroFile *DIBuilder::createTempMacroFile(DIMacroFile *Parent, |
234 | unsigned LineNumber, DIFile *File) { |
235 | auto *MF = DIMacroFile::getTemporary(Context&: VMContext, MIType: dwarf::DW_MACINFO_start_file, |
236 | Line: LineNumber, File, Elements: DIMacroNodeArray()) |
237 | .release(); |
238 | AllMacrosPerParent[Parent].insert(X: MF); |
239 | // Add the new temporary DIMacroFile to the macro per parent map as a parent. |
240 | // This is needed to assure DIMacroFile with no children to have an entry in |
241 | // the map. Otherwise, it will not be resolved in DIBuilder::finalize(). |
242 | AllMacrosPerParent.insert(KV: {MF, {}}); |
243 | return MF; |
244 | } |
245 | |
246 | DIEnumerator *DIBuilder::createEnumerator(StringRef Name, uint64_t Val, |
247 | bool IsUnsigned) { |
248 | assert(!Name.empty() && "Unable to create enumerator without name" ); |
249 | return DIEnumerator::get(Context&: VMContext, Value: APInt(64, Val, !IsUnsigned), IsUnsigned, |
250 | Name); |
251 | } |
252 | |
253 | DIEnumerator *DIBuilder::createEnumerator(StringRef Name, const APSInt &Value) { |
254 | assert(!Name.empty() && "Unable to create enumerator without name" ); |
255 | return DIEnumerator::get(Context&: VMContext, Value: APInt(Value), IsUnsigned: Value.isUnsigned(), Name); |
256 | } |
257 | |
258 | DIBasicType *DIBuilder::createUnspecifiedType(StringRef Name) { |
259 | assert(!Name.empty() && "Unable to create type without name" ); |
260 | return DIBasicType::get(Context&: VMContext, Tag: dwarf::DW_TAG_unspecified_type, Name); |
261 | } |
262 | |
263 | DIBasicType *DIBuilder::createNullPtrType() { |
264 | return createUnspecifiedType(Name: "decltype(nullptr)" ); |
265 | } |
266 | |
267 | DIBasicType *DIBuilder::createBasicType(StringRef Name, uint64_t SizeInBits, |
268 | unsigned Encoding, |
269 | DINode::DIFlags Flags) { |
270 | assert(!Name.empty() && "Unable to create type without name" ); |
271 | return DIBasicType::get(Context&: VMContext, Tag: dwarf::DW_TAG_base_type, Name, SizeInBits, |
272 | AlignInBits: 0, Encoding, Flags); |
273 | } |
274 | |
275 | DIStringType *DIBuilder::createStringType(StringRef Name, uint64_t SizeInBits) { |
276 | assert(!Name.empty() && "Unable to create type without name" ); |
277 | return DIStringType::get(Context&: VMContext, Tag: dwarf::DW_TAG_string_type, Name, |
278 | SizeInBits, AlignInBits: 0); |
279 | } |
280 | |
281 | DIStringType *DIBuilder::createStringType(StringRef Name, |
282 | DIVariable *StringLength, |
283 | DIExpression *StrLocationExp) { |
284 | assert(!Name.empty() && "Unable to create type without name" ); |
285 | return DIStringType::get(Context&: VMContext, Tag: dwarf::DW_TAG_string_type, Name, |
286 | StringLength, StringLengthExp: nullptr, StringLocationExp: StrLocationExp, SizeInBits: 0, AlignInBits: 0, Encoding: 0); |
287 | } |
288 | |
289 | DIStringType *DIBuilder::createStringType(StringRef Name, |
290 | DIExpression *StringLengthExp, |
291 | DIExpression *StrLocationExp) { |
292 | assert(!Name.empty() && "Unable to create type without name" ); |
293 | return DIStringType::get(Context&: VMContext, Tag: dwarf::DW_TAG_string_type, Name, StringLength: nullptr, |
294 | StringLengthExp, StringLocationExp: StrLocationExp, SizeInBits: 0, AlignInBits: 0, Encoding: 0); |
295 | } |
296 | |
297 | DIDerivedType *DIBuilder::createQualifiedType(unsigned Tag, DIType *FromTy) { |
298 | return DIDerivedType::get(Context&: VMContext, Tag, Name: "" , File: nullptr, Line: 0, Scope: nullptr, BaseType: FromTy, SizeInBits: 0, |
299 | AlignInBits: 0, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags: DINode::FlagZero); |
300 | } |
301 | |
302 | DIDerivedType *DIBuilder::createPtrAuthQualifiedType( |
303 | DIType *FromTy, unsigned Key, bool IsAddressDiscriminated, |
304 | unsigned , bool IsaPointer, |
305 | bool AuthenticatesNullValues) { |
306 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_LLVM_ptrauth_type, Name: "" , |
307 | File: nullptr, Line: 0, Scope: nullptr, BaseType: FromTy, SizeInBits: 0, AlignInBits: 0, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, |
308 | PtrAuthData: std::optional<DIDerivedType::PtrAuthData>( |
309 | std::in_place, Key, IsAddressDiscriminated, |
310 | ExtraDiscriminator, IsaPointer, |
311 | AuthenticatesNullValues), |
312 | Flags: DINode::FlagZero); |
313 | } |
314 | |
315 | DIDerivedType * |
316 | DIBuilder::createPointerType(DIType *PointeeTy, uint64_t SizeInBits, |
317 | uint32_t AlignInBits, |
318 | std::optional<unsigned> DWARFAddressSpace, |
319 | StringRef Name, DINodeArray Annotations) { |
320 | // FIXME: Why is there a name here? |
321 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_pointer_type, Name, |
322 | File: nullptr, Line: 0, Scope: nullptr, BaseType: PointeeTy, SizeInBits, |
323 | AlignInBits, OffsetInBits: 0, DWARFAddressSpace, PtrAuthData: std::nullopt, |
324 | Flags: DINode::FlagZero, ExtraData: nullptr, Annotations); |
325 | } |
326 | |
327 | DIDerivedType *DIBuilder::createMemberPointerType(DIType *PointeeTy, |
328 | DIType *Base, |
329 | uint64_t SizeInBits, |
330 | uint32_t AlignInBits, |
331 | DINode::DIFlags Flags) { |
332 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_ptr_to_member_type, Name: "" , |
333 | File: nullptr, Line: 0, Scope: nullptr, BaseType: PointeeTy, SizeInBits, |
334 | AlignInBits, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags, |
335 | ExtraData: Base); |
336 | } |
337 | |
338 | DIDerivedType * |
339 | DIBuilder::createReferenceType(unsigned Tag, DIType *RTy, uint64_t SizeInBits, |
340 | uint32_t AlignInBits, |
341 | std::optional<unsigned> DWARFAddressSpace) { |
342 | assert(RTy && "Unable to create reference type" ); |
343 | return DIDerivedType::get(Context&: VMContext, Tag, Name: "" , File: nullptr, Line: 0, Scope: nullptr, BaseType: RTy, |
344 | SizeInBits, AlignInBits, OffsetInBits: 0, DWARFAddressSpace, PtrAuthData: {}, |
345 | Flags: DINode::FlagZero); |
346 | } |
347 | |
348 | DIDerivedType *DIBuilder::createTypedef(DIType *Ty, StringRef Name, |
349 | DIFile *File, unsigned LineNo, |
350 | DIScope *Context, uint32_t AlignInBits, |
351 | DINode::DIFlags Flags, |
352 | DINodeArray Annotations) { |
353 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_typedef, Name, File, |
354 | Line: LineNo, Scope: getNonCompileUnitScope(N: Context), BaseType: Ty, SizeInBits: 0, |
355 | AlignInBits, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags, |
356 | ExtraData: nullptr, Annotations); |
357 | } |
358 | |
359 | DIDerivedType * |
360 | DIBuilder::createTemplateAlias(DIType *Ty, StringRef Name, DIFile *File, |
361 | unsigned LineNo, DIScope *Context, |
362 | DINodeArray TParams, uint32_t AlignInBits, |
363 | DINode::DIFlags Flags, DINodeArray Annotations) { |
364 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_template_alias, Name, File, |
365 | Line: LineNo, Scope: getNonCompileUnitScope(N: Context), BaseType: Ty, SizeInBits: 0, |
366 | AlignInBits, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags, |
367 | ExtraData: TParams.get(), Annotations); |
368 | } |
369 | |
370 | DIDerivedType *DIBuilder::createFriend(DIType *Ty, DIType *FriendTy) { |
371 | assert(Ty && "Invalid type!" ); |
372 | assert(FriendTy && "Invalid friend type!" ); |
373 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_friend, Name: "" , File: nullptr, Line: 0, Scope: Ty, |
374 | BaseType: FriendTy, SizeInBits: 0, AlignInBits: 0, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, |
375 | Flags: DINode::FlagZero); |
376 | } |
377 | |
378 | DIDerivedType *DIBuilder::createInheritance(DIType *Ty, DIType *BaseTy, |
379 | uint64_t BaseOffset, |
380 | uint32_t VBPtrOffset, |
381 | DINode::DIFlags Flags) { |
382 | assert(Ty && "Unable to create inheritance" ); |
383 | Metadata * = ConstantAsMetadata::get( |
384 | C: ConstantInt::get(Ty: IntegerType::get(C&: VMContext, NumBits: 32), V: VBPtrOffset)); |
385 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_inheritance, Name: "" , File: nullptr, |
386 | Line: 0, Scope: Ty, BaseType: BaseTy, SizeInBits: 0, AlignInBits: 0, OffsetInBits: BaseOffset, DWARFAddressSpace: std::nullopt, |
387 | PtrAuthData: std::nullopt, Flags, ExtraData); |
388 | } |
389 | |
390 | DIDerivedType *DIBuilder::createMemberType( |
391 | DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, |
392 | uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, |
393 | DINode::DIFlags Flags, DIType *Ty, DINodeArray Annotations) { |
394 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_member, Name, File, |
395 | Line: LineNumber, Scope: getNonCompileUnitScope(N: Scope), BaseType: Ty, |
396 | SizeInBits, AlignInBits, OffsetInBits, DWARFAddressSpace: std::nullopt, |
397 | PtrAuthData: std::nullopt, Flags, ExtraData: nullptr, Annotations); |
398 | } |
399 | |
400 | static ConstantAsMetadata *getConstantOrNull(Constant *C) { |
401 | if (C) |
402 | return ConstantAsMetadata::get(C); |
403 | return nullptr; |
404 | } |
405 | |
406 | DIDerivedType *DIBuilder::createVariantMemberType( |
407 | DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, |
408 | uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, |
409 | Constant *Discriminant, DINode::DIFlags Flags, DIType *Ty) { |
410 | return DIDerivedType::get( |
411 | Context&: VMContext, Tag: dwarf::DW_TAG_member, Name, File, Line: LineNumber, |
412 | Scope: getNonCompileUnitScope(N: Scope), BaseType: Ty, SizeInBits, AlignInBits, OffsetInBits, |
413 | DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags, ExtraData: getConstantOrNull(C: Discriminant)); |
414 | } |
415 | |
416 | DIDerivedType *DIBuilder::createBitFieldMemberType( |
417 | DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, |
418 | uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits, |
419 | DINode::DIFlags Flags, DIType *Ty, DINodeArray Annotations) { |
420 | Flags |= DINode::FlagBitField; |
421 | return DIDerivedType::get( |
422 | Context&: VMContext, Tag: dwarf::DW_TAG_member, Name, File, Line: LineNumber, |
423 | Scope: getNonCompileUnitScope(N: Scope), BaseType: Ty, SizeInBits, /*AlignInBits=*/0, |
424 | OffsetInBits, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags, |
425 | ExtraData: ConstantAsMetadata::get(C: ConstantInt::get(Ty: IntegerType::get(C&: VMContext, NumBits: 64), |
426 | V: StorageOffsetInBits)), |
427 | Annotations); |
428 | } |
429 | |
430 | DIDerivedType * |
431 | DIBuilder::createStaticMemberType(DIScope *Scope, StringRef Name, DIFile *File, |
432 | unsigned LineNumber, DIType *Ty, |
433 | DINode::DIFlags Flags, llvm::Constant *Val, |
434 | unsigned Tag, uint32_t AlignInBits) { |
435 | Flags |= DINode::FlagStaticMember; |
436 | return DIDerivedType::get(Context&: VMContext, Tag, Name, File, Line: LineNumber, |
437 | Scope: getNonCompileUnitScope(N: Scope), BaseType: Ty, SizeInBits: 0, AlignInBits, |
438 | OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: std::nullopt, Flags, |
439 | ExtraData: getConstantOrNull(C: Val)); |
440 | } |
441 | |
442 | DIDerivedType * |
443 | DIBuilder::createObjCIVar(StringRef Name, DIFile *File, unsigned LineNumber, |
444 | uint64_t SizeInBits, uint32_t AlignInBits, |
445 | uint64_t OffsetInBits, DINode::DIFlags Flags, |
446 | DIType *Ty, MDNode *PropertyNode) { |
447 | return DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_member, Name, File, |
448 | Line: LineNumber, Scope: getNonCompileUnitScope(N: File), BaseType: Ty, |
449 | SizeInBits, AlignInBits, OffsetInBits, DWARFAddressSpace: std::nullopt, |
450 | PtrAuthData: std::nullopt, Flags, ExtraData: PropertyNode); |
451 | } |
452 | |
453 | DIObjCProperty * |
454 | DIBuilder::createObjCProperty(StringRef Name, DIFile *File, unsigned LineNumber, |
455 | StringRef GetterName, StringRef SetterName, |
456 | unsigned PropertyAttributes, DIType *Ty) { |
457 | return DIObjCProperty::get(Context&: VMContext, Name, File, Line: LineNumber, GetterName, |
458 | SetterName, Attributes: PropertyAttributes, Type: Ty); |
459 | } |
460 | |
461 | DITemplateTypeParameter * |
462 | DIBuilder::createTemplateTypeParameter(DIScope *Context, StringRef Name, |
463 | DIType *Ty, bool isDefault) { |
464 | assert((!Context || isa<DICompileUnit>(Context)) && "Expected compile unit" ); |
465 | return DITemplateTypeParameter::get(Context&: VMContext, Name, Type: Ty, IsDefault: isDefault); |
466 | } |
467 | |
468 | static DITemplateValueParameter * |
469 | createTemplateValueParameterHelper(LLVMContext &VMContext, unsigned Tag, |
470 | DIScope *Context, StringRef Name, DIType *Ty, |
471 | bool IsDefault, Metadata *MD) { |
472 | assert((!Context || isa<DICompileUnit>(Context)) && "Expected compile unit" ); |
473 | return DITemplateValueParameter::get(Context&: VMContext, Tag, Name, Type: Ty, IsDefault, Value: MD); |
474 | } |
475 | |
476 | DITemplateValueParameter * |
477 | DIBuilder::createTemplateValueParameter(DIScope *Context, StringRef Name, |
478 | DIType *Ty, bool isDefault, |
479 | Constant *Val) { |
480 | return createTemplateValueParameterHelper( |
481 | VMContext, Tag: dwarf::DW_TAG_template_value_parameter, Context, Name, Ty, |
482 | IsDefault: isDefault, MD: getConstantOrNull(C: Val)); |
483 | } |
484 | |
485 | DITemplateValueParameter * |
486 | DIBuilder::createTemplateTemplateParameter(DIScope *Context, StringRef Name, |
487 | DIType *Ty, StringRef Val, |
488 | bool IsDefault) { |
489 | return createTemplateValueParameterHelper( |
490 | VMContext, Tag: dwarf::DW_TAG_GNU_template_template_param, Context, Name, Ty, |
491 | IsDefault, MD: MDString::get(Context&: VMContext, Str: Val)); |
492 | } |
493 | |
494 | DITemplateValueParameter * |
495 | DIBuilder::createTemplateParameterPack(DIScope *Context, StringRef Name, |
496 | DIType *Ty, DINodeArray Val) { |
497 | return createTemplateValueParameterHelper( |
498 | VMContext, Tag: dwarf::DW_TAG_GNU_template_parameter_pack, Context, Name, Ty, |
499 | IsDefault: false, MD: Val.get()); |
500 | } |
501 | |
502 | DICompositeType *DIBuilder::createClassType( |
503 | DIScope *Context, StringRef Name, DIFile *File, unsigned LineNumber, |
504 | uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, |
505 | DINode::DIFlags Flags, DIType *DerivedFrom, DINodeArray Elements, |
506 | unsigned RunTimeLang, DIType *VTableHolder, MDNode *TemplateParams, |
507 | StringRef UniqueIdentifier) { |
508 | assert((!Context || isa<DIScope>(Context)) && |
509 | "createClassType should be called with a valid Context" ); |
510 | |
511 | auto *R = DICompositeType::get( |
512 | Context&: VMContext, Tag: dwarf::DW_TAG_structure_type, Name, File, Line: LineNumber, |
513 | Scope: getNonCompileUnitScope(N: Context), BaseType: DerivedFrom, SizeInBits, AlignInBits, |
514 | OffsetInBits, Flags, Elements, RuntimeLang: RunTimeLang, VTableHolder, |
515 | TemplateParams: cast_or_null<MDTuple>(Val: TemplateParams), Identifier: UniqueIdentifier); |
516 | trackIfUnresolved(N: R); |
517 | return R; |
518 | } |
519 | |
520 | DICompositeType *DIBuilder::createStructType( |
521 | DIScope *Context, StringRef Name, DIFile *File, unsigned LineNumber, |
522 | uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, |
523 | DIType *DerivedFrom, DINodeArray Elements, unsigned RunTimeLang, |
524 | DIType *VTableHolder, StringRef UniqueIdentifier) { |
525 | auto *R = DICompositeType::get( |
526 | Context&: VMContext, Tag: dwarf::DW_TAG_structure_type, Name, File, Line: LineNumber, |
527 | Scope: getNonCompileUnitScope(N: Context), BaseType: DerivedFrom, SizeInBits, AlignInBits, OffsetInBits: 0, |
528 | Flags, Elements, RuntimeLang: RunTimeLang, VTableHolder, TemplateParams: nullptr, Identifier: UniqueIdentifier); |
529 | trackIfUnresolved(N: R); |
530 | return R; |
531 | } |
532 | |
533 | DICompositeType *DIBuilder::createUnionType( |
534 | DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, |
535 | uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, |
536 | DINodeArray Elements, unsigned RunTimeLang, StringRef UniqueIdentifier) { |
537 | auto *R = DICompositeType::get( |
538 | Context&: VMContext, Tag: dwarf::DW_TAG_union_type, Name, File, Line: LineNumber, |
539 | Scope: getNonCompileUnitScope(N: Scope), BaseType: nullptr, SizeInBits, AlignInBits, OffsetInBits: 0, Flags, |
540 | Elements, RuntimeLang: RunTimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier: UniqueIdentifier); |
541 | trackIfUnresolved(N: R); |
542 | return R; |
543 | } |
544 | |
545 | DICompositeType * |
546 | DIBuilder::createVariantPart(DIScope *Scope, StringRef Name, DIFile *File, |
547 | unsigned LineNumber, uint64_t SizeInBits, |
548 | uint32_t AlignInBits, DINode::DIFlags Flags, |
549 | DIDerivedType *Discriminator, DINodeArray Elements, |
550 | StringRef UniqueIdentifier) { |
551 | auto *R = DICompositeType::get( |
552 | Context&: VMContext, Tag: dwarf::DW_TAG_variant_part, Name, File, Line: LineNumber, |
553 | Scope: getNonCompileUnitScope(N: Scope), BaseType: nullptr, SizeInBits, AlignInBits, OffsetInBits: 0, Flags, |
554 | Elements, RuntimeLang: 0, VTableHolder: nullptr, TemplateParams: nullptr, Identifier: UniqueIdentifier, Discriminator); |
555 | trackIfUnresolved(N: R); |
556 | return R; |
557 | } |
558 | |
559 | DISubroutineType *DIBuilder::createSubroutineType(DITypeRefArray ParameterTypes, |
560 | DINode::DIFlags Flags, |
561 | unsigned CC) { |
562 | return DISubroutineType::get(Context&: VMContext, Flags, CC, TypeArray: ParameterTypes); |
563 | } |
564 | |
565 | DICompositeType * |
566 | DIBuilder::createEnumerationType(DIScope *Scope, StringRef Name, DIFile *File, |
567 | unsigned LineNumber, uint64_t SizeInBits, |
568 | uint32_t AlignInBits, DINodeArray Elements, |
569 | DIType *UnderlyingType, unsigned RunTimeLang, |
570 | StringRef UniqueIdentifier, bool IsScoped) { |
571 | auto *CTy = DICompositeType::get( |
572 | Context&: VMContext, Tag: dwarf::DW_TAG_enumeration_type, Name, File, Line: LineNumber, |
573 | Scope: getNonCompileUnitScope(N: Scope), BaseType: UnderlyingType, SizeInBits, AlignInBits, OffsetInBits: 0, |
574 | Flags: IsScoped ? DINode::FlagEnumClass : DINode::FlagZero, Elements, |
575 | RuntimeLang: RunTimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier: UniqueIdentifier); |
576 | AllEnumTypes.emplace_back(Args&: CTy); |
577 | trackIfUnresolved(N: CTy); |
578 | return CTy; |
579 | } |
580 | |
581 | DIDerivedType *DIBuilder::createSetType(DIScope *Scope, StringRef Name, |
582 | DIFile *File, unsigned LineNo, |
583 | uint64_t SizeInBits, |
584 | uint32_t AlignInBits, DIType *Ty) { |
585 | auto *R = DIDerivedType::get(Context&: VMContext, Tag: dwarf::DW_TAG_set_type, Name, File, |
586 | Line: LineNo, Scope: getNonCompileUnitScope(N: Scope), BaseType: Ty, |
587 | SizeInBits, AlignInBits, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, |
588 | PtrAuthData: std::nullopt, Flags: DINode::FlagZero); |
589 | trackIfUnresolved(N: R); |
590 | return R; |
591 | } |
592 | |
593 | DICompositeType * |
594 | DIBuilder::createArrayType(uint64_t Size, uint32_t AlignInBits, DIType *Ty, |
595 | DINodeArray Subscripts, |
596 | PointerUnion<DIExpression *, DIVariable *> DL, |
597 | PointerUnion<DIExpression *, DIVariable *> AS, |
598 | PointerUnion<DIExpression *, DIVariable *> AL, |
599 | PointerUnion<DIExpression *, DIVariable *> RK) { |
600 | auto *R = DICompositeType::get( |
601 | Context&: VMContext, Tag: dwarf::DW_TAG_array_type, Name: "" , File: nullptr, Line: 0, Scope: nullptr, BaseType: Ty, SizeInBits: Size, |
602 | AlignInBits, OffsetInBits: 0, Flags: DINode::FlagZero, Elements: Subscripts, RuntimeLang: 0, VTableHolder: nullptr, TemplateParams: nullptr, Identifier: "" , |
603 | Discriminator: nullptr, |
604 | DataLocation: isa<DIExpression *>(Val: DL) ? (Metadata *)cast<DIExpression *>(Val&: DL) |
605 | : (Metadata *)cast<DIVariable *>(Val&: DL), |
606 | Associated: isa<DIExpression *>(Val: AS) ? (Metadata *)cast<DIExpression *>(Val&: AS) |
607 | : (Metadata *)cast<DIVariable *>(Val&: AS), |
608 | Allocated: isa<DIExpression *>(Val: AL) ? (Metadata *)cast<DIExpression *>(Val&: AL) |
609 | : (Metadata *)cast<DIVariable *>(Val&: AL), |
610 | Rank: isa<DIExpression *>(Val: RK) ? (Metadata *)cast<DIExpression *>(Val&: RK) |
611 | : (Metadata *)cast<DIVariable *>(Val&: RK)); |
612 | trackIfUnresolved(N: R); |
613 | return R; |
614 | } |
615 | |
616 | DICompositeType *DIBuilder::createVectorType(uint64_t Size, |
617 | uint32_t AlignInBits, DIType *Ty, |
618 | DINodeArray Subscripts) { |
619 | auto *R = DICompositeType::get(Context&: VMContext, Tag: dwarf::DW_TAG_array_type, Name: "" , |
620 | File: nullptr, Line: 0, Scope: nullptr, BaseType: Ty, SizeInBits: Size, AlignInBits, OffsetInBits: 0, |
621 | Flags: DINode::FlagVector, Elements: Subscripts, RuntimeLang: 0, VTableHolder: nullptr); |
622 | trackIfUnresolved(N: R); |
623 | return R; |
624 | } |
625 | |
626 | DISubprogram *DIBuilder::createArtificialSubprogram(DISubprogram *SP) { |
627 | auto NewSP = SP->cloneWithFlags(NewFlags: SP->getFlags() | DINode::FlagArtificial); |
628 | return MDNode::replaceWithDistinct(N: std::move(NewSP)); |
629 | } |
630 | |
631 | static DIType *createTypeWithFlags(const DIType *Ty, |
632 | DINode::DIFlags FlagsToSet) { |
633 | auto NewTy = Ty->cloneWithFlags(NewFlags: Ty->getFlags() | FlagsToSet); |
634 | return MDNode::replaceWithUniqued(N: std::move(NewTy)); |
635 | } |
636 | |
637 | DIType *DIBuilder::createArtificialType(DIType *Ty) { |
638 | // FIXME: Restrict this to the nodes where it's valid. |
639 | if (Ty->isArtificial()) |
640 | return Ty; |
641 | return createTypeWithFlags(Ty, FlagsToSet: DINode::FlagArtificial); |
642 | } |
643 | |
644 | DIType *DIBuilder::createObjectPointerType(DIType *Ty) { |
645 | // FIXME: Restrict this to the nodes where it's valid. |
646 | if (Ty->isObjectPointer()) |
647 | return Ty; |
648 | DINode::DIFlags Flags = DINode::FlagObjectPointer | DINode::FlagArtificial; |
649 | return createTypeWithFlags(Ty, FlagsToSet: Flags); |
650 | } |
651 | |
652 | void DIBuilder::retainType(DIScope *T) { |
653 | assert(T && "Expected non-null type" ); |
654 | assert((isa<DIType>(T) || (isa<DISubprogram>(T) && |
655 | cast<DISubprogram>(T)->isDefinition() == false)) && |
656 | "Expected type or subprogram declaration" ); |
657 | AllRetainTypes.emplace_back(Args&: T); |
658 | } |
659 | |
660 | DIBasicType *DIBuilder::createUnspecifiedParameter() { return nullptr; } |
661 | |
662 | DICompositeType * |
663 | DIBuilder::createForwardDecl(unsigned Tag, StringRef Name, DIScope *Scope, |
664 | DIFile *F, unsigned Line, unsigned RuntimeLang, |
665 | uint64_t SizeInBits, uint32_t AlignInBits, |
666 | StringRef UniqueIdentifier) { |
667 | // FIXME: Define in terms of createReplaceableForwardDecl() by calling |
668 | // replaceWithUniqued(). |
669 | auto *RetTy = DICompositeType::get( |
670 | Context&: VMContext, Tag, Name, File: F, Line, Scope: getNonCompileUnitScope(N: Scope), BaseType: nullptr, |
671 | SizeInBits, AlignInBits, OffsetInBits: 0, Flags: DINode::FlagFwdDecl, Elements: nullptr, RuntimeLang, |
672 | VTableHolder: nullptr, TemplateParams: nullptr, Identifier: UniqueIdentifier); |
673 | trackIfUnresolved(N: RetTy); |
674 | return RetTy; |
675 | } |
676 | |
677 | DICompositeType *DIBuilder::createReplaceableCompositeType( |
678 | unsigned Tag, StringRef Name, DIScope *Scope, DIFile *F, unsigned Line, |
679 | unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, |
680 | DINode::DIFlags Flags, StringRef UniqueIdentifier, |
681 | DINodeArray Annotations) { |
682 | auto *RetTy = |
683 | DICompositeType::getTemporary( |
684 | Context&: VMContext, Tag, Name, File: F, Line, Scope: getNonCompileUnitScope(N: Scope), BaseType: nullptr, |
685 | SizeInBits, AlignInBits, OffsetInBits: 0, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, |
686 | TemplateParams: nullptr, Identifier: UniqueIdentifier, Discriminator: nullptr, DataLocation: nullptr, Associated: nullptr, Allocated: nullptr, |
687 | Rank: nullptr, Annotations) |
688 | .release(); |
689 | trackIfUnresolved(N: RetTy); |
690 | return RetTy; |
691 | } |
692 | |
693 | DINodeArray DIBuilder::getOrCreateArray(ArrayRef<Metadata *> Elements) { |
694 | return MDTuple::get(Context&: VMContext, MDs: Elements); |
695 | } |
696 | |
697 | DIMacroNodeArray |
698 | DIBuilder::getOrCreateMacroArray(ArrayRef<Metadata *> Elements) { |
699 | return MDTuple::get(Context&: VMContext, MDs: Elements); |
700 | } |
701 | |
702 | DITypeRefArray DIBuilder::getOrCreateTypeArray(ArrayRef<Metadata *> Elements) { |
703 | SmallVector<llvm::Metadata *, 16> Elts; |
704 | for (Metadata *E : Elements) { |
705 | if (isa_and_nonnull<MDNode>(Val: E)) |
706 | Elts.push_back(Elt: cast<DIType>(Val: E)); |
707 | else |
708 | Elts.push_back(Elt: E); |
709 | } |
710 | return DITypeRefArray(MDNode::get(Context&: VMContext, MDs: Elts)); |
711 | } |
712 | |
713 | DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, int64_t Count) { |
714 | auto *LB = ConstantAsMetadata::get( |
715 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: VMContext), V: Lo)); |
716 | auto *CountNode = ConstantAsMetadata::get( |
717 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: VMContext), V: Count)); |
718 | return DISubrange::get(Context&: VMContext, CountNode, LowerBound: LB, UpperBound: nullptr, Stride: nullptr); |
719 | } |
720 | |
721 | DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, Metadata *CountNode) { |
722 | auto *LB = ConstantAsMetadata::get( |
723 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: VMContext), V: Lo)); |
724 | return DISubrange::get(Context&: VMContext, CountNode, LowerBound: LB, UpperBound: nullptr, Stride: nullptr); |
725 | } |
726 | |
727 | DISubrange *DIBuilder::getOrCreateSubrange(Metadata *CountNode, Metadata *LB, |
728 | Metadata *UB, Metadata *Stride) { |
729 | return DISubrange::get(Context&: VMContext, CountNode, LowerBound: LB, UpperBound: UB, Stride); |
730 | } |
731 | |
732 | DIGenericSubrange *DIBuilder::getOrCreateGenericSubrange( |
733 | DIGenericSubrange::BoundType CountNode, DIGenericSubrange::BoundType LB, |
734 | DIGenericSubrange::BoundType UB, DIGenericSubrange::BoundType Stride) { |
735 | auto ConvToMetadata = [&](DIGenericSubrange::BoundType Bound) -> Metadata * { |
736 | return isa<DIExpression *>(Val: Bound) ? (Metadata *)cast<DIExpression *>(Val&: Bound) |
737 | : (Metadata *)cast<DIVariable *>(Val&: Bound); |
738 | }; |
739 | return DIGenericSubrange::get(Context&: VMContext, CountNode: ConvToMetadata(CountNode), |
740 | LowerBound: ConvToMetadata(LB), UpperBound: ConvToMetadata(UB), |
741 | Stride: ConvToMetadata(Stride)); |
742 | } |
743 | |
744 | static void checkGlobalVariableScope(DIScope *Context) { |
745 | #ifndef NDEBUG |
746 | if (auto *CT = |
747 | dyn_cast_or_null<DICompositeType>(getNonCompileUnitScope(Context))) |
748 | assert(CT->getIdentifier().empty() && |
749 | "Context of a global variable should not be a type with identifier" ); |
750 | #endif |
751 | } |
752 | |
753 | DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression( |
754 | DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, |
755 | unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, bool isDefined, |
756 | DIExpression *Expr, MDNode *Decl, MDTuple *TemplateParams, |
757 | uint32_t AlignInBits, DINodeArray Annotations) { |
758 | checkGlobalVariableScope(Context); |
759 | |
760 | auto *GV = DIGlobalVariable::getDistinct( |
761 | Context&: VMContext, Scope: cast_or_null<DIScope>(Val: Context), Name, LinkageName, File: F, |
762 | Line: LineNumber, Type: Ty, IsLocalToUnit, IsDefinition: isDefined, |
763 | StaticDataMemberDeclaration: cast_or_null<DIDerivedType>(Val: Decl), TemplateParams, AlignInBits, |
764 | Annotations); |
765 | if (!Expr) |
766 | Expr = createExpression(); |
767 | auto *N = DIGlobalVariableExpression::get(Context&: VMContext, Variable: GV, Expression: Expr); |
768 | AllGVs.push_back(Elt: N); |
769 | return N; |
770 | } |
771 | |
772 | DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( |
773 | DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, |
774 | unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, MDNode *Decl, |
775 | MDTuple *TemplateParams, uint32_t AlignInBits) { |
776 | checkGlobalVariableScope(Context); |
777 | |
778 | return DIGlobalVariable::getTemporary( |
779 | Context&: VMContext, Scope: cast_or_null<DIScope>(Val: Context), Name, LinkageName, File: F, |
780 | Line: LineNumber, Type: Ty, IsLocalToUnit, IsDefinition: false, |
781 | StaticDataMemberDeclaration: cast_or_null<DIDerivedType>(Val: Decl), TemplateParams, AlignInBits, |
782 | Annotations: nullptr) |
783 | .release(); |
784 | } |
785 | |
786 | static DILocalVariable *createLocalVariable( |
787 | LLVMContext &VMContext, |
788 | SmallVectorImpl<TrackingMDNodeRef> &PreservedNodes, |
789 | DIScope *Context, StringRef Name, unsigned ArgNo, DIFile *File, |
790 | unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, |
791 | uint32_t AlignInBits, DINodeArray Annotations = nullptr) { |
792 | // FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT |
793 | // the only valid scopes)? |
794 | auto *Scope = cast<DILocalScope>(Val: Context); |
795 | auto *Node = DILocalVariable::get(Context&: VMContext, Scope, Name, File, Line: LineNo, Type: Ty, |
796 | Arg: ArgNo, Flags, AlignInBits, Annotations); |
797 | if (AlwaysPreserve) { |
798 | // The optimizer may remove local variables. If there is an interest |
799 | // to preserve variable info in such situation then stash it in a |
800 | // named mdnode. |
801 | PreservedNodes.emplace_back(Args&: Node); |
802 | } |
803 | return Node; |
804 | } |
805 | |
806 | DILocalVariable *DIBuilder::createAutoVariable(DIScope *Scope, StringRef Name, |
807 | DIFile *File, unsigned LineNo, |
808 | DIType *Ty, bool AlwaysPreserve, |
809 | DINode::DIFlags Flags, |
810 | uint32_t AlignInBits) { |
811 | assert(Scope && isa<DILocalScope>(Scope) && |
812 | "Unexpected scope for a local variable." ); |
813 | return createLocalVariable( |
814 | VMContext, PreservedNodes&: getSubprogramNodesTrackingVector(S: Scope), Context: Scope, Name, |
815 | /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, Flags, AlignInBits); |
816 | } |
817 | |
818 | DILocalVariable *DIBuilder::createParameterVariable( |
819 | DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File, |
820 | unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, |
821 | DINodeArray Annotations) { |
822 | assert(ArgNo && "Expected non-zero argument number for parameter" ); |
823 | assert(Scope && isa<DILocalScope>(Scope) && |
824 | "Unexpected scope for a local variable." ); |
825 | return createLocalVariable( |
826 | VMContext, PreservedNodes&: getSubprogramNodesTrackingVector(S: Scope), Context: Scope, Name, ArgNo, |
827 | File, LineNo, Ty, AlwaysPreserve, Flags, /*AlignInBits=*/0, Annotations); |
828 | } |
829 | |
830 | DILabel *DIBuilder::createLabel(DIScope *Context, StringRef Name, DIFile *File, |
831 | unsigned LineNo, bool AlwaysPreserve) { |
832 | auto *Scope = cast<DILocalScope>(Val: Context); |
833 | auto *Node = DILabel::get(Context&: VMContext, Scope, Name, File, Line: LineNo); |
834 | |
835 | if (AlwaysPreserve) { |
836 | /// The optimizer may remove labels. If there is an interest |
837 | /// to preserve label info in such situation then append it to |
838 | /// the list of retained nodes of the DISubprogram. |
839 | getSubprogramNodesTrackingVector(S: Scope).emplace_back(Args&: Node); |
840 | } |
841 | return Node; |
842 | } |
843 | |
844 | DIExpression *DIBuilder::createExpression(ArrayRef<uint64_t> Addr) { |
845 | return DIExpression::get(Context&: VMContext, Elements: Addr); |
846 | } |
847 | |
848 | template <class... Ts> |
849 | static DISubprogram *getSubprogram(bool IsDistinct, Ts &&...Args) { |
850 | if (IsDistinct) |
851 | return DISubprogram::getDistinct(std::forward<Ts>(Args)...); |
852 | return DISubprogram::get(std::forward<Ts>(Args)...); |
853 | } |
854 | |
855 | DISubprogram *DIBuilder::createFunction( |
856 | DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, |
857 | unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, |
858 | DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, |
859 | DITemplateParameterArray TParams, DISubprogram *Decl, |
860 | DITypeArray ThrownTypes, DINodeArray Annotations, |
861 | StringRef TargetFuncName) { |
862 | bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; |
863 | auto *Node = getSubprogram( |
864 | /*IsDistinct=*/IsDefinition, Args&: VMContext, Args: getNonCompileUnitScope(N: Context), |
865 | Args&: Name, Args&: LinkageName, Args&: File, Args&: LineNo, Args&: Ty, Args&: ScopeLine, Args: nullptr, Args: 0, Args: 0, Args&: Flags, |
866 | Args&: SPFlags, Args: IsDefinition ? CUNode : nullptr, Args&: TParams, Args&: Decl, Args: nullptr, |
867 | Args&: ThrownTypes, Args&: Annotations, Args&: TargetFuncName); |
868 | |
869 | if (IsDefinition) |
870 | AllSubprograms.push_back(Elt: Node); |
871 | trackIfUnresolved(N: Node); |
872 | return Node; |
873 | } |
874 | |
875 | DISubprogram *DIBuilder::createTempFunctionFwdDecl( |
876 | DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, |
877 | unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, |
878 | DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, |
879 | DITemplateParameterArray TParams, DISubprogram *Decl, |
880 | DITypeArray ThrownTypes) { |
881 | bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; |
882 | return DISubprogram::getTemporary(Context&: VMContext, Scope: getNonCompileUnitScope(N: Context), |
883 | Name, LinkageName, File, Line: LineNo, Type: Ty, |
884 | ScopeLine, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags, SPFlags, |
885 | Unit: IsDefinition ? CUNode : nullptr, TemplateParams: TParams, |
886 | Declaration: Decl, RetainedNodes: nullptr, ThrownTypes) |
887 | .release(); |
888 | } |
889 | |
890 | DISubprogram *DIBuilder::createMethod( |
891 | DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, |
892 | unsigned LineNo, DISubroutineType *Ty, unsigned VIndex, int ThisAdjustment, |
893 | DIType *VTableHolder, DINode::DIFlags Flags, |
894 | DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams, |
895 | DITypeArray ThrownTypes) { |
896 | assert(getNonCompileUnitScope(Context) && |
897 | "Methods should have both a Context and a context that isn't " |
898 | "the compile unit." ); |
899 | // FIXME: Do we want to use different scope/lines? |
900 | bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; |
901 | auto *SP = getSubprogram( |
902 | /*IsDistinct=*/IsDefinition, Args&: VMContext, Args: cast<DIScope>(Val: Context), Args&: Name, |
903 | Args&: LinkageName, Args&: F, Args&: LineNo, Args&: Ty, Args&: LineNo, Args&: VTableHolder, Args&: VIndex, Args&: ThisAdjustment, |
904 | Args&: Flags, Args&: SPFlags, Args: IsDefinition ? CUNode : nullptr, Args&: TParams, Args: nullptr, |
905 | Args: nullptr, Args&: ThrownTypes); |
906 | |
907 | if (IsDefinition) |
908 | AllSubprograms.push_back(Elt: SP); |
909 | trackIfUnresolved(N: SP); |
910 | return SP; |
911 | } |
912 | |
913 | DICommonBlock *DIBuilder::createCommonBlock(DIScope *Scope, |
914 | DIGlobalVariable *Decl, |
915 | StringRef Name, DIFile *File, |
916 | unsigned LineNo) { |
917 | return DICommonBlock::get(Context&: VMContext, Scope, Decl, Name, File, LineNo); |
918 | } |
919 | |
920 | DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name, |
921 | bool ExportSymbols) { |
922 | |
923 | // It is okay to *not* make anonymous top-level namespaces distinct, because |
924 | // all nodes that have an anonymous namespace as their parent scope are |
925 | // guaranteed to be unique and/or are linked to their containing |
926 | // DICompileUnit. This decision is an explicit tradeoff of link time versus |
927 | // memory usage versus code simplicity and may get revisited in the future. |
928 | return DINamespace::get(Context&: VMContext, Scope: getNonCompileUnitScope(N: Scope), Name, |
929 | ExportSymbols); |
930 | } |
931 | |
932 | DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, |
933 | StringRef ConfigurationMacros, |
934 | StringRef IncludePath, StringRef APINotesFile, |
935 | DIFile *File, unsigned LineNo, bool IsDecl) { |
936 | return DIModule::get(Context&: VMContext, File, Scope: getNonCompileUnitScope(N: Scope), Name, |
937 | ConfigurationMacros, IncludePath, APINotesFile, LineNo, |
938 | IsDecl); |
939 | } |
940 | |
941 | DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, |
942 | DIFile *File, |
943 | unsigned Discriminator) { |
944 | return DILexicalBlockFile::get(Context&: VMContext, Scope, File, Discriminator); |
945 | } |
946 | |
947 | DILexicalBlock *DIBuilder::createLexicalBlock(DIScope *Scope, DIFile *File, |
948 | unsigned Line, unsigned Col) { |
949 | // Make these distinct, to avoid merging two lexical blocks on the same |
950 | // file/line/column. |
951 | return DILexicalBlock::getDistinct(Context&: VMContext, Scope: getNonCompileUnitScope(N: Scope), |
952 | File, Line, Column: Col); |
953 | } |
954 | |
955 | DbgInstPtr DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, |
956 | DIExpression *Expr, const DILocation *DL, |
957 | Instruction *InsertBefore) { |
958 | return insertDeclare(Storage, VarInfo, Expr, DL, InsertBB: InsertBefore->getParent(), |
959 | InsertBefore); |
960 | } |
961 | |
962 | DbgInstPtr DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, |
963 | DIExpression *Expr, const DILocation *DL, |
964 | BasicBlock *InsertAtEnd) { |
965 | // If this block already has a terminator then insert this intrinsic before |
966 | // the terminator. Otherwise, put it at the end of the block. |
967 | Instruction *InsertBefore = InsertAtEnd->getTerminator(); |
968 | return insertDeclare(Storage, VarInfo, Expr, DL, InsertBB: InsertAtEnd, InsertBefore); |
969 | } |
970 | |
971 | DbgInstPtr DIBuilder::insertDbgAssign(Instruction *LinkedInstr, Value *Val, |
972 | DILocalVariable *SrcVar, |
973 | DIExpression *ValExpr, Value *Addr, |
974 | DIExpression *AddrExpr, |
975 | const DILocation *DL) { |
976 | auto *Link = cast_or_null<DIAssignID>( |
977 | Val: LinkedInstr->getMetadata(KindID: LLVMContext::MD_DIAssignID)); |
978 | assert(Link && "Linked instruction must have DIAssign metadata attached" ); |
979 | |
980 | if (M.IsNewDbgInfoFormat) { |
981 | DbgVariableRecord *DVR = DbgVariableRecord::createDVRAssign( |
982 | Val, Variable: SrcVar, Expression: ValExpr, AssignID: Link, Address: Addr, AddressExpression: AddrExpr, DI: DL); |
983 | BasicBlock *InsertBB = LinkedInstr->getParent(); |
984 | // Insert after LinkedInstr. |
985 | BasicBlock::iterator NextIt = std::next(x: LinkedInstr->getIterator()); |
986 | Instruction *InsertBefore = NextIt == InsertBB->end() ? nullptr : &*NextIt; |
987 | insertDbgVariableRecord(DVR, InsertBB, InsertBefore, InsertAtHead: true); |
988 | return DVR; |
989 | } |
990 | |
991 | LLVMContext &Ctx = LinkedInstr->getContext(); |
992 | Module *M = LinkedInstr->getModule(); |
993 | if (!AssignFn) |
994 | AssignFn = Intrinsic::getDeclaration(M, id: Intrinsic::dbg_assign); |
995 | |
996 | std::array<Value *, 6> Args = { |
997 | MetadataAsValue::get(Context&: Ctx, MD: ValueAsMetadata::get(V: Val)), |
998 | MetadataAsValue::get(Context&: Ctx, MD: SrcVar), |
999 | MetadataAsValue::get(Context&: Ctx, MD: ValExpr), |
1000 | MetadataAsValue::get(Context&: Ctx, MD: Link), |
1001 | MetadataAsValue::get(Context&: Ctx, MD: ValueAsMetadata::get(V: Addr)), |
1002 | MetadataAsValue::get(Context&: Ctx, MD: AddrExpr), |
1003 | }; |
1004 | |
1005 | IRBuilder<> B(Ctx); |
1006 | B.SetCurrentDebugLocation(DL); |
1007 | |
1008 | auto *DVI = cast<DbgAssignIntrinsic>(Val: B.CreateCall(Callee: AssignFn, Args)); |
1009 | DVI->insertAfter(InsertPos: LinkedInstr); |
1010 | return DVI; |
1011 | } |
1012 | |
1013 | DbgInstPtr DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL, |
1014 | Instruction *InsertBefore) { |
1015 | return insertLabel(LabelInfo, DL, |
1016 | InsertBB: InsertBefore ? InsertBefore->getParent() : nullptr, |
1017 | InsertBefore); |
1018 | } |
1019 | |
1020 | DbgInstPtr DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL, |
1021 | BasicBlock *InsertAtEnd) { |
1022 | return insertLabel(LabelInfo, DL, InsertBB: InsertAtEnd, InsertBefore: nullptr); |
1023 | } |
1024 | |
1025 | DbgInstPtr DIBuilder::insertDbgValueIntrinsic(Value *V, |
1026 | DILocalVariable *VarInfo, |
1027 | DIExpression *Expr, |
1028 | const DILocation *DL, |
1029 | Instruction *InsertBefore) { |
1030 | DbgInstPtr DVI = insertDbgValueIntrinsic( |
1031 | Val: V, VarInfo, Expr, DL, InsertBB: InsertBefore ? InsertBefore->getParent() : nullptr, |
1032 | InsertBefore); |
1033 | if (DVI.is<Instruction *>()) |
1034 | cast<CallInst>(Val: DVI.get<Instruction *>())->setTailCall(); |
1035 | return DVI; |
1036 | } |
1037 | |
1038 | DbgInstPtr DIBuilder::insertDbgValueIntrinsic(Value *V, |
1039 | DILocalVariable *VarInfo, |
1040 | DIExpression *Expr, |
1041 | const DILocation *DL, |
1042 | BasicBlock *InsertAtEnd) { |
1043 | return insertDbgValueIntrinsic(Val: V, VarInfo, Expr, DL, InsertBB: InsertAtEnd, InsertBefore: nullptr); |
1044 | } |
1045 | |
1046 | /// Initialize IRBuilder for inserting dbg.declare and dbg.value intrinsics. |
1047 | /// This abstracts over the various ways to specify an insert position. |
1048 | static void initIRBuilder(IRBuilder<> &Builder, const DILocation *DL, |
1049 | BasicBlock *InsertBB, Instruction *InsertBefore) { |
1050 | if (InsertBefore) |
1051 | Builder.SetInsertPoint(InsertBefore); |
1052 | else if (InsertBB) |
1053 | Builder.SetInsertPoint(InsertBB); |
1054 | Builder.SetCurrentDebugLocation(DL); |
1055 | } |
1056 | |
1057 | static Value *getDbgIntrinsicValueImpl(LLVMContext &VMContext, Value *V) { |
1058 | assert(V && "no value passed to dbg intrinsic" ); |
1059 | return MetadataAsValue::get(Context&: VMContext, MD: ValueAsMetadata::get(V)); |
1060 | } |
1061 | |
1062 | static Function *getDeclareIntrin(Module &M) { |
1063 | return Intrinsic::getDeclaration(M: &M, id: Intrinsic::dbg_declare); |
1064 | } |
1065 | |
1066 | DbgInstPtr DIBuilder::insertDbgValueIntrinsic( |
1067 | llvm::Value *Val, DILocalVariable *VarInfo, DIExpression *Expr, |
1068 | const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore) { |
1069 | if (M.IsNewDbgInfoFormat) { |
1070 | DbgVariableRecord *DVR = |
1071 | DbgVariableRecord::createDbgVariableRecord(Location: Val, DV: VarInfo, Expr, DI: DL); |
1072 | insertDbgVariableRecord(DVR, InsertBB, InsertBefore); |
1073 | return DVR; |
1074 | } |
1075 | |
1076 | if (!ValueFn) |
1077 | ValueFn = Intrinsic::getDeclaration(M: &M, id: Intrinsic::dbg_value); |
1078 | return insertDbgIntrinsic(Intrinsic: ValueFn, Val, VarInfo, Expr, DL, InsertBB, |
1079 | InsertBefore); |
1080 | } |
1081 | |
1082 | DbgInstPtr DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, |
1083 | DIExpression *Expr, const DILocation *DL, |
1084 | BasicBlock *InsertBB, |
1085 | Instruction *InsertBefore) { |
1086 | assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.declare" ); |
1087 | assert(DL && "Expected debug loc" ); |
1088 | assert(DL->getScope()->getSubprogram() == |
1089 | VarInfo->getScope()->getSubprogram() && |
1090 | "Expected matching subprograms" ); |
1091 | |
1092 | if (M.IsNewDbgInfoFormat) { |
1093 | DbgVariableRecord *DVR = |
1094 | DbgVariableRecord::createDVRDeclare(Address: Storage, DV: VarInfo, Expr, DI: DL); |
1095 | insertDbgVariableRecord(DVR, InsertBB, InsertBefore); |
1096 | return DVR; |
1097 | } |
1098 | |
1099 | if (!DeclareFn) |
1100 | DeclareFn = getDeclareIntrin(M); |
1101 | |
1102 | trackIfUnresolved(N: VarInfo); |
1103 | trackIfUnresolved(N: Expr); |
1104 | Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, V: Storage), |
1105 | MetadataAsValue::get(Context&: VMContext, MD: VarInfo), |
1106 | MetadataAsValue::get(Context&: VMContext, MD: Expr)}; |
1107 | |
1108 | IRBuilder<> B(DL->getContext()); |
1109 | initIRBuilder(Builder&: B, DL, InsertBB, InsertBefore); |
1110 | return B.CreateCall(Callee: DeclareFn, Args); |
1111 | } |
1112 | |
1113 | void DIBuilder::insertDbgVariableRecord(DbgVariableRecord *DVR, |
1114 | BasicBlock *InsertBB, |
1115 | Instruction *InsertBefore, |
1116 | bool InsertAtHead) { |
1117 | assert(InsertBefore || InsertBB); |
1118 | trackIfUnresolved(N: DVR->getVariable()); |
1119 | trackIfUnresolved(N: DVR->getExpression()); |
1120 | if (DVR->isDbgAssign()) |
1121 | trackIfUnresolved(N: DVR->getAddressExpression()); |
1122 | |
1123 | BasicBlock::iterator InsertPt; |
1124 | if (InsertBB && InsertBefore) |
1125 | InsertPt = InsertBefore->getIterator(); |
1126 | else if (InsertBB) |
1127 | InsertPt = InsertBB->end(); |
1128 | InsertPt.setHeadBit(InsertAtHead); |
1129 | InsertBB->insertDbgRecordBefore(DR: DVR, Here: InsertPt); |
1130 | } |
1131 | |
1132 | Instruction *DIBuilder::insertDbgIntrinsic(llvm::Function *IntrinsicFn, |
1133 | Value *V, DILocalVariable *VarInfo, |
1134 | DIExpression *Expr, |
1135 | const DILocation *DL, |
1136 | BasicBlock *InsertBB, |
1137 | Instruction *InsertBefore) { |
1138 | assert(IntrinsicFn && "must pass a non-null intrinsic function" ); |
1139 | assert(V && "must pass a value to a dbg intrinsic" ); |
1140 | assert(VarInfo && |
1141 | "empty or invalid DILocalVariable* passed to debug intrinsic" ); |
1142 | assert(DL && "Expected debug loc" ); |
1143 | assert(DL->getScope()->getSubprogram() == |
1144 | VarInfo->getScope()->getSubprogram() && |
1145 | "Expected matching subprograms" ); |
1146 | |
1147 | trackIfUnresolved(N: VarInfo); |
1148 | trackIfUnresolved(N: Expr); |
1149 | Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, V), |
1150 | MetadataAsValue::get(Context&: VMContext, MD: VarInfo), |
1151 | MetadataAsValue::get(Context&: VMContext, MD: Expr)}; |
1152 | |
1153 | IRBuilder<> B(DL->getContext()); |
1154 | initIRBuilder(Builder&: B, DL, InsertBB, InsertBefore); |
1155 | return B.CreateCall(Callee: IntrinsicFn, Args); |
1156 | } |
1157 | |
1158 | DbgInstPtr DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL, |
1159 | BasicBlock *InsertBB, |
1160 | Instruction *InsertBefore) { |
1161 | assert(LabelInfo && "empty or invalid DILabel* passed to dbg.label" ); |
1162 | assert(DL && "Expected debug loc" ); |
1163 | assert(DL->getScope()->getSubprogram() == |
1164 | LabelInfo->getScope()->getSubprogram() && |
1165 | "Expected matching subprograms" ); |
1166 | |
1167 | trackIfUnresolved(N: LabelInfo); |
1168 | if (M.IsNewDbgInfoFormat) { |
1169 | DbgLabelRecord *DLR = new DbgLabelRecord(LabelInfo, DL); |
1170 | if (InsertBB && InsertBefore) |
1171 | InsertBB->insertDbgRecordBefore(DR: DLR, Here: InsertBefore->getIterator()); |
1172 | else if (InsertBB) |
1173 | InsertBB->insertDbgRecordBefore(DR: DLR, Here: InsertBB->end()); |
1174 | return DLR; |
1175 | } |
1176 | |
1177 | if (!LabelFn) |
1178 | LabelFn = Intrinsic::getDeclaration(M: &M, id: Intrinsic::dbg_label); |
1179 | |
1180 | Value *Args[] = {MetadataAsValue::get(Context&: VMContext, MD: LabelInfo)}; |
1181 | |
1182 | IRBuilder<> B(DL->getContext()); |
1183 | initIRBuilder(Builder&: B, DL, InsertBB, InsertBefore); |
1184 | return B.CreateCall(Callee: LabelFn, Args); |
1185 | } |
1186 | |
1187 | void DIBuilder::replaceVTableHolder(DICompositeType *&T, DIType *VTableHolder) { |
1188 | { |
1189 | TypedTrackingMDRef<DICompositeType> N(T); |
1190 | N->replaceVTableHolder(VTableHolder); |
1191 | T = N.get(); |
1192 | } |
1193 | |
1194 | // If this didn't create a self-reference, just return. |
1195 | if (T != VTableHolder) |
1196 | return; |
1197 | |
1198 | // Look for unresolved operands. T will drop RAUW support, orphaning any |
1199 | // cycles underneath it. |
1200 | if (T->isResolved()) |
1201 | for (const MDOperand &O : T->operands()) |
1202 | if (auto *N = dyn_cast_or_null<MDNode>(Val: O)) |
1203 | trackIfUnresolved(N); |
1204 | } |
1205 | |
1206 | void DIBuilder::replaceArrays(DICompositeType *&T, DINodeArray Elements, |
1207 | DINodeArray TParams) { |
1208 | { |
1209 | TypedTrackingMDRef<DICompositeType> N(T); |
1210 | if (Elements) |
1211 | N->replaceElements(Elements); |
1212 | if (TParams) |
1213 | N->replaceTemplateParams(TemplateParams: DITemplateParameterArray(TParams)); |
1214 | T = N.get(); |
1215 | } |
1216 | |
1217 | // If T isn't resolved, there's no problem. |
1218 | if (!T->isResolved()) |
1219 | return; |
1220 | |
1221 | // If T is resolved, it may be due to a self-reference cycle. Track the |
1222 | // arrays explicitly if they're unresolved, or else the cycles will be |
1223 | // orphaned. |
1224 | if (Elements) |
1225 | trackIfUnresolved(N: Elements.get()); |
1226 | if (TParams) |
1227 | trackIfUnresolved(N: TParams.get()); |
1228 | } |
1229 | |