Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED
8 : #define ASMJIT_CORE_CONSTPOOL_H_INCLUDED
9 :
10 : #include "support.h"
11 : #include "zone.h"
12 : #include "zonetree.h"
13 :
14 : ASMJIT_BEGIN_NAMESPACE
15 :
16 : //! \addtogroup asmjit_utilities
17 : //! \{
18 :
19 : //! Constant pool scope.
20 : enum class ConstPoolScope : uint32_t {
21 : //! Local constant, always embedded right after the current function.
22 : kLocal = 0,
23 : //! Global constant, embedded at the end of the currently compiled code.
24 : kGlobal = 1,
25 :
26 : //! Maximum value of `ConstPoolScope`.
27 : kMaxValue = kGlobal
28 : };
29 :
30 : //! Constant pool.
31 : class ConstPool {
32 : public:
33 : ASMJIT_NONCOPYABLE(ConstPool)
34 :
35 : //! \cond INTERNAL
36 :
37 : //! Index of a given size in const-pool table.
38 : enum Index : uint32_t {
39 : kIndex1 = 0,
40 : kIndex2 = 1,
41 : kIndex4 = 2,
42 : kIndex8 = 3,
43 : kIndex16 = 4,
44 : kIndex32 = 5,
45 : kIndex64 = 6,
46 : kIndexCount = 7
47 : };
48 :
49 : //! Zone-allocated const-pool gap created by two differently aligned constants.
50 : struct Gap {
51 : //! Pointer to the next gap
52 : Gap* _next;
53 : //! Offset of the gap.
54 : size_t _offset;
55 : //! Remaining bytes of the gap (basically a gap size).
56 : size_t _size;
57 : };
58 :
59 : //! Zone-allocated const-pool node.
60 : class Node : public ZoneTreeNodeT<Node> {
61 : public:
62 : ASMJIT_NONCOPYABLE(Node)
63 :
64 : //! If this constant is shared with another.
65 : uint32_t _shared : 1;
66 : //! Data offset from the beginning of the pool.
67 : uint32_t _offset;
68 :
69 : inline Node(size_t offset, bool shared) noexcept
70 0 : : ZoneTreeNodeT<Node>(),
71 0 : _shared(shared),
72 0 : _offset(uint32_t(offset)) {}
73 :
74 : inline void* data() const noexcept {
75 0 : return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1);
76 : }
77 : };
78 :
79 : //! Data comparer used internally.
80 : class Compare {
81 : public:
82 : size_t _dataSize;
83 :
84 : inline Compare(size_t dataSize) noexcept
85 0 : : _dataSize(dataSize) {}
86 :
87 : inline int operator()(const Node& a, const Node& b) const noexcept {
88 0 : return ::memcmp(a.data(), b.data(), _dataSize);
89 : }
90 :
91 : inline int operator()(const Node& a, const void* data) const noexcept {
92 0 : return ::memcmp(a.data(), data, _dataSize);
93 : }
94 : };
95 :
96 : //! Zone-allocated const-pool tree.
97 : struct Tree {
98 : //! RB tree.
99 : ZoneTree<Node> _tree;
100 : //! Size of the tree (number of nodes).
101 : size_t _size;
102 : //! Size of the data.
103 : size_t _dataSize;
104 :
105 : inline explicit Tree(size_t dataSize = 0) noexcept
106 0 : : _tree(),
107 0 : _size(0),
108 0 : _dataSize(dataSize) {}
109 :
110 : inline void reset() noexcept {
111 : _tree.reset();
112 0 : _size = 0;
113 : }
114 :
115 : inline bool empty() const noexcept { return _size == 0; }
116 : inline size_t size() const noexcept { return _size; }
117 :
118 : inline void setDataSize(size_t dataSize) noexcept {
119 : ASMJIT_ASSERT(empty());
120 0 : _dataSize = dataSize;
121 : }
122 :
123 : inline Node* get(const void* data) noexcept {
124 0 : Compare cmp(_dataSize);
125 0 : return _tree.get(data, cmp);
126 : }
127 :
128 0 : inline void insert(Node* node) noexcept {
129 0 : Compare cmp(_dataSize);
130 0 : _tree.insert(node, cmp);
131 0 : _size++;
132 0 : }
133 :
134 : template<typename Visitor>
135 0 : inline void forEach(Visitor& visitor) const noexcept {
136 : Node* node = _tree.root();
137 0 : if (!node) return;
138 :
139 : Node* stack[Globals::kMaxTreeHeight];
140 : size_t top = 0;
141 :
142 : for (;;) {
143 : Node* left = node->left();
144 0 : if (left != nullptr) {
145 : ASMJIT_ASSERT(top != Globals::kMaxTreeHeight);
146 0 : stack[top++] = node;
147 :
148 : node = left;
149 0 : continue;
150 : }
151 :
152 : for (;;) {
153 0 : visitor(node);
154 : node = node->right();
155 :
156 0 : if (node != nullptr)
157 : break;
158 :
159 0 : if (top == 0)
160 : return;
161 :
162 0 : node = stack[--top];
163 : }
164 : }
165 : }
166 :
167 0 : static inline Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept {
168 0 : Node* node = zone->allocT<Node>(sizeof(Node) + size);
169 0 : if (ASMJIT_UNLIKELY(!node)) return nullptr;
170 :
171 : node = new(node) Node(offset, shared);
172 : memcpy(node->data(), data, size);
173 0 : return node;
174 : }
175 : };
176 :
177 : //! \endcond
178 :
179 : //! \name Members
180 : //! \{
181 :
182 : //! Zone allocator.
183 : Zone* _zone;
184 : //! Tree per size.
185 : Tree _tree[kIndexCount];
186 : //! Gaps per size.
187 : Gap* _gaps[kIndexCount];
188 : //! Gaps pool
189 : Gap* _gapPool;
190 :
191 : //! Size of the pool (in bytes).
192 : size_t _size;
193 : //! Required pool alignment.
194 : size_t _alignment;
195 : //! Minimum item size in the pool.
196 : size_t _minItemSize;
197 :
198 : //! \}
199 :
200 : //! \name Construction & Destruction
201 : //! \{
202 :
203 : ASMJIT_API ConstPool(Zone* zone) noexcept;
204 : ASMJIT_API ~ConstPool() noexcept;
205 :
206 : ASMJIT_API void reset(Zone* zone) noexcept;
207 :
208 : //! \}
209 :
210 : //! \name Accessors
211 : //! \{
212 :
213 : //! Tests whether the constant-pool is empty.
214 : inline bool empty() const noexcept { return _size == 0; }
215 : //! Returns the size of the constant-pool in bytes.
216 0 : inline size_t size() const noexcept { return _size; }
217 : //! Returns minimum alignment.
218 0 : inline size_t alignment() const noexcept { return _alignment; }
219 : //! Returns the minimum size of all items added to the constant pool.
220 0 : inline size_t minItemSize() const noexcept { return _minItemSize; }
221 :
222 : //! \}
223 :
224 : //! \name Utilities
225 : //! \{
226 :
227 : //! Adds a constant to the constant pool.
228 : //!
229 : //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes. The constant is added to the pool only
230 : //! if it doesn't not exist, otherwise cached value is returned.
231 : //!
232 : //! AsmJit is able to subdivide added constants, so for example if you add 8-byte constant 0x1122334455667788 it
233 : //! will create the following slots:
234 : //!
235 : //! 8-byte: 0x1122334455667788
236 : //! 4-byte: 0x11223344, 0x55667788
237 : //!
238 : //! The reason is that when combining MMX/SSE/AVX code some patterns are used frequently. However, AsmJit is not
239 : //! able to reallocate a constant that has been already added. For example if you try to add 4-byte constant and
240 : //! then 8-byte constant having the same 4-byte pattern as the previous one, two independent slots will be used.
241 : ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
242 :
243 : //! Fills the destination with the content of this constant pool.
244 : ASMJIT_API void fill(void* dst) const noexcept;
245 : };
246 :
247 : //! \}
248 :
249 : ASMJIT_END_NAMESPACE
250 :
251 : #endif // ASMJIT_CORE_CONSTPOOL_H_INCLUDED
252 :
253 : #endif // __PLUMED_HAS_ASMJIT
|