Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Guard]
33 : #include "./asmjit_build.h"
34 : #if !defined(ASMJIT_DISABLE_BUILDER)
35 :
36 : // [Dependencies]
37 : #include "./codebuilder.h"
38 :
39 : // [Api-Begin]
40 : #include "./asmjit_apibegin.h"
41 :
42 : namespace PLMD {
43 : namespace asmjit {
44 :
45 : // ============================================================================
46 : // [asmjit::CodeBuilder - Construction / Destruction]
47 : // ============================================================================
48 :
49 1944 : CodeBuilder::CodeBuilder() noexcept
50 : : CodeEmitter(kTypeBuilder),
51 1944 : _cbBaseZone(32768 - Zone::kZoneOverhead),
52 1944 : _cbDataZone(16384 - Zone::kZoneOverhead),
53 1944 : _cbPassZone(32768 - Zone::kZoneOverhead),
54 1944 : _cbHeap(&_cbBaseZone),
55 : _cbPasses(),
56 : _cbLabels(),
57 1944 : _firstNode(nullptr),
58 1944 : _lastNode(nullptr),
59 1944 : _cursor(nullptr),
60 1944 : _position(0),
61 1944 : _nodeFlags(0) {}
62 1944 : CodeBuilder::~CodeBuilder() noexcept {}
63 :
64 : // ============================================================================
65 : // [asmjit::CodeBuilder - Events]
66 : // ============================================================================
67 :
68 1944 : Error CodeBuilder::onAttach(CodeHolder* code) noexcept {
69 1944 : return Base::onAttach(code);
70 : }
71 :
72 0 : Error CodeBuilder::onDetach(CodeHolder* code) noexcept {
73 : _cbPasses.reset();
74 : _cbLabels.reset();
75 0 : _cbHeap.reset(&_cbBaseZone);
76 :
77 0 : _cbBaseZone.reset(false);
78 0 : _cbDataZone.reset(false);
79 0 : _cbPassZone.reset(false);
80 :
81 0 : _position = 0;
82 0 : _nodeFlags = 0;
83 :
84 0 : _firstNode = nullptr;
85 0 : _lastNode = nullptr;
86 0 : _cursor = nullptr;
87 :
88 0 : return Base::onDetach(code);
89 : }
90 :
91 : // ============================================================================
92 : // [asmjit::CodeBuilder - Node-Factory]
93 : // ============================================================================
94 :
95 0 : Error CodeBuilder::getCBLabel(CBLabel** pOut, uint32_t id) noexcept {
96 0 : if (_lastError) return _lastError;
97 : ASMJIT_ASSERT(_code != nullptr);
98 :
99 0 : size_t index = Operand::unpackId(id);
100 0 : if (ASMJIT_UNLIKELY(index >= _code->getLabelsCount()))
101 : return DebugUtils::errored(kErrorInvalidLabel);
102 :
103 0 : if (index >= _cbLabels.getLength())
104 0 : ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
105 :
106 0 : CBLabel* node = _cbLabels[index];
107 0 : if (!node) {
108 : node = newNodeT<CBLabel>(id);
109 0 : if (ASMJIT_UNLIKELY(!node))
110 : return DebugUtils::errored(kErrorNoHeapMemory);
111 0 : _cbLabels[index] = node;
112 : }
113 :
114 0 : *pOut = node;
115 0 : return kErrorOk;
116 : }
117 :
118 3888 : Error CodeBuilder::registerLabelNode(CBLabel* node) noexcept {
119 3888 : if (_lastError) return _lastError;
120 : ASMJIT_ASSERT(_code != nullptr);
121 :
122 : // Don't call setLastError() from here, we are noexcept and we are called
123 : // by `newLabelNode()` and `newFuncNode()`, which are noexcept as well.
124 : uint32_t id;
125 3888 : ASMJIT_PROPAGATE(_code->newLabelId(id));
126 3888 : size_t index = Operand::unpackId(id);
127 :
128 : // We just added one label so it must be true.
129 : ASMJIT_ASSERT(_cbLabels.getLength() < index + 1);
130 3888 : ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
131 :
132 3888 : _cbLabels[index] = node;
133 3888 : node->_id = id;
134 3888 : return kErrorOk;
135 : }
136 :
137 1944 : CBLabel* CodeBuilder::newLabelNode() noexcept {
138 : CBLabel* node = newNodeT<CBLabel>();
139 1944 : if (!node || registerLabelNode(node) != kErrorOk)
140 0 : return nullptr;
141 : return node;
142 : }
143 :
144 0 : CBAlign* CodeBuilder::newAlignNode(uint32_t mode, uint32_t alignment) noexcept {
145 0 : return newNodeT<CBAlign>(mode, alignment);
146 : }
147 :
148 0 : CBData* CodeBuilder::newDataNode(const void* data, uint32_t size) noexcept {
149 0 : if (size > CBData::kInlineBufferSize) {
150 0 : void* cloned = _cbDataZone.alloc(size);
151 0 : if (!cloned) return nullptr;
152 :
153 0 : if (data) ::memcpy(cloned, data, size);
154 : data = cloned;
155 : }
156 :
157 0 : return newNodeT<CBData>(const_cast<void*>(data), size);
158 : }
159 :
160 0 : CBConstPool* CodeBuilder::newConstPool() noexcept {
161 : CBConstPool* node = newNodeT<CBConstPool>();
162 0 : if (!node || registerLabelNode(node) != kErrorOk)
163 0 : return nullptr;
164 : return node;
165 : }
166 :
167 0 : CBComment* CodeBuilder::newCommentNode(const char* s, size_t len) noexcept {
168 0 : if (s) {
169 0 : if (len == Globals::kInvalidIndex) len = ::strlen(s);
170 0 : if (len > 0) {
171 0 : s = static_cast<char*>(_cbDataZone.dup(s, len, true));
172 0 : if (!s) return nullptr;
173 : }
174 : }
175 :
176 0 : return newNodeT<CBComment>(s);
177 : }
178 :
179 : // ============================================================================
180 : // [asmjit::CodeBuilder - Code-Emitter]
181 : // ============================================================================
182 :
183 0 : Label CodeBuilder::newLabel() {
184 : uint32_t id = kInvalidValue;
185 :
186 0 : if (!_lastError) {
187 : CBLabel* node = newNodeT<CBLabel>(id);
188 0 : if (ASMJIT_UNLIKELY(!node)) {
189 0 : setLastError(DebugUtils::errored(kErrorNoHeapMemory));
190 : }
191 : else {
192 0 : Error err = registerLabelNode(node);
193 0 : if (ASMJIT_UNLIKELY(err))
194 0 : setLastError(err);
195 : else
196 : id = node->getId();
197 : }
198 : }
199 :
200 0 : return Label(id);
201 : }
202 :
203 0 : Label CodeBuilder::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
204 0 : uint32_t id = kInvalidValue;
205 :
206 0 : if (!_lastError) {
207 : CBLabel* node = newNodeT<CBLabel>(id);
208 0 : if (ASMJIT_UNLIKELY(!node)) {
209 0 : setLastError(DebugUtils::errored(kErrorNoHeapMemory));
210 : }
211 : else {
212 0 : Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
213 0 : if (ASMJIT_UNLIKELY(err))
214 0 : setLastError(err);
215 : else
216 0 : id = node->getId();
217 : }
218 : }
219 :
220 0 : return Label(id);
221 : }
222 :
223 0 : Error CodeBuilder::bind(const Label& label) {
224 0 : if (_lastError) return _lastError;
225 :
226 : CBLabel* node;
227 : Error err = getCBLabel(&node, label);
228 0 : if (ASMJIT_UNLIKELY(err))
229 0 : return setLastError(err);
230 :
231 0 : addNode(node);
232 0 : return kErrorOk;
233 : }
234 :
235 0 : Error CodeBuilder::align(uint32_t mode, uint32_t alignment) {
236 0 : if (_lastError) return _lastError;
237 :
238 0 : CBAlign* node = newAlignNode(mode, alignment);
239 0 : if (ASMJIT_UNLIKELY(!node))
240 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
241 :
242 0 : addNode(node);
243 0 : return kErrorOk;
244 : }
245 :
246 0 : Error CodeBuilder::embed(const void* data, uint32_t size) {
247 0 : if (_lastError) return _lastError;
248 :
249 0 : CBData* node = newDataNode(data, size);
250 0 : if (ASMJIT_UNLIKELY(!node))
251 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
252 :
253 0 : addNode(node);
254 0 : return kErrorOk;
255 : }
256 :
257 0 : Error CodeBuilder::embedLabel(const Label& label) {
258 0 : if (_lastError) return _lastError;
259 :
260 : CBLabelData* node = newNodeT<CBLabelData>(label.getId());
261 0 : if (ASMJIT_UNLIKELY(!node))
262 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
263 :
264 0 : addNode(node);
265 0 : return kErrorOk;
266 : }
267 :
268 0 : Error CodeBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
269 0 : if (_lastError) return _lastError;
270 :
271 0 : if (!isLabelValid(label))
272 0 : return setLastError(DebugUtils::errored(kErrorInvalidLabel));
273 :
274 0 : ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
275 0 : ASMJIT_PROPAGATE(bind(label));
276 :
277 0 : CBData* node = newDataNode(nullptr, static_cast<uint32_t>(pool.getSize()));
278 0 : if (ASMJIT_UNLIKELY(!node))
279 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
280 :
281 0 : pool.fill(node->getData());
282 0 : addNode(node);
283 0 : return kErrorOk;
284 : }
285 :
286 0 : Error CodeBuilder::comment(const char* s, size_t len) {
287 0 : if (_lastError) return _lastError;
288 :
289 0 : CBComment* node = newCommentNode(s, len);
290 0 : if (ASMJIT_UNLIKELY(!node))
291 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
292 :
293 0 : addNode(node);
294 0 : return kErrorOk;
295 : }
296 :
297 : // ============================================================================
298 : // [asmjit::CodeBuilder - Node-Management]
299 : // ============================================================================
300 :
301 56030 : CBNode* CodeBuilder::addNode(CBNode* node) noexcept {
302 : ASMJIT_ASSERT(node);
303 : ASMJIT_ASSERT(node->_prev == nullptr);
304 : ASMJIT_ASSERT(node->_next == nullptr);
305 :
306 56030 : if (!_cursor) {
307 1944 : if (!_firstNode) {
308 1944 : _firstNode = node;
309 1944 : _lastNode = node;
310 : }
311 : else {
312 0 : node->_next = _firstNode;
313 0 : _firstNode->_prev = node;
314 0 : _firstNode = node;
315 : }
316 : }
317 : else {
318 : CBNode* prev = _cursor;
319 54086 : CBNode* next = _cursor->_next;
320 :
321 54086 : node->_prev = prev;
322 54086 : node->_next = next;
323 :
324 54086 : prev->_next = node;
325 54086 : if (next)
326 50198 : next->_prev = node;
327 : else
328 3888 : _lastNode = node;
329 : }
330 :
331 56030 : _cursor = node;
332 56030 : return node;
333 : }
334 :
335 0 : CBNode* CodeBuilder::addAfter(CBNode* node, CBNode* ref) noexcept {
336 : ASMJIT_ASSERT(node);
337 : ASMJIT_ASSERT(ref);
338 :
339 : ASMJIT_ASSERT(node->_prev == nullptr);
340 : ASMJIT_ASSERT(node->_next == nullptr);
341 :
342 : CBNode* prev = ref;
343 0 : CBNode* next = ref->_next;
344 :
345 0 : node->_prev = prev;
346 0 : node->_next = next;
347 :
348 0 : prev->_next = node;
349 0 : if (next)
350 0 : next->_prev = node;
351 : else
352 0 : _lastNode = node;
353 :
354 0 : return node;
355 : }
356 :
357 0 : CBNode* CodeBuilder::addBefore(CBNode* node, CBNode* ref) noexcept {
358 : ASMJIT_ASSERT(node != nullptr);
359 : ASMJIT_ASSERT(node->_prev == nullptr);
360 : ASMJIT_ASSERT(node->_next == nullptr);
361 : ASMJIT_ASSERT(ref != nullptr);
362 :
363 0 : CBNode* prev = ref->_prev;
364 : CBNode* next = ref;
365 :
366 0 : node->_prev = prev;
367 0 : node->_next = next;
368 :
369 0 : next->_prev = node;
370 0 : if (prev)
371 0 : prev->_next = node;
372 : else
373 0 : _firstNode = node;
374 :
375 0 : return node;
376 : }
377 :
378 : static ASMJIT_INLINE void CodeBuilder_nodeRemoved(CodeBuilder* self, CBNode* node_) noexcept {
379 0 : if (node_->isJmpOrJcc()) {
380 : CBJump* node = static_cast<CBJump*>(node_);
381 : CBLabel* label = node->getTarget();
382 :
383 0 : if (label) {
384 : // Disconnect.
385 0 : CBJump** pPrev = &label->_from;
386 : for (;;) {
387 : ASMJIT_ASSERT(*pPrev != nullptr);
388 :
389 0 : CBJump* current = *pPrev;
390 0 : if (!current) break;
391 :
392 0 : if (current == node) {
393 0 : *pPrev = node->_jumpNext;
394 0 : break;
395 : }
396 :
397 0 : pPrev = ¤t->_jumpNext;
398 0 : }
399 :
400 : label->subNumRefs();
401 : }
402 : }
403 : }
404 :
405 0 : CBNode* CodeBuilder::removeNode(CBNode* node) noexcept {
406 0 : CBNode* prev = node->_prev;
407 0 : CBNode* next = node->_next;
408 :
409 0 : if (_firstNode == node)
410 0 : _firstNode = next;
411 : else
412 0 : prev->_next = next;
413 :
414 0 : if (_lastNode == node)
415 0 : _lastNode = prev;
416 : else
417 0 : next->_prev = prev;
418 :
419 0 : node->_prev = nullptr;
420 0 : node->_next = nullptr;
421 :
422 0 : if (_cursor == node)
423 0 : _cursor = prev;
424 : CodeBuilder_nodeRemoved(this, node);
425 :
426 0 : return node;
427 : }
428 :
429 0 : void CodeBuilder::removeNodes(CBNode* first, CBNode* last) noexcept {
430 0 : if (first == last) {
431 0 : removeNode(first);
432 0 : return;
433 : }
434 :
435 0 : CBNode* prev = first->_prev;
436 0 : CBNode* next = last->_next;
437 :
438 0 : if (_firstNode == first)
439 0 : _firstNode = next;
440 : else
441 0 : prev->_next = next;
442 :
443 0 : if (_lastNode == last)
444 0 : _lastNode = prev;
445 : else
446 0 : next->_prev = prev;
447 :
448 : CBNode* node = first;
449 : for (;;) {
450 : CBNode* next = node->getNext();
451 : ASMJIT_ASSERT(next != nullptr);
452 :
453 0 : node->_prev = nullptr;
454 0 : node->_next = nullptr;
455 :
456 0 : if (_cursor == node)
457 0 : _cursor = prev;
458 : CodeBuilder_nodeRemoved(this, node);
459 :
460 0 : if (node == last)
461 : break;
462 : node = next;
463 : }
464 : }
465 :
466 3888 : CBNode* CodeBuilder::setCursor(CBNode* node) noexcept {
467 3888 : CBNode* old = _cursor;
468 3888 : _cursor = node;
469 3888 : return old;
470 : }
471 :
472 : // ============================================================================
473 : // [asmjit::CodeBuilder - Passes]
474 : // ============================================================================
475 :
476 0 : ASMJIT_FAVOR_SIZE CBPass* CodeBuilder::getPassByName(const char* name) const noexcept {
477 0 : for (size_t i = 0, len = _cbPasses.getLength(); i < len; i++) {
478 0 : CBPass* pass = _cbPasses[i];
479 0 : if (::strcmp(pass->getName(), name) == 0)
480 0 : return pass;
481 : }
482 :
483 : return nullptr;
484 : }
485 :
486 1944 : ASMJIT_FAVOR_SIZE Error CodeBuilder::addPass(CBPass* pass) noexcept {
487 1944 : if (ASMJIT_UNLIKELY(pass == nullptr)) {
488 : // Since this is directly called by `addPassT()` we treat `null` argument
489 : // as out-of-memory condition. Otherwise it would be API misuse.
490 : return DebugUtils::errored(kErrorNoHeapMemory);
491 : }
492 1944 : else if (ASMJIT_UNLIKELY(pass->_cb)) {
493 : // Kind of weird, but okay...
494 0 : if (pass->_cb == this)
495 0 : return kErrorOk;
496 : return DebugUtils::errored(kErrorInvalidState);
497 : }
498 :
499 1944 : ASMJIT_PROPAGATE(_cbPasses.append(&_cbHeap, pass));
500 1944 : pass->_cb = this;
501 1944 : return kErrorOk;
502 : }
503 :
504 0 : ASMJIT_FAVOR_SIZE Error CodeBuilder::deletePass(CBPass* pass) noexcept {
505 0 : if (ASMJIT_UNLIKELY(pass == nullptr))
506 : return DebugUtils::errored(kErrorInvalidArgument);
507 :
508 0 : if (pass->_cb != nullptr) {
509 0 : if (pass->_cb != this)
510 : return DebugUtils::errored(kErrorInvalidState);
511 :
512 : size_t index = _cbPasses.indexOf(pass);
513 : ASMJIT_ASSERT(index != Globals::kInvalidIndex);
514 :
515 0 : pass->_cb = nullptr;
516 : _cbPasses.removeAt(index);
517 : }
518 :
519 0 : pass->~CBPass();
520 0 : return kErrorOk;
521 : }
522 :
523 : // ============================================================================
524 : // [asmjit::CodeBuilder - Serialization]
525 : // ============================================================================
526 :
527 1944 : Error CodeBuilder::serialize(CodeEmitter* dst) {
528 : Error err = kErrorOk;
529 : CBNode* node_ = getFirstNode();
530 :
531 : do {
532 : dst->setInlineComment(node_->getInlineComment());
533 :
534 56030 : switch (node_->getType()) {
535 0 : case CBNode::kNodeAlign: {
536 : CBAlign* node = static_cast<CBAlign*>(node_);
537 0 : err = dst->align(node->getMode(), node->getAlignment());
538 0 : break;
539 : }
540 :
541 0 : case CBNode::kNodeData: {
542 : CBData* node = static_cast<CBData*>(node_);
543 0 : err = dst->embed(node->getData(), node->getSize());
544 0 : break;
545 : }
546 :
547 3888 : case CBNode::kNodeFunc:
548 : case CBNode::kNodeLabel: {
549 : CBLabel* node = static_cast<CBLabel*>(node_);
550 3888 : err = dst->bind(node->getLabel());
551 3888 : break;
552 : }
553 :
554 0 : case CBNode::kNodeLabelData: {
555 : CBLabelData* node = static_cast<CBLabelData*>(node_);
556 0 : err = dst->embedLabel(node->getLabel());
557 0 : break;
558 : }
559 :
560 0 : case CBNode::kNodeConstPool: {
561 : CBConstPool* node = static_cast<CBConstPool*>(node_);
562 0 : err = dst->embedConstPool(node->getLabel(), node->getConstPool());
563 0 : break;
564 : }
565 :
566 : case CBNode::kNodeInst:
567 : case CBNode::kNodeFuncCall: {
568 : CBInst* node = node_->as<CBInst>();
569 : dst->setOptions(node->getOptions());
570 : dst->setExtraReg(node->getExtraReg());
571 48254 : err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount());
572 48254 : break;
573 : }
574 :
575 0 : case CBNode::kNodeComment: {
576 : CBComment* node = static_cast<CBComment*>(node_);
577 0 : err = dst->comment(node->getInlineComment());
578 0 : break;
579 : }
580 :
581 : default:
582 : break;
583 : }
584 :
585 56030 : if (err) break;
586 : node_ = node_->getNext();
587 56030 : } while (node_);
588 :
589 1944 : return err;
590 : }
591 :
592 : // ============================================================================
593 : // [asmjit::CBPass]
594 : // ============================================================================
595 :
596 1944 : CBPass::CBPass(const char* name) noexcept
597 1944 : : _cb(nullptr),
598 1944 : _name(name) {}
599 0 : CBPass::~CBPass() noexcept {}
600 :
601 : } // asmjit namespace
602 : } // namespace PLMD
603 :
604 : // [Api-End]
605 : #include "./asmjit_apiend.h"
606 :
607 : // [Guard]
608 : #endif // !ASMJIT_DISABLE_BUILDER
609 : #pragma GCC diagnostic pop
610 : #endif // __PLUMED_HAS_ASMJIT
|