aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
blob: b0b6ad3a1e8cfaafb31dec51ebd58ec56ef98225 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
//===- "DependencyTracker.h" ------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H
#define LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H

#include "DWARFLinkerCompileUnit.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"

namespace llvm {
class DWARFDebugInfoEntry;
class DWARFDie;

namespace dwarflinker_parallel {

/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE
/// locations (whether DIE should be cloned as regular DIE or it should be put
/// into the artificial type unit).
class DependencyTracker {
public:
  DependencyTracker(CompileUnit &CU) : CU(CU) {}

  /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
  /// information in \p CU's DIEInfo.
  ///
  /// This function is the entry point of the DIE selection algorithm. It is
  /// expected to walk the DIE tree and(through the mediation of
  /// Context.File.Addresses) ask for relocation adjustment value on each
  /// DIE that might be a 'root DIE'(f.e. subprograms, variables).
  ///
  /// Returns true if all dependencies are correctly discovered. Inter-CU
  /// dependencies cannot be discovered if referenced CU is not analyzed yet.
  /// If that is the case this method returns false.
  bool resolveDependenciesAndMarkLiveness(
      bool InterCUProcessingStarted,
      std::atomic<bool> &HasNewInterconnectedCUs);

  /// Check if dependencies have incompatible placement.
  /// If that is the case modify placement to be compatible.
  /// \returns true if any placement was updated, otherwise returns false.
  /// This method should be called as a followup processing after
  /// resolveDependenciesAndMarkLiveness().
  bool updateDependenciesCompleteness();

  /// Recursively walk the \p DIE tree and check "keepness" and "placement"
  /// information. It is an error if parent node does not have "keep" flag,
  /// while child has one. It is an error if parent node has "TypeTable"
  /// placement while child has "PlainDwarf" placement. This function dump error
  /// at stderr in that case.
  void verifyKeepChain();

protected:
  enum class LiveRootWorklistActionTy : uint8_t {
    /// Mark current item as live entry.
    MarkSingleLiveEntry = 0,

    /// Mark current item as type entry.
    MarkSingleTypeEntry,

    /// Mark current item and all its children as live entry.
    MarkLiveEntryRec,

    /// Mark current item and all its children as type entry.
    MarkTypeEntryRec,

    /// Mark all children of current item as live entry.
    MarkLiveChildrenRec,

    /// Mark all children of current item as type entry.
    MarkTypeChildrenRec,
  };

  /// \returns true if the specified action is for the "PlainDwarf".
  bool isLiveAction(LiveRootWorklistActionTy Action) {
    switch (Action) {
    default:
      return false;

    case LiveRootWorklistActionTy::MarkSingleLiveEntry:
    case LiveRootWorklistActionTy::MarkLiveEntryRec:
    case LiveRootWorklistActionTy::MarkLiveChildrenRec:
      return true;
    }
  }

  /// \returns true if the specified action is for the "TypeTable".
  bool isTypeAction(LiveRootWorklistActionTy Action) {
    switch (Action) {
    default:
      return false;

    case LiveRootWorklistActionTy::MarkSingleTypeEntry:
    case LiveRootWorklistActionTy::MarkTypeEntryRec:
    case LiveRootWorklistActionTy::MarkTypeChildrenRec:
      return true;
    }
  }

  /// \returns true if the specified action affects only Root entry
  /// itself and does not affect it`s children.
  bool isSingleAction(LiveRootWorklistActionTy Action) {
    switch (Action) {
    default:
      return false;

    case LiveRootWorklistActionTy::MarkSingleLiveEntry:
    case LiveRootWorklistActionTy::MarkSingleTypeEntry:
      return true;
    }
  }

  /// \returns true if the specified action affects only Root entry
  /// itself and does not affect it`s children.
  bool isChildrenAction(LiveRootWorklistActionTy Action) {
    switch (Action) {
    default:
      return false;

    case LiveRootWorklistActionTy::MarkLiveChildrenRec:
    case LiveRootWorklistActionTy::MarkTypeChildrenRec:
      return true;
    }
  }

  /// Class keeping live worklist item data.
  class LiveRootWorklistItemTy {
  public:
    LiveRootWorklistItemTy() = default;
    LiveRootWorklistItemTy(const LiveRootWorklistItemTy &) = default;
    LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
                           UnitEntryPairTy RootEntry) {
      RootCU.setInt(Action);
      RootCU.setPointer(RootEntry.CU);

      RootDieEntry = RootEntry.DieEntry;
    }
    LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
                           UnitEntryPairTy RootEntry,
                           UnitEntryPairTy ReferencedBy) {
      RootCU.setPointer(RootEntry.CU);
      RootCU.setInt(Action);
      RootDieEntry = RootEntry.DieEntry;

      ReferencedByCU = ReferencedBy.CU;
      ReferencedByDieEntry = ReferencedBy.DieEntry;
    }

    UnitEntryPairTy getRootEntry() const {
      return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry};
    }

    CompileUnit::DieOutputPlacement getPlacement() const {
      return static_cast<CompileUnit::DieOutputPlacement>(RootCU.getInt());
    }

    bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; }

    UnitEntryPairTy getReferencedByEntry() const {
      assert(ReferencedByCU);
      assert(ReferencedByDieEntry);
      return UnitEntryPairTy{ReferencedByCU, ReferencedByDieEntry};
    }

    LiveRootWorklistActionTy getAction() const {
      return static_cast<LiveRootWorklistActionTy>(RootCU.getInt());
    }

  protected:
    /// Root entry.
    /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
    /// Thus LiveRootWorklistActionTy should have no more eight elements.

    /// Pointer traits for CompileUnit.
    struct CompileUnitPointerTraits {
      static inline void *getAsVoidPointer(CompileUnit *P) { return P; }
      static inline CompileUnit *getFromVoidPointer(void *P) {
        return (CompileUnit *)P;
      }
      static constexpr int NumLowBitsAvailable = 3;
      static_assert(
          alignof(CompileUnit) >= (1 << NumLowBitsAvailable),
          "CompileUnit insufficiently aligned to have enough low bits.");
    };

    PointerIntPair<CompileUnit *, 3, LiveRootWorklistActionTy,
                   CompileUnitPointerTraits>
        RootCU;
    const DWARFDebugInfoEntry *RootDieEntry = nullptr;

    /// Another root entry which references this RootDieEntry.
    /// ReferencedByDieEntry is kept to update placement.
    /// if RootDieEntry has placement incompatible with placement
    /// of ReferencedByDieEntry then it should be updated.
    CompileUnit *ReferencedByCU = nullptr;
    const DWARFDebugInfoEntry *ReferencedByDieEntry = nullptr;
  };

  using RootEntriesListTy = SmallVector<LiveRootWorklistItemTy>;

  /// This function navigates DIEs tree starting from specified \p Entry.
  /// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries
  /// instructs to collect either live roots(like subprograms having live
  /// DW_AT_low_pc) or otherwise roots which is not live(they need to be
  /// collected if they are imported f.e. by DW_TAG_imported_module).
  void collectRootsToKeep(const UnitEntryPairTy &Entry,
                          std::optional<UnitEntryPairTy> ReferencedBy,
                          bool IsLiveParent);

  /// Returns true if specified variable references live code section.
  static bool isLiveVariableEntry(const UnitEntryPairTy &Entry,
                                  bool IsLiveParent);

  /// Returns true if specified subprogram references live code section.
  static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry);

  /// Examine worklist and mark all 'root DIE's as kept and set "Placement"
  /// property.
  bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,
                                    std::atomic<bool> &HasNewInterconnectedCUs);

  /// Mark whole DIE tree as kept recursively.
  bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,
                             const UnitEntryPairTy &RootEntry,
                             const UnitEntryPairTy &Entry,
                             bool InterCUProcessingStarted,
                             std::atomic<bool> &HasNewInterconnectedCUs);

  /// Mark parents as keeping children.
  void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry);

  /// Mark whole DIE tree as placed in "PlainDwarf".
  void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry);

  /// Check referenced DIEs and add them into the worklist.
  bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action,
                               const UnitEntryPairTy &RootEntry,
                               const UnitEntryPairTy &Entry,
                               bool InterCUProcessingStarted,
                               std::atomic<bool> &HasNewInterconnectedCUs);

  /// \returns true if \p DIEEntry can possibly be put into the artificial type
  /// unit.
  bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry);

  /// \returns root for the specified \p Entry.
  UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry);

  /// Add action item to the work list.
  void
  addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,
                                 const UnitEntryPairTy &Entry,
                                 std::optional<UnitEntryPairTy> ReferencedBy);

  CompileUnit &CU;

  /// List of entries which are 'root DIE's.
  RootEntriesListTy RootEntriesWorkList;

  /// List of entries dependencies.
  RootEntriesListTy Dependencies;
};

} // end namespace dwarflinker_parallel
} // end namespace llvm

#endif // LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H