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 : #include "api-build_p.h"
8 : #ifndef ASMJIT_NO_BUILDER
9 :
10 : #include "builder.h"
11 : #include "emitterutils_p.h"
12 : #include "errorhandler.h"
13 : #include "formatter.h"
14 : #include "logger.h"
15 : #include "support.h"
16 :
17 : ASMJIT_BEGIN_NAMESPACE
18 :
19 : // PostponedErrorHandler (Internal)
20 : // ================================
21 :
22 : //! Postponed error handler that never throws. Used as a temporal error handler
23 : //! to run passes. If error occurs, the caller is notified and will call the
24 : //! real error handler, that can throw.
25 : class PostponedErrorHandler : public ErrorHandler {
26 : public:
27 0 : void handleError(Error err, const char* message, BaseEmitter* origin) override {
28 : DebugUtils::unused(err, origin);
29 0 : _message.assign(message);
30 0 : }
31 :
32 : StringTmp<128> _message;
33 : };
34 :
35 : // BaseBuilder - Utilities
36 : // =======================
37 :
38 27492 : static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
39 82476 : for (Pass* pass : self->_passes)
40 54984 : pass->~Pass();
41 : self->_passes.reset();
42 27492 : }
43 :
44 : // BaseBuilder - Construction & Destruction
45 : // ========================================
46 :
47 27492 : BaseBuilder::BaseBuilder() noexcept
48 : : BaseEmitter(EmitterType::kBuilder),
49 27492 : _codeZone(32768 - Zone::kBlockOverhead),
50 27492 : _dataZone(16384 - Zone::kBlockOverhead),
51 27492 : _passZone(65536 - Zone::kBlockOverhead),
52 54984 : _allocator(&_codeZone) {}
53 :
54 27492 : BaseBuilder::~BaseBuilder() noexcept {
55 27492 : BaseBuilder_deletePasses(this);
56 27492 : }
57 :
58 : // BaseBuilder - Node Management
59 : // =============================
60 :
61 0 : Error BaseBuilder::newInstNode(InstNode** out, InstId instId, InstOptions instOptions, uint32_t opCount) {
62 : uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
63 : ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
64 :
65 0 : InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
66 0 : if (ASMJIT_UNLIKELY(!node))
67 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
68 :
69 0 : *out = new(node) InstNode(this, instId, instOptions, opCount, opCapacity);
70 0 : return kErrorOk;
71 : }
72 :
73 :
74 27492 : Error BaseBuilder::newLabelNode(LabelNode** out) {
75 27492 : *out = nullptr;
76 :
77 27492 : ASMJIT_PROPAGATE(_newNodeT<LabelNode>(out));
78 27492 : return registerLabelNode(*out);
79 : }
80 :
81 0 : Error BaseBuilder::newAlignNode(AlignNode** out, AlignMode alignMode, uint32_t alignment) {
82 0 : *out = nullptr;
83 0 : return _newNodeT<AlignNode>(out, alignMode, alignment);
84 : }
85 :
86 0 : Error BaseBuilder::newEmbedDataNode(EmbedDataNode** out, TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) {
87 0 : *out = nullptr;
88 :
89 : uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize());
90 : TypeId finalTypeId = TypeUtils::deabstract(typeId, deabstractDelta);
91 :
92 0 : if (ASMJIT_UNLIKELY(!TypeUtils::isValid(finalTypeId)))
93 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
94 :
95 : uint32_t typeSize = TypeUtils::sizeOf(finalTypeId);
96 : Support::FastUInt8 of = 0;
97 :
98 : size_t dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of);
99 0 : if (ASMJIT_UNLIKELY(of))
100 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
101 :
102 : EmbedDataNode* node;
103 0 : ASMJIT_PROPAGATE(_newNodeT<EmbedDataNode>(&node));
104 :
105 0 : node->_embed._typeId = typeId;
106 0 : node->_embed._typeSize = uint8_t(typeSize);
107 0 : node->_itemCount = itemCount;
108 0 : node->_repeatCount = repeatCount;
109 :
110 0 : uint8_t* dstData = node->_inlineData;
111 0 : if (dataSize > EmbedDataNode::kInlineBufferSize) {
112 0 : dstData = static_cast<uint8_t*>(_dataZone.alloc(dataSize, 8));
113 0 : if (ASMJIT_UNLIKELY(!dstData))
114 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
115 0 : node->_externalData = dstData;
116 : }
117 :
118 0 : if (data)
119 : memcpy(dstData, data, dataSize);
120 :
121 0 : *out = node;
122 0 : return kErrorOk;
123 : }
124 :
125 0 : Error BaseBuilder::newConstPoolNode(ConstPoolNode** out) {
126 0 : *out = nullptr;
127 :
128 0 : ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out));
129 0 : return registerLabelNode(*out);
130 : }
131 :
132 0 : Error BaseBuilder::newCommentNode(CommentNode** out, const char* data, size_t size) {
133 0 : *out = nullptr;
134 :
135 0 : if (data) {
136 0 : if (size == SIZE_MAX)
137 0 : size = strlen(data);
138 :
139 0 : if (size > 0) {
140 0 : data = static_cast<char*>(_dataZone.dup(data, size, true));
141 0 : if (ASMJIT_UNLIKELY(!data))
142 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
143 : }
144 : }
145 :
146 0 : return _newNodeT<CommentNode>(out, data);
147 : }
148 :
149 501977 : BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept {
150 : ASMJIT_ASSERT(!node->_prev);
151 : ASMJIT_ASSERT(!node->_next);
152 : ASMJIT_ASSERT(!node->isActive());
153 :
154 501977 : if (!_cursor) {
155 0 : if (!_firstNode) {
156 0 : _firstNode = node;
157 0 : _lastNode = node;
158 : }
159 : else {
160 0 : node->_next = _firstNode;
161 0 : _firstNode->_prev = node;
162 0 : _firstNode = node;
163 : }
164 : }
165 : else {
166 : BaseNode* prev = _cursor;
167 : BaseNode* next = _cursor->next();
168 :
169 501977 : node->_prev = prev;
170 501977 : node->_next = next;
171 :
172 501977 : prev->_next = node;
173 501977 : if (next)
174 419501 : next->_prev = node;
175 : else
176 82476 : _lastNode = node;
177 : }
178 :
179 : node->addFlags(NodeFlags::kIsActive);
180 501977 : if (node->isSection())
181 0 : _dirtySectionLinks = true;
182 :
183 501977 : _cursor = node;
184 501977 : return node;
185 : }
186 :
187 0 : BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept {
188 : ASMJIT_ASSERT(!node->_prev);
189 : ASMJIT_ASSERT(!node->_next);
190 :
191 : BaseNode* prev = ref;
192 : BaseNode* next = ref->next();
193 :
194 0 : node->_prev = prev;
195 0 : node->_next = next;
196 :
197 : node->addFlags(NodeFlags::kIsActive);
198 0 : if (node->isSection())
199 0 : _dirtySectionLinks = true;
200 :
201 0 : prev->_next = node;
202 0 : if (next)
203 0 : next->_prev = node;
204 : else
205 0 : _lastNode = node;
206 :
207 0 : return node;
208 : }
209 :
210 0 : BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept {
211 : ASMJIT_ASSERT(!node->_prev);
212 : ASMJIT_ASSERT(!node->_next);
213 : ASMJIT_ASSERT(!node->isActive());
214 : ASMJIT_ASSERT(ref->isActive());
215 :
216 : BaseNode* prev = ref->prev();
217 : BaseNode* next = ref;
218 :
219 0 : node->_prev = prev;
220 0 : node->_next = next;
221 :
222 : node->addFlags(NodeFlags::kIsActive);
223 0 : if (node->isSection())
224 0 : _dirtySectionLinks = true;
225 :
226 0 : next->_prev = node;
227 0 : if (prev)
228 0 : prev->_next = node;
229 : else
230 0 : _firstNode = node;
231 :
232 0 : return node;
233 : }
234 :
235 27492 : BaseNode* BaseBuilder::removeNode(BaseNode* node) noexcept {
236 27492 : if (!node->isActive())
237 : return node;
238 :
239 : BaseNode* prev = node->prev();
240 : BaseNode* next = node->next();
241 :
242 27492 : if (_firstNode == node)
243 0 : _firstNode = next;
244 : else
245 27492 : prev->_next = next;
246 :
247 27492 : if (_lastNode == node)
248 0 : _lastNode = prev;
249 : else
250 27492 : next->_prev = prev;
251 :
252 27492 : node->_prev = nullptr;
253 27492 : node->_next = nullptr;
254 : node->clearFlags(NodeFlags::kIsActive);
255 27492 : if (node->isSection())
256 0 : _dirtySectionLinks = true;
257 :
258 27492 : if (_cursor == node)
259 0 : _cursor = prev;
260 :
261 : return node;
262 : }
263 :
264 0 : void BaseBuilder::removeNodes(BaseNode* first, BaseNode* last) noexcept {
265 0 : if (first == last) {
266 0 : removeNode(first);
267 0 : return;
268 : }
269 :
270 0 : if (!first->isActive())
271 : return;
272 :
273 : BaseNode* prev = first->prev();
274 : BaseNode* next = last->next();
275 :
276 0 : if (_firstNode == first)
277 0 : _firstNode = next;
278 : else
279 0 : prev->_next = next;
280 :
281 0 : if (_lastNode == last)
282 0 : _lastNode = prev;
283 : else
284 0 : next->_prev = prev;
285 :
286 : BaseNode* node = first;
287 : uint32_t didRemoveSection = false;
288 :
289 : for (;;) {
290 : next = node->next();
291 : ASMJIT_ASSERT(next != nullptr);
292 :
293 0 : node->_prev = nullptr;
294 0 : node->_next = nullptr;
295 : node->clearFlags(NodeFlags::kIsActive);
296 0 : didRemoveSection |= uint32_t(node->isSection());
297 :
298 0 : if (_cursor == node)
299 0 : _cursor = prev;
300 :
301 0 : if (node == last)
302 : break;
303 : node = next;
304 : }
305 :
306 0 : if (didRemoveSection)
307 0 : _dirtySectionLinks = true;
308 : }
309 :
310 27492 : BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept {
311 27492 : BaseNode* old = _cursor;
312 27492 : _cursor = node;
313 27492 : return old;
314 : }
315 :
316 : // BaseBuilder - Sections
317 : // ======================
318 :
319 27492 : Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) {
320 27492 : *out = nullptr;
321 :
322 27492 : if (ASMJIT_UNLIKELY(!_code))
323 : return DebugUtils::errored(kErrorNotInitialized);
324 :
325 27492 : if (ASMJIT_UNLIKELY(!_code->isSectionValid(sectionId)))
326 0 : return reportError(DebugUtils::errored(kErrorInvalidSection));
327 :
328 27492 : if (sectionId >= _sectionNodes.size()) {
329 27492 : Error err = _sectionNodes.reserve(&_allocator, sectionId + 1);
330 27492 : if (ASMJIT_UNLIKELY(err != kErrorOk))
331 0 : return reportError(err);
332 : }
333 :
334 27492 : SectionNode* node = nullptr;
335 27492 : if (sectionId < _sectionNodes.size())
336 0 : node = _sectionNodes[sectionId];
337 :
338 27492 : if (!node) {
339 27492 : ASMJIT_PROPAGATE(_newNodeT<SectionNode>(&node, sectionId));
340 :
341 : // We have already reserved enough space, this cannot fail now.
342 27492 : if (sectionId >= _sectionNodes.size())
343 27492 : _sectionNodes.resize(&_allocator, sectionId + 1);
344 :
345 27492 : _sectionNodes[sectionId] = node;
346 : }
347 :
348 27492 : *out = node;
349 27492 : return kErrorOk;
350 : }
351 :
352 0 : Error BaseBuilder::section(Section* section) {
353 : SectionNode* node;
354 0 : ASMJIT_PROPAGATE(sectionNodeOf(&node, section->id()));
355 0 : ASMJIT_ASSUME(node != nullptr);
356 :
357 0 : if (!node->isActive()) {
358 : // Insert the section at the end if it was not part of the code.
359 0 : addAfter(node, lastNode());
360 0 : _cursor = node;
361 : }
362 : else {
363 : // This is a bit tricky. We cache section links to make sure that
364 : // switching sections doesn't involve traversal in linked-list unless
365 : // the position of the section has changed.
366 0 : if (hasDirtySectionLinks())
367 0 : updateSectionLinks();
368 :
369 0 : if (node->_nextSection)
370 0 : _cursor = node->_nextSection->_prev;
371 : else
372 0 : _cursor = _lastNode;
373 : }
374 :
375 : return kErrorOk;
376 : }
377 :
378 0 : void BaseBuilder::updateSectionLinks() noexcept {
379 0 : if (!_dirtySectionLinks)
380 : return;
381 :
382 0 : BaseNode* node_ = _firstNode;
383 : SectionNode* currentSection = nullptr;
384 :
385 0 : while (node_) {
386 0 : if (node_->isSection()) {
387 0 : if (currentSection)
388 0 : currentSection->_nextSection = node_->as<SectionNode>();
389 : currentSection = node_->as<SectionNode>();
390 : }
391 : node_ = node_->next();
392 : }
393 :
394 0 : if (currentSection)
395 0 : currentSection->_nextSection = nullptr;
396 :
397 0 : _dirtySectionLinks = false;
398 : }
399 :
400 : // BaseBuilder - Labels
401 : // ====================
402 :
403 0 : Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) {
404 0 : *out = nullptr;
405 :
406 0 : if (ASMJIT_UNLIKELY(!_code))
407 : return DebugUtils::errored(kErrorNotInitialized);
408 :
409 0 : uint32_t index = labelId;
410 0 : if (ASMJIT_UNLIKELY(index >= _code->labelCount()))
411 : return DebugUtils::errored(kErrorInvalidLabel);
412 :
413 0 : if (index >= _labelNodes.size())
414 0 : ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, index + 1));
415 :
416 0 : LabelNode* node = _labelNodes[index];
417 0 : if (!node) {
418 0 : ASMJIT_PROPAGATE(_newNodeT<LabelNode>(&node, labelId));
419 0 : _labelNodes[index] = node;
420 : }
421 :
422 0 : *out = node;
423 0 : return kErrorOk;
424 : }
425 :
426 54984 : Error BaseBuilder::registerLabelNode(LabelNode* node) {
427 54984 : if (ASMJIT_UNLIKELY(!_code))
428 : return DebugUtils::errored(kErrorNotInitialized);
429 :
430 : LabelEntry* le;
431 54984 : ASMJIT_PROPAGATE(_code->newLabelEntry(&le));
432 54984 : uint32_t labelId = le->id();
433 :
434 : // We just added one label so it must be true.
435 : ASMJIT_ASSERT(_labelNodes.size() < labelId + 1);
436 54984 : ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, labelId + 1));
437 :
438 54984 : _labelNodes[labelId] = node;
439 54984 : node->_labelId = labelId;
440 :
441 54984 : return kErrorOk;
442 : }
443 :
444 0 : static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) {
445 : ASMJIT_ASSERT(self->_labelNodes.size() < labelId + 1);
446 :
447 0 : uint32_t growBy = labelId - self->_labelNodes.size();
448 0 : Error err = self->_labelNodes.willGrow(&self->_allocator, growBy);
449 :
450 0 : if (ASMJIT_UNLIKELY(err))
451 0 : return self->reportError(err);
452 :
453 : LabelNode* node;
454 0 : ASMJIT_PROPAGATE(self->_newNodeT<LabelNode>(&node, labelId));
455 :
456 0 : self->_labelNodes.resize(&self->_allocator, labelId + 1);
457 0 : self->_labelNodes[labelId] = node;
458 0 : node->_labelId = labelId;
459 0 : return kErrorOk;
460 : }
461 :
462 0 : Label BaseBuilder::newLabel() {
463 : uint32_t labelId = Globals::kInvalidId;
464 : LabelEntry* le;
465 :
466 0 : if (_code &&
467 0 : _code->newLabelEntry(&le) == kErrorOk &&
468 0 : BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) {
469 0 : labelId = le->id();
470 : }
471 :
472 0 : return Label(labelId);
473 : }
474 :
475 0 : Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
476 : uint32_t labelId = Globals::kInvalidId;
477 : LabelEntry* le;
478 :
479 0 : if (_code &&
480 0 : _code->newNamedLabelEntry(&le, name, nameSize, type, parentId) == kErrorOk &&
481 0 : BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) {
482 0 : labelId = le->id();
483 : }
484 :
485 0 : return Label(labelId);
486 : }
487 :
488 0 : Error BaseBuilder::bind(const Label& label) {
489 : LabelNode* node;
490 0 : ASMJIT_PROPAGATE(labelNodeOf(&node, label));
491 :
492 0 : addNode(node);
493 0 : return kErrorOk;
494 : }
495 :
496 : // BaseBuilder - Passes
497 : // ====================
498 :
499 0 : ASMJIT_FAVOR_SIZE Pass* BaseBuilder::passByName(const char* name) const noexcept {
500 0 : for (Pass* pass : _passes)
501 0 : if (strcmp(pass->name(), name) == 0)
502 0 : return pass;
503 : return nullptr;
504 : }
505 :
506 54984 : ASMJIT_FAVOR_SIZE Error BaseBuilder::addPass(Pass* pass) noexcept {
507 54984 : if (ASMJIT_UNLIKELY(!_code))
508 : return DebugUtils::errored(kErrorNotInitialized);
509 :
510 54984 : if (ASMJIT_UNLIKELY(pass == nullptr)) {
511 : // Since this is directly called by `addPassT()` we treat `null` argument
512 : // as out-of-memory condition. Otherwise it would be API misuse.
513 : return DebugUtils::errored(kErrorOutOfMemory);
514 : }
515 54984 : else if (ASMJIT_UNLIKELY(pass->_cb)) {
516 : // Kinda weird, but okay...
517 0 : if (pass->_cb == this)
518 : return kErrorOk;
519 : return DebugUtils::errored(kErrorInvalidState);
520 : }
521 :
522 109968 : ASMJIT_PROPAGATE(_passes.append(&_allocator, pass));
523 54984 : pass->_cb = this;
524 54984 : return kErrorOk;
525 : }
526 :
527 0 : ASMJIT_FAVOR_SIZE Error BaseBuilder::deletePass(Pass* pass) noexcept {
528 0 : if (ASMJIT_UNLIKELY(!_code))
529 : return DebugUtils::errored(kErrorNotInitialized);
530 :
531 0 : if (ASMJIT_UNLIKELY(pass == nullptr))
532 : return DebugUtils::errored(kErrorInvalidArgument);
533 :
534 0 : if (pass->_cb != nullptr) {
535 0 : if (pass->_cb != this)
536 : return DebugUtils::errored(kErrorInvalidState);
537 :
538 : uint32_t index = _passes.indexOf(pass);
539 : ASMJIT_ASSERT(index != Globals::kNotFound);
540 :
541 0 : pass->_cb = nullptr;
542 0 : _passes.removeAt(index);
543 : }
544 :
545 0 : pass->~Pass();
546 0 : return kErrorOk;
547 : }
548 :
549 27492 : Error BaseBuilder::runPasses() {
550 27492 : if (ASMJIT_UNLIKELY(!_code))
551 : return DebugUtils::errored(kErrorNotInitialized);
552 :
553 27492 : if (_passes.empty())
554 : return kErrorOk;
555 :
556 : ErrorHandler* prev = errorHandler();
557 27492 : PostponedErrorHandler postponed;
558 :
559 : Error err = kErrorOk;
560 27492 : setErrorHandler(&postponed);
561 :
562 82476 : for (Pass* pass : _passes) {
563 54984 : _passZone.reset();
564 54984 : err = pass->run(&_passZone, _logger);
565 54984 : if (err)
566 : break;
567 : }
568 27492 : _passZone.reset();
569 27492 : setErrorHandler(prev);
570 :
571 27492 : if (ASMJIT_UNLIKELY(err))
572 0 : return reportError(err, !postponed._message.empty() ? postponed._message.data() : nullptr);
573 :
574 : return kErrorOk;
575 27492 : }
576 :
577 : // BaseBuilder - Emit
578 : // ==================
579 :
580 382370 : Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
581 : uint32_t opCount = EmitterUtils::opCountFromEmitArgs(o0, o1, o2, opExt);
582 : InstOptions options = instOptions() | forcedInstOptions();
583 :
584 382370 : if (Support::test(options, InstOptions::kReserved)) {
585 0 : if (ASMJIT_UNLIKELY(!_code))
586 : return DebugUtils::errored(kErrorNotInitialized);
587 :
588 : #ifndef ASMJIT_NO_VALIDATION
589 : // Strict validation.
590 0 : if (hasDiagnosticOption(DiagnosticOptions::kValidateIntermediate)) {
591 : Operand_ opArray[Globals::kMaxOpCount];
592 : EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
593 :
594 0 : ValidationFlags validationFlags = isCompiler() ? ValidationFlags::kEnableVirtRegs : ValidationFlags::kNone;
595 0 : Error err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount, validationFlags);
596 :
597 0 : if (ASMJIT_UNLIKELY(err)) {
598 : resetInstOptions();
599 : resetExtraReg();
600 : resetInlineComment();
601 0 : return reportError(err);
602 : }
603 : }
604 : #endif
605 :
606 : // Clear instruction options that should never be part of a regular instruction.
607 : options &= ~InstOptions::kReserved;
608 : }
609 :
610 : uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
611 : ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
612 :
613 382370 : InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
614 : const char* comment = inlineComment();
615 :
616 : resetInstOptions();
617 : resetInlineComment();
618 :
619 382370 : if (ASMJIT_UNLIKELY(!node)) {
620 : resetExtraReg();
621 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
622 : }
623 :
624 : node = new(node) InstNode(this, instId, options, opCount, opCapacity);
625 : node->setExtraReg(extraReg());
626 : node->setOp(0, o0);
627 : node->setOp(1, o1);
628 : node->setOp(2, o2);
629 384503 : for (uint32_t i = 3; i < opCount; i++)
630 2133 : node->setOp(i, opExt[i - 3]);
631 : node->resetOpRange(opCount, opCapacity);
632 :
633 382370 : if (comment)
634 0 : node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true)));
635 :
636 382370 : addNode(node);
637 : resetExtraReg();
638 382370 : return kErrorOk;
639 : }
640 :
641 : // BaseBuilder - Align
642 : // ===================
643 :
644 0 : Error BaseBuilder::align(AlignMode alignMode, uint32_t alignment) {
645 0 : if (ASMJIT_UNLIKELY(!_code))
646 : return DebugUtils::errored(kErrorNotInitialized);
647 :
648 : AlignNode* node;
649 0 : ASMJIT_PROPAGATE(newAlignNode(&node, alignMode, alignment));
650 0 : ASMJIT_ASSUME(node != nullptr);
651 :
652 0 : addNode(node);
653 0 : return kErrorOk;
654 : }
655 :
656 : // BaseBuilder - Embed
657 : // ===================
658 :
659 0 : Error BaseBuilder::embed(const void* data, size_t dataSize) {
660 0 : if (ASMJIT_UNLIKELY(!_code))
661 : return DebugUtils::errored(kErrorNotInitialized);
662 :
663 : EmbedDataNode* node;
664 0 : ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, data, dataSize));
665 0 : ASMJIT_ASSUME(node != nullptr);
666 :
667 0 : addNode(node);
668 0 : return kErrorOk;
669 : }
670 :
671 0 : Error BaseBuilder::embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t itemRepeat) {
672 0 : if (ASMJIT_UNLIKELY(!_code))
673 : return DebugUtils::errored(kErrorNotInitialized);
674 :
675 : EmbedDataNode* node;
676 0 : ASMJIT_PROPAGATE(newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat));
677 0 : ASMJIT_ASSUME(node != nullptr);
678 :
679 0 : addNode(node);
680 0 : return kErrorOk;
681 : }
682 :
683 0 : Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
684 0 : if (ASMJIT_UNLIKELY(!_code))
685 : return DebugUtils::errored(kErrorNotInitialized);
686 :
687 0 : if (!isLabelValid(label))
688 0 : return reportError(DebugUtils::errored(kErrorInvalidLabel));
689 :
690 0 : ASMJIT_PROPAGATE(align(AlignMode::kData, uint32_t(pool.alignment())));
691 0 : ASMJIT_PROPAGATE(bind(label));
692 :
693 : EmbedDataNode* node;
694 0 : ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, nullptr, pool.size()));
695 0 : ASMJIT_ASSUME(node != nullptr);
696 :
697 0 : pool.fill(node->data());
698 0 : addNode(node);
699 0 : return kErrorOk;
700 : }
701 :
702 : // BaseBuilder - EmbedLabel & EmbedLabelDelta
703 : // ==========================================
704 : //
705 : // If dataSize is zero it means that the size is the same as target register width, however,
706 : // if it's provided we really want to validate whether it's within the possible range.
707 :
708 : static inline bool BaseBuilder_checkDataSize(size_t dataSize) noexcept {
709 0 : return !dataSize || (Support::isPowerOf2(dataSize) && dataSize <= 8);
710 : }
711 :
712 0 : Error BaseBuilder::embedLabel(const Label& label, size_t dataSize) {
713 0 : if (ASMJIT_UNLIKELY(!_code))
714 : return DebugUtils::errored(kErrorNotInitialized);
715 :
716 : if (!BaseBuilder_checkDataSize(dataSize))
717 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
718 :
719 : EmbedLabelNode* node;
720 0 : ASMJIT_PROPAGATE(_newNodeT<EmbedLabelNode>(&node, label.id(), uint32_t(dataSize)));
721 :
722 0 : addNode(node);
723 0 : return kErrorOk;
724 : }
725 :
726 0 : Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) {
727 0 : if (ASMJIT_UNLIKELY(!_code))
728 : return DebugUtils::errored(kErrorNotInitialized);
729 :
730 : if (!BaseBuilder_checkDataSize(dataSize))
731 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
732 :
733 : EmbedLabelDeltaNode* node;
734 0 : ASMJIT_PROPAGATE(_newNodeT<EmbedLabelDeltaNode>(&node, label.id(), base.id(), uint32_t(dataSize)));
735 :
736 0 : addNode(node);
737 0 : return kErrorOk;
738 : }
739 :
740 : // BaseBuilder - Comment
741 : // =====================
742 :
743 0 : Error BaseBuilder::comment(const char* data, size_t size) {
744 0 : if (ASMJIT_UNLIKELY(!_code))
745 : return DebugUtils::errored(kErrorNotInitialized);
746 :
747 : CommentNode* node;
748 0 : ASMJIT_PROPAGATE(newCommentNode(&node, data, size));
749 0 : ASMJIT_ASSUME(node != nullptr);
750 :
751 0 : addNode(node);
752 0 : return kErrorOk;
753 : }
754 :
755 : // BaseBuilder - SerializeTo
756 : // =========================
757 :
758 27492 : Error BaseBuilder::serializeTo(BaseEmitter* dst) {
759 : Error err = kErrorOk;
760 27492 : BaseNode* node_ = _firstNode;
761 :
762 : Operand_ opArray[Globals::kMaxOpCount];
763 :
764 : do {
765 : dst->setInlineComment(node_->inlineComment());
766 :
767 501977 : if (node_->isInst()) {
768 : InstNode* node = node_->as<InstNode>();
769 :
770 : // NOTE: Inlined to remove one additional call per instruction.
771 : dst->setInstOptions(node->options());
772 : dst->setExtraReg(node->extraReg());
773 :
774 : const Operand_* op = node->operands();
775 : const Operand_* opExt = EmitterUtils::noExt;
776 :
777 : uint32_t opCount = node->opCount();
778 392009 : if (opCount > 3) {
779 : uint32_t i = 4;
780 2133 : opArray[3] = op[3];
781 :
782 2133 : while (i < opCount) {
783 0 : opArray[i].copyFrom(op[i]);
784 0 : i++;
785 : }
786 6399 : while (i < Globals::kMaxOpCount) {
787 4266 : opArray[i].reset();
788 4266 : i++;
789 : }
790 : opExt = opArray + 3;
791 : }
792 :
793 392009 : err = dst->_emit(node->id(), op[0], op[1], op[2], opExt);
794 : }
795 109968 : else if (node_->isLabel()) {
796 54984 : if (node_->isConstPool()) {
797 : ConstPoolNode* node = node_->as<ConstPoolNode>();
798 0 : err = dst->embedConstPool(node->label(), node->constPool());
799 : }
800 : else {
801 : LabelNode* node = node_->as<LabelNode>();
802 54984 : err = dst->bind(node->label());
803 : }
804 : }
805 : else if (node_->isAlign()) {
806 : AlignNode* node = node_->as<AlignNode>();
807 0 : err = dst->align(node->alignMode(), node->alignment());
808 : }
809 : else if (node_->isEmbedData()) {
810 : EmbedDataNode* node = node_->as<EmbedDataNode>();
811 0 : err = dst->embedDataArray(node->typeId(), node->data(), node->itemCount(), node->repeatCount());
812 : }
813 : else if (node_->isEmbedLabel()) {
814 : EmbedLabelNode* node = node_->as<EmbedLabelNode>();
815 0 : err = dst->embedLabel(node->label(), node->dataSize());
816 : }
817 : else if (node_->isEmbedLabelDelta()) {
818 : EmbedLabelDeltaNode* node = node_->as<EmbedLabelDeltaNode>();
819 0 : err = dst->embedLabelDelta(node->label(), node->baseLabel(), node->dataSize());
820 : }
821 : else if (node_->isSection()) {
822 : SectionNode* node = node_->as<SectionNode>();
823 27492 : err = dst->section(_code->sectionById(node->id()));
824 : }
825 : else if (node_->isComment()) {
826 : CommentNode* node = node_->as<CommentNode>();
827 0 : err = dst->comment(node->inlineComment());
828 : }
829 :
830 501977 : if (err) break;
831 : node_ = node_->next();
832 501977 : } while (node_);
833 :
834 27492 : return err;
835 : }
836 :
837 : // BaseBuilder - Events
838 : // ====================
839 :
840 27492 : Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
841 27492 : ASMJIT_PROPAGATE(Base::onAttach(code));
842 :
843 : SectionNode* initialSection;
844 27492 : Error err = sectionNodeOf(&initialSection, 0);
845 :
846 27492 : if (!err)
847 27492 : err = _passes.willGrow(&_allocator, 8);
848 :
849 27492 : if (ASMJIT_UNLIKELY(err)) {
850 0 : onDetach(code);
851 0 : return err;
852 : }
853 :
854 27492 : ASMJIT_ASSUME(initialSection != nullptr);
855 27492 : _cursor = initialSection;
856 27492 : _firstNode = initialSection;
857 27492 : _lastNode = initialSection;
858 : initialSection->setFlags(NodeFlags::kIsActive);
859 :
860 27492 : return kErrorOk;
861 : }
862 :
863 0 : Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
864 0 : BaseBuilder_deletePasses(this);
865 : _sectionNodes.reset();
866 : _labelNodes.reset();
867 :
868 0 : _allocator.reset(&_codeZone);
869 0 : _codeZone.reset();
870 0 : _dataZone.reset();
871 0 : _passZone.reset();
872 :
873 0 : _nodeFlags = NodeFlags::kNone;
874 0 : _cursor = nullptr;
875 0 : _firstNode = nullptr;
876 0 : _lastNode = nullptr;
877 :
878 0 : return Base::onDetach(code);
879 : }
880 :
881 : // Pass - Construction & Destruction
882 : // =================================
883 :
884 54984 : Pass::Pass(const char* name) noexcept
885 54984 : : _name(name) {}
886 54984 : Pass::~Pass() noexcept {}
887 :
888 : ASMJIT_END_NAMESPACE
889 :
890 : #endif // !ASMJIT_NO_BUILDER
891 :
892 : #endif // __PLUMED_HAS_ASMJIT
|