1 //===- TypePool.h -----------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_DWARFLINKER_PARALLEL_TYPEPOOL_H
10 #define LLVM_DWARFLINKER_PARALLEL_TYPEPOOL_H
12 #include "ArrayList.h"
13 #include "llvm/ADT/ConcurrentHashtable.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/CodeGen/DIE.h"
16 #include "llvm/Support/Allocator.h"
20 namespace dwarf_linker
{
27 using TypeEntry
= StringMapEntry
<std::atomic
<TypeEntryBody
*>>;
29 /// Keeps cloned data for the type DIE.
32 /// Returns copy of type DIE which should be emitted into resulting file.
33 DIE
&getFinalDie() const {
37 assert(DeclarationDie
);
38 return *DeclarationDie
;
41 /// Returns true if type die entry has only declaration die.
42 bool hasOnlyDeclaration() const { return Die
== nullptr; }
44 /// Creates type DIE for the specified name.
45 static TypeEntryBody
*
46 create(llvm::parallel::PerThreadBumpPtrAllocator
&Allocator
) {
47 TypeEntryBody
*Result
= Allocator
.Allocate
<TypeEntryBody
>();
48 new (Result
) TypeEntryBody(Allocator
);
52 /// TypeEntryBody keeps partially cloned DIEs corresponding to this type.
53 /// The two kinds of DIE can be kept: declaration and definition.
54 /// If definition DIE was met while parsing input DWARF then this DIE would
55 /// be used as a final DIE for this type. If definition DIE is not met then
56 /// declaration DIE would be used as a final DIE.
58 // Keeps definition die.
59 std::atomic
<DIE
*> Die
= {nullptr};
61 // Keeps declaration die.
62 std::atomic
<DIE
*> DeclarationDie
= {nullptr};
64 // True if parent type die is declaration.
65 std::atomic
<bool> ParentIsDeclaration
= {true};
67 /// Children for current type.
68 ArrayList
<TypeEntry
*, 5> Children
;
71 TypeEntryBody() = delete;
72 TypeEntryBody(const TypeEntryBody
&RHS
) = delete;
73 TypeEntryBody(TypeEntryBody
&&RHS
) = delete;
74 TypeEntryBody
&operator=(const TypeEntryBody
&RHS
) = delete;
75 TypeEntryBody
&operator=(const TypeEntryBody
&&RHS
) = delete;
77 TypeEntryBody(llvm::parallel::PerThreadBumpPtrAllocator
&Allocator
)
78 : Children(&Allocator
) {}
83 /// \returns Hash value for the specified \p Key.
84 static inline uint64_t getHashValue(const StringRef
&Key
) {
85 return xxh3_64bits(Key
);
88 /// \returns true if both \p LHS and \p RHS are equal.
89 static inline bool isEqual(const StringRef
&LHS
, const StringRef
&RHS
) {
93 /// \returns key for the specified \p KeyData.
94 static inline StringRef
getKey(const TypeEntry
&KeyData
) {
95 return KeyData
.getKey();
98 /// \returns newly created object of KeyDataTy type.
99 static inline TypeEntry
*
100 create(const StringRef
&Key
,
101 llvm::parallel::PerThreadBumpPtrAllocator
&Allocator
) {
102 return TypeEntry::create(Key
, Allocator
);
106 /// TypePool keeps type descriptors which contain partially cloned DIE
107 /// correspinding to each type. Types are identified by names.
109 : ConcurrentHashTableByPtr
<StringRef
, TypeEntry
,
110 llvm::parallel::PerThreadBumpPtrAllocator
,
114 : ConcurrentHashTableByPtr
<StringRef
, TypeEntry
,
115 llvm::parallel::PerThreadBumpPtrAllocator
,
116 TypeEntryInfo
>(Allocator
) {
117 Root
= TypeEntry::create("", Allocator
);
118 Root
->getValue().store(TypeEntryBody::create(Allocator
));
121 TypeEntry
*insert(StringRef Name
) {
122 return ConcurrentHashTableByPtr
<StringRef
, TypeEntry
,
123 llvm::parallel::PerThreadBumpPtrAllocator
,
124 TypeEntryInfo
>::insert(Name
)
128 /// Create or return existing type entry body for the specified \p Entry.
129 /// Link that entry as child for the specified \p ParentEntry.
130 /// \returns The existing or created type entry body.
131 TypeEntryBody
*getOrCreateTypeEntryBody(TypeEntry
*Entry
,
132 TypeEntry
*ParentEntry
) {
133 TypeEntryBody
*DIE
= Entry
->getValue().load();
137 TypeEntryBody
*NewDIE
= TypeEntryBody::create(Allocator
);
138 if (Entry
->getValue().compare_exchange_weak(DIE
, NewDIE
)) {
139 ParentEntry
->getValue().load()->Children
.add(Entry
);
146 /// Sort children for each kept type entry.
148 std::function
<void(TypeEntry
* Entry
)> SortChildrenRec
=
149 [&](TypeEntry
*Entry
) {
150 Entry
->getValue().load()->Children
.sort(TypesComparator
);
151 Entry
->getValue().load()->Children
.forEach(SortChildrenRec
);
154 SortChildrenRec(getRoot());
157 /// Return root for all type entries.
158 TypeEntry
*getRoot() const { return Root
; }
160 /// Return thread local allocator used by pool.
161 BumpPtrAllocator
&getThreadLocalAllocator() {
162 return Allocator
.getThreadLocalAllocator();
166 std::function
<bool(const TypeEntry
*LHS
, const TypeEntry
*RHS
)>
167 TypesComparator
= [](const TypeEntry
*LHS
, const TypeEntry
*RHS
) -> bool {
168 return LHS
->getKey() < RHS
->getKey();
171 // Root of all type entries.
172 TypeEntry
*Root
= nullptr;
175 llvm::parallel::PerThreadBumpPtrAllocator Allocator
;
178 } // end of namespace parallel
179 } // end of namespace dwarf_linker
180 } // end of namespace llvm
182 #endif // LLVM_DWARFLINKER_PARALLEL_TYPEPOOL_H