Revert " [LoongArch][ISel] Check the number of sign bits in `PatGprGpr_32` (#107432)"
[llvm-project.git] / llvm / lib / DWARFLinker / Parallel / ArrayList.h
blobc48f828609be2fdd1cf0436502b4cbc1ea664c3e
1 //===- ArrayList.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_DWARFLINKER_PARALLEL_ARRAYLIST_H
10 #define LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H
12 #include "llvm/Support/PerThreadBumpPtrAllocator.h"
13 #include <atomic>
15 namespace llvm {
16 namespace dwarf_linker {
17 namespace parallel {
19 /// This class is a simple list of T structures. It keeps elements as
20 /// pre-allocated groups to save memory for each element's next pointer.
21 /// It allocates internal data using specified per-thread BumpPtrAllocator.
22 /// Method add() can be called asynchronously.
23 template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
24 public:
25 ArrayList(llvm::parallel::PerThreadBumpPtrAllocator *Allocator)
26 : Allocator(Allocator) {}
28 /// Add specified \p Item to the list.
29 T &add(const T &Item) {
30 assert(Allocator);
32 // Allocate head group if it is not allocated yet.
33 while (!LastGroup) {
34 if (allocateNewGroup(GroupsHead))
35 LastGroup = GroupsHead.load();
38 ItemsGroup *CurGroup;
39 size_t CurItemsCount;
40 do {
41 CurGroup = LastGroup;
42 CurItemsCount = CurGroup->ItemsCount.fetch_add(1);
44 // Check whether current group is full.
45 if (CurItemsCount < ItemsGroupSize)
46 break;
48 // Allocate next group if necessary.
49 if (!CurGroup->Next)
50 allocateNewGroup(CurGroup->Next);
52 LastGroup.compare_exchange_weak(CurGroup, CurGroup->Next);
53 } while (true);
55 // Store item into the current group.
56 CurGroup->Items[CurItemsCount] = Item;
57 return CurGroup->Items[CurItemsCount];
60 using ItemHandlerTy = function_ref<void(T &)>;
62 /// Enumerate all items and apply specified \p Handler to each.
63 void forEach(ItemHandlerTy Handler) {
64 for (ItemsGroup *CurGroup = GroupsHead; CurGroup;
65 CurGroup = CurGroup->Next) {
66 for (T &Item : *CurGroup)
67 Handler(Item);
71 /// Check whether list is empty.
72 bool empty() { return !GroupsHead; }
74 /// Erase list.
75 void erase() {
76 GroupsHead = nullptr;
77 LastGroup = nullptr;
80 void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) {
81 SmallVector<T> SortedItems;
82 forEach([&](T &Item) { SortedItems.push_back(Item); });
84 if (SortedItems.size()) {
85 std::sort(SortedItems.begin(), SortedItems.end(), Comparator);
87 size_t SortedItemIdx = 0;
88 forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });
89 assert(SortedItemIdx == SortedItems.size());
93 size_t size() {
94 size_t Result = 0;
96 for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
97 CurGroup = CurGroup->Next)
98 Result += CurGroup->getItemsCount();
100 return Result;
103 protected:
104 struct ItemsGroup {
105 using ArrayTy = std::array<T, ItemsGroupSize>;
107 // Array of items kept by this group.
108 ArrayTy Items;
110 // Pointer to the next items group.
111 std::atomic<ItemsGroup *> Next = nullptr;
113 // Number of items in this group.
114 // NOTE: ItemsCount could be inaccurate as it might be incremented by
115 // several threads. Use getItemsCount() method to get real number of items
116 // inside ItemsGroup.
117 std::atomic<size_t> ItemsCount = 0;
119 size_t getItemsCount() const {
120 return std::min(ItemsCount.load(), ItemsGroupSize);
123 typename ArrayTy::iterator begin() { return Items.begin(); }
124 typename ArrayTy::iterator end() { return Items.begin() + getItemsCount(); }
127 // Allocate new group. Put allocated group into the \p AtomicGroup if
128 // it is empty. If \p AtomicGroup is filled by another thread then
129 // put allocated group into the end of groups list.
130 // \returns true if allocated group is put into the \p AtomicGroup.
131 bool allocateNewGroup(std::atomic<ItemsGroup *> &AtomicGroup) {
132 ItemsGroup *CurGroup = nullptr;
134 // Allocate new group.
135 ItemsGroup *NewGroup = Allocator->Allocate<ItemsGroup>();
136 NewGroup->ItemsCount = 0;
137 NewGroup->Next = nullptr;
139 // Try to replace current group with allocated one.
140 if (AtomicGroup.compare_exchange_weak(CurGroup, NewGroup))
141 return true;
143 // Put allocated group as last group.
144 while (CurGroup) {
145 ItemsGroup *NextGroup = CurGroup->Next;
147 if (!NextGroup) {
148 if (CurGroup->Next.compare_exchange_weak(NextGroup, NewGroup))
149 break;
152 CurGroup = NextGroup;
155 return false;
158 std::atomic<ItemsGroup *> GroupsHead = nullptr;
159 std::atomic<ItemsGroup *> LastGroup = nullptr;
160 llvm::parallel::PerThreadBumpPtrAllocator *Allocator = nullptr;
163 } // end of namespace parallel
164 } // end of namespace dwarf_linker
165 } // end of namespace llvm
167 #endif // LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H