[AMDGPU] Test codegen'ing True16 additions.
[llvm-project.git] / llvm / lib / DWARFLinkerParallel / DWARFLinkerCompileUnit.h
blobf1267c1fe407e5d33ecccbd23f34416eb9d83450
1 //===- DWARFLinkerCompileUnit.h ---------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
10 #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
12 #include "DWARFLinkerUnit.h"
13 #include "IndexedValuesMap.h"
14 #include "llvm/DWARFLinkerParallel/DWARFFile.h"
15 #include <optional>
17 namespace llvm {
18 namespace dwarflinker_parallel {
20 using OffsetToUnitTy = function_ref<CompileUnit *(uint64_t Offset)>;
22 /// Stores all information related to a compile unit, be it in its original
23 /// instance of the object file or its brand new cloned and generated DIE tree.
24 class CompileUnit : public DwarfUnit {
25 public:
26 /// The stages of new compile unit processing.
27 enum class Stage : uint8_t {
28 /// Created, linked with input DWARF file.
29 CreatedNotLoaded = 0,
31 /// Input DWARF is loaded.
32 Loaded,
34 /// Input DWARF is analysed(DIEs pointing to the real code section are
35 /// discovered, type names are assigned if ODR is requested).
36 LivenessAnalysisDone,
38 /// Output DWARF is generated.
39 Cloned,
41 /// Offsets inside patch records are updated.
42 PatchesUpdated,
44 /// Resources(Input DWARF, Output DWARF tree) are released.
45 Cleaned,
48 CompileUnit(LinkingGlobalData &GlobalData, unsigned ID,
49 StringRef ClangModuleName, DWARFFile &File,
50 OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format,
51 support::endianness Endianess)
52 : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
53 getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded) {
54 UnitName = File.FileName;
55 setOutputFormat(Format, Endianess);
58 CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, unsigned ID,
59 StringRef ClangModuleName, DWARFFile &File,
60 OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format,
61 support::endianness Endianess)
62 : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
63 OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset),
64 Stage(Stage::CreatedNotLoaded) {
65 DWARFDie CUDie = OrigUnit.getUnitDIE();
66 if (!CUDie)
67 return;
69 setOutputFormat(Format, Endianess);
71 Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0);
72 if (const char *CUName = CUDie.getName(DINameKind::ShortName))
73 UnitName = CUName;
74 else
75 UnitName = File.FileName;
76 SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
79 /// Returns stage of overall processing.
80 Stage getStage() const { return Stage; }
82 /// Set stage of overall processing.
83 void setStage(Stage Stage) { this->Stage = Stage; }
85 /// Loads unit line table.
86 void loadLineTable();
88 /// Returns name of the file for the \p FileIdx
89 /// from the unit`s line table.
90 StringEntry *getFileName(unsigned FileIdx, StringPool &GlobalStrings);
92 /// Returns DWARFFile containing this compile unit.
93 const DWARFFile &getContaingFile() const { return File; }
95 /// Load DIEs of input compilation unit. \returns true if input DIEs
96 /// successfully loaded.
97 bool loadInputDIEs();
99 /// Reset compile units data(results of liveness analysis, clonning)
100 /// if current stage greater than Stage::Loaded. We need to reset data
101 /// as we are going to repeat stages.
102 void maybeResetToLoadedStage();
104 /// Collect references to parseable Swift interfaces in imported
105 /// DW_TAG_module blocks.
106 void analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry);
108 /// Navigate DWARF tree and set die properties.
109 void analyzeDWARFStructure() {
110 analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false, false);
113 /// Cleanup unneeded resources after compile unit is cloned.
114 void cleanupDataAfterClonning();
116 /// After cloning stage the output DIEs offsets are deallocated.
117 /// This method copies output offsets for referenced DIEs into DIEs patches.
118 void updateDieRefPatchesWithClonedOffsets();
120 /// Kinds of placement for the output die.
121 enum DieOutputPlacement : uint8_t {
122 NotSet = 0,
124 /// Corresponding DIE goes to the type table only.
125 /// NOTE: Not used yet.
126 TypeTable = 1,
128 /// Corresponding DIE goes to the plain dwarf only.
129 PlainDwarf = 2,
131 /// Corresponding DIE goes to type table and to plain dwarf.
132 /// NOTE: Not used yet.
133 Both = 3,
135 /// Corresponding DIE needs to examine parent to determine
136 /// the point of placement.
137 /// NOTE: Not used yet.
138 Parent = 4
141 /// Information gathered about source DIEs.
142 struct DIEInfo {
143 DIEInfo() = default;
144 DIEInfo(const DIEInfo &Other) { Flags = Other.Flags.load(); }
145 DIEInfo &operator=(const DIEInfo &Other) {
146 Flags = Other.Flags.load();
147 return *this;
150 /// Data member keeping various flags.
151 std::atomic<uint16_t> Flags = {0};
153 /// \returns Placement kind for the corresponding die.
154 DieOutputPlacement getPlacement() const {
155 return DieOutputPlacement(Flags & 0x7);
158 /// Sets Placement kind for the corresponding die.
159 void setPlacement(DieOutputPlacement Placement) {
160 auto InputData = Flags.load();
161 while (!Flags.compare_exchange_weak(InputData,
162 ((InputData & ~0x7) | Placement))) {
166 /// Unsets Placement kind for the corresponding die.
167 void unsetPlacement() {
168 auto InputData = Flags.load();
169 while (!Flags.compare_exchange_weak(InputData, (InputData & ~0x7))) {
173 /// Sets Placement kind for the corresponding die.
174 bool setPlacementIfUnset(DieOutputPlacement Placement) {
175 auto InputData = Flags.load();
176 if ((InputData & 0x7) == NotSet)
177 if (Flags.compare_exchange_weak(InputData, (InputData | Placement)))
178 return true;
180 return false;
183 #define SINGLE_FLAG_METHODS_SET(Name, Value) \
184 bool get##Name() const { return Flags & Value; } \
185 void set##Name() { \
186 auto InputData = Flags.load(); \
187 while (!Flags.compare_exchange_weak(InputData, InputData | Value)) { \
190 void unset##Name() { \
191 auto InputData = Flags.load(); \
192 while (!Flags.compare_exchange_weak(InputData, InputData & ~Value)) { \
196 /// DIE is a part of the linked output.
197 SINGLE_FLAG_METHODS_SET(Keep, 0x08)
199 /// DIE has children which are part of the linked output.
200 SINGLE_FLAG_METHODS_SET(KeepChildren, 0x10)
202 /// DIE is referenced by other DIE.
203 SINGLE_FLAG_METHODS_SET(ReferrencedBy, 0x20)
205 /// DIE is in module scope.
206 SINGLE_FLAG_METHODS_SET(IsInMouduleScope, 0x40)
208 /// DIE is in function scope.
209 SINGLE_FLAG_METHODS_SET(IsInFunctionScope, 0x80)
211 void unsetFlagsWhichSetDuringLiveAnalysis() {
212 auto InputData = Flags.load();
213 while (!Flags.compare_exchange_weak(
214 InputData, InputData & ~(0x7 | 0x8 | 0x10 | 0x20))) {
218 /// Erase all flags.
219 void eraseData() { Flags = 0; }
221 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
222 LLVM_DUMP_METHOD void dump();
223 #endif
226 /// \defgroup Group of functions returning DIE info.
228 /// @{
230 /// \p Idx index of the DIE.
231 /// \returns DieInfo descriptor.
232 DIEInfo &getDIEInfo(unsigned Idx) { return DieInfoArray[Idx]; }
234 /// \p Idx index of the DIE.
235 /// \returns DieInfo descriptor.
236 const DIEInfo &getDIEInfo(unsigned Idx) const { return DieInfoArray[Idx]; }
238 /// \p Idx index of the DIE.
239 /// \returns DieInfo descriptor.
240 DIEInfo &getDIEInfo(const DWARFDebugInfoEntry *Entry) {
241 return DieInfoArray[getOrigUnit().getDIEIndex(Entry)];
244 /// \p Idx index of the DIE.
245 /// \returns DieInfo descriptor.
246 const DIEInfo &getDIEInfo(const DWARFDebugInfoEntry *Entry) const {
247 return DieInfoArray[getOrigUnit().getDIEIndex(Entry)];
250 /// \p Die
251 /// \returns PlainDieInfo descriptor.
252 DIEInfo &getDIEInfo(const DWARFDie &Die) {
253 return DieInfoArray[getOrigUnit().getDIEIndex(Die)];
256 /// \p Die
257 /// \returns PlainDieInfo descriptor.
258 const DIEInfo &getDIEInfo(const DWARFDie &Die) const {
259 return DieInfoArray[getOrigUnit().getDIEIndex(Die)];
262 /// \p Idx index of the DIE.
263 /// \returns DieInfo descriptor.
264 uint64_t getDieOutOffset(uint32_t Idx) {
265 return reinterpret_cast<std::atomic<uint64_t> *>(&OutDieOffsetArray[Idx])
266 ->load();
269 /// \p Idx index of the DIE.
270 /// \returns DieInfo descriptor.
271 void rememberDieOutOffset(uint32_t Idx, uint64_t Offset) {
272 reinterpret_cast<std::atomic<uint64_t> *>(&OutDieOffsetArray[Idx])
273 ->store(Offset);
276 /// @}
278 /// Returns value of DW_AT_low_pc attribute.
279 std::optional<uint64_t> getLowPc() const { return LowPc; }
281 /// Returns value of DW_AT_high_pc attribute.
282 uint64_t getHighPc() const { return HighPc; }
284 /// Returns true if there is a label corresponding to the specified \p Addr.
285 bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); }
287 /// Add the low_pc of a label that is relocated by applying
288 /// offset \p PCOffset.
289 void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset);
291 /// Resolve the DIE attribute reference that has been extracted in \p
292 /// RefValue. The resulting DIE might be in another CompileUnit.
293 /// \returns referenced die and corresponding compilation unit.
294 /// compilation unit is null if reference could not be resolved.
295 std::optional<std::pair<CompileUnit *, uint32_t>>
296 resolveDIEReference(const DWARFFormValue &RefValue);
297 /// @}
299 /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying
300 /// offset \p PCOffset.
301 void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset);
303 /// Returns function ranges of this unit.
304 const RangesTy &getFunctionRanges() const { return Ranges; }
306 /// Clone and emit this compilation unit.
307 Error cloneAndEmit(std::optional<Triple> TargetTriple);
309 /// Clone and emit debug locations(.debug_loc/.debug_loclists).
310 Error cloneAndEmitDebugLocations();
312 /// Clone and emit ranges.
313 Error cloneAndEmitRanges();
315 /// Clone and emit debug macros(.debug_macinfo/.debug_macro).
316 Error cloneAndEmitDebugMacro();
318 // Clone input DIE entry.
319 DIE *cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
320 std::optional<int64_t> FuncAddressAdjustment,
321 std::optional<int64_t> VarAddressAdjustment,
322 BumpPtrAllocator &Allocator);
324 // Clone and emit line table.
325 Error cloneAndEmitLineTable(Triple &TargetTriple);
327 /// Clone attribute location axpression.
328 void cloneDieAttrExpression(const DWARFExpression &InputExpression,
329 SmallVectorImpl<uint8_t> &OutputExpression,
330 SectionDescriptor &Section,
331 std::optional<int64_t> VarAddressAdjustment,
332 OffsetsPtrVector &PatchesOffsets);
334 /// Returns index(inside .debug_addr) of an address.
335 uint64_t getDebugAddrIndex(uint64_t Addr) {
336 return DebugAddrIndexMap.getValueIndex(Addr);
339 /// Returns index(inside .debug_str_offsets) of specified string.
340 uint64_t getDebugStrIndex(const StringEntry *String) {
341 return DebugStringIndexMap.getValueIndex(String);
344 /// \defgroup Helper methods to access OrigUnit.
346 /// @{
348 /// Returns paired compile unit from input DWARF.
349 DWARFUnit &getOrigUnit() const {
350 assert(OrigUnit != nullptr);
351 return *OrigUnit;
354 const DWARFDebugInfoEntry *
355 getFirstChildEntry(const DWARFDebugInfoEntry *Die) const {
356 assert(OrigUnit != nullptr);
357 return OrigUnit->getFirstChildEntry(Die);
360 const DWARFDebugInfoEntry *
361 getSiblingEntry(const DWARFDebugInfoEntry *Die) const {
362 assert(OrigUnit != nullptr);
363 return OrigUnit->getSiblingEntry(Die);
366 DWARFDie getParent(const DWARFDebugInfoEntry *Die) {
367 assert(OrigUnit != nullptr);
368 return OrigUnit->getParent(Die);
371 DWARFDie getDIEAtIndex(unsigned Index) {
372 assert(OrigUnit != nullptr);
373 return OrigUnit->getDIEAtIndex(Index);
376 const DWARFDebugInfoEntry *getDebugInfoEntry(unsigned Index) const {
377 assert(OrigUnit != nullptr);
378 return OrigUnit->getDebugInfoEntry(Index);
381 DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) {
382 assert(OrigUnit != nullptr);
383 return OrigUnit->getUnitDIE(ExtractUnitDIEOnly);
386 DWARFDie getDIE(const DWARFDebugInfoEntry *Die) {
387 assert(OrigUnit != nullptr);
388 return DWARFDie(OrigUnit, Die);
391 uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) const {
392 assert(OrigUnit != nullptr);
393 return OrigUnit->getDIEIndex(Die);
396 uint32_t getDIEIndex(const DWARFDie &Die) const {
397 assert(OrigUnit != nullptr);
398 return OrigUnit->getDIEIndex(Die);
401 std::optional<DWARFFormValue> find(uint32_t DieIdx,
402 ArrayRef<dwarf::Attribute> Attrs) const {
403 assert(OrigUnit != nullptr);
404 return find(OrigUnit->getDebugInfoEntry(DieIdx), Attrs);
407 std::optional<DWARFFormValue> find(const DWARFDebugInfoEntry *Die,
408 ArrayRef<dwarf::Attribute> Attrs) const {
409 if (!Die)
410 return std::nullopt;
411 auto AbbrevDecl = Die->getAbbreviationDeclarationPtr();
412 if (AbbrevDecl) {
413 for (auto Attr : Attrs) {
414 if (auto Value = AbbrevDecl->getAttributeValue(Die->getOffset(), Attr,
415 *OrigUnit))
416 return Value;
419 return std::nullopt;
422 std::optional<uint32_t> getDIEIndexForOffset(uint64_t Offset) {
423 return OrigUnit->getDIEIndexForOffset(Offset);
426 /// @}
428 /// \defgroup Methods used for reporting warnings and errors:
430 /// @{
432 void warn(const Twine &Warning, const DWARFDie *DIE = nullptr) {
433 GlobalData.warn(Warning, getUnitName(), DIE);
436 void warn(Error Warning, const DWARFDie *DIE = nullptr) {
437 handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
438 GlobalData.warn(Info.message(), getUnitName(), DIE);
442 void warn(const Twine &Warning, const DWARFDebugInfoEntry *DieEntry) {
443 if (DieEntry != nullptr) {
444 DWARFDie DIE(&getOrigUnit(), DieEntry);
445 GlobalData.warn(Warning, getUnitName(), &DIE);
446 return;
449 GlobalData.warn(Warning, getUnitName());
452 void error(const Twine &Err, const DWARFDie *DIE = nullptr) {
453 GlobalData.warn(Err, getUnitName(), DIE);
456 void error(Error Err, const DWARFDie *DIE = nullptr) {
457 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
458 GlobalData.error(Info.message(), getUnitName(), DIE);
462 /// @}
464 private:
465 /// Navigate DWARF tree recursively and set die properties.
466 void analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
467 bool IsInModule, bool IsInFunction);
469 struct LinkedLocationExpressionsWithOffsetPatches {
470 DWARFLocationExpression Expression;
471 OffsetsPtrVector Patches;
473 using LinkedLocationExpressionsVector =
474 SmallVector<LinkedLocationExpressionsWithOffsetPatches>;
476 /// Emit debug locations.
477 void emitLocations(DebugSectionKind LocationSectionKind);
479 /// Emit location list header.
480 uint64_t emitLocListHeader(SectionDescriptor &OutLocationSection);
482 /// Emit location list fragment.
483 uint64_t emitLocListFragment(
484 const LinkedLocationExpressionsVector &LinkedLocationExpression,
485 SectionDescriptor &OutLocationSection);
487 /// Emit the .debug_addr section fragment for current unit.
488 Error emitDebugAddrSection();
490 /// Emit the .debug_str_offsets section for current unit.
491 Error emitDebugStringOffsetSection();
493 /// Emit .debug_aranges.
494 void emitAranges(AddressRanges &LinkedFunctionRanges);
496 /// Clone and emit .debug_ranges/.debug_rnglists.
497 void cloneAndEmitRangeList(DebugSectionKind RngSectionKind,
498 AddressRanges &LinkedFunctionRanges);
500 /// Emit range list header.
501 uint64_t emitRangeListHeader(SectionDescriptor &OutRangeSection);
503 /// Emit range list fragment.
504 void emitRangeListFragment(const AddressRanges &LinkedRanges,
505 SectionDescriptor &OutRangeSection);
507 /// Insert the new line info sequence \p Seq into the current
508 /// set of already linked line info \p Rows.
509 void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
510 std::vector<DWARFDebugLine::Row> &Rows);
512 /// Emits body for both macro sections.
513 void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
514 uint64_t OffsetToMacroTable, bool hasDWARFv5Header);
516 /// DWARFFile containing this compile unit.
517 DWARFFile &File;
519 /// Pointer to the paired compile unit from the input DWARF.
520 DWARFUnit *OrigUnit = nullptr;
522 /// Line table for this unit.
523 const DWARFDebugLine::LineTable *LineTablePtr = nullptr;
525 /// Cached resolved paths from the line table.
526 /// The key is <UniqueUnitID, FileIdx>.
527 using ResolvedPathsMap = DenseMap<unsigned, StringEntry *>;
528 ResolvedPathsMap ResolvedFullPaths;
529 StringMap<StringEntry *> ResolvedParentPaths;
531 /// This field instructs compile unit to store DIE name with stripped
532 /// template parameters into the accelerator table.
533 bool CanStripTemplateName = false;
535 /// Maps an address into the index inside .debug_addr section.
536 IndexedValuesMap<uint64_t> DebugAddrIndexMap;
538 /// Maps a string into the index inside .debug_str_offsets section.
539 IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
541 /// \defgroup Data Members accessed asinchroniously.
543 /// @{
544 OffsetToUnitTy getUnitFromOffset;
546 std::optional<uint64_t> LowPc;
547 uint64_t HighPc = 0;
549 /// The ranges in that map are the PC ranges for functions in this unit,
550 /// associated with the PC offset to apply to the addresses to get
551 /// the linked address.
552 RangesTy Ranges;
553 std::mutex RangesMutex;
555 /// The DW_AT_low_pc of each DW_TAG_label.
556 SmallDenseMap<uint64_t, uint64_t, 1> Labels;
557 std::mutex LabelsMutex;
559 /// This field keeps current stage of overall compile unit processing.
560 std::atomic<Stage> Stage;
562 /// DIE info indexed by DIE index.
563 SmallVector<DIEInfo> DieInfoArray;
564 SmallVector<uint64_t> OutDieOffsetArray;
565 /// @}
568 } // end of namespace dwarflinker_parallel
569 } // end namespace llvm
571 #endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H