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_COMPILER)
35 :
36 : // [Dependencies]
37 : #include "./assembler.h"
38 : #include "./codecompiler.h"
39 : #include "./cpuinfo.h"
40 : #include "./logging.h"
41 : #include "./regalloc_p.h"
42 : #include "./utils.h"
43 : #include <stdarg.h>
44 :
45 : // [Api-Begin]
46 : #include "./asmjit_apibegin.h"
47 :
48 : namespace PLMD {
49 : namespace asmjit {
50 :
51 : // ============================================================================
52 : // [Constants]
53 : // ============================================================================
54 :
55 : static const char noName[1] = { '\0' };
56 :
57 : // ============================================================================
58 : // [asmjit::CCFuncCall - Arg / Ret]
59 : // ============================================================================
60 :
61 1850 : bool CCFuncCall::_setArg(uint32_t i, const Operand_& op) noexcept {
62 1850 : if ((i & ~kFuncArgHi) >= _funcDetail.getArgCount())
63 : return false;
64 :
65 1850 : _args[i] = op;
66 1850 : return true;
67 : }
68 :
69 1636 : bool CCFuncCall::_setRet(uint32_t i, const Operand_& op) noexcept {
70 1636 : if (i >= 2)
71 : return false;
72 :
73 1636 : _ret[i] = op;
74 1636 : return true;
75 : }
76 :
77 : // ============================================================================
78 : // [asmjit::CodeCompiler - Construction / Destruction]
79 : // ============================================================================
80 :
81 1944 : CodeCompiler::CodeCompiler() noexcept
82 : : CodeBuilder(),
83 1944 : _func(nullptr),
84 1944 : _vRegZone(4096 - Zone::kZoneOverhead),
85 : _vRegArray(),
86 1944 : _localConstPool(nullptr),
87 1944 : _globalConstPool(nullptr) {
88 :
89 1944 : _type = kTypeCompiler;
90 1944 : }
91 1944 : CodeCompiler::~CodeCompiler() noexcept {}
92 :
93 : // ============================================================================
94 : // [asmjit::CodeCompiler - Events]
95 : // ============================================================================
96 :
97 1944 : Error CodeCompiler::onAttach(CodeHolder* code) noexcept {
98 1944 : return Base::onAttach(code);
99 : }
100 :
101 0 : Error CodeCompiler::onDetach(CodeHolder* code) noexcept {
102 0 : _func = nullptr;
103 :
104 0 : _localConstPool = nullptr;
105 0 : _globalConstPool = nullptr;
106 :
107 : _vRegArray.reset();
108 0 : _vRegZone.reset(false);
109 :
110 0 : return Base::onDetach(code);
111 : }
112 :
113 : // ============================================================================
114 : // [asmjit::CodeCompiler - Node-Factory]
115 : // ============================================================================
116 :
117 0 : CCHint* CodeCompiler::newHintNode(Reg& r, uint32_t hint, uint32_t value) noexcept {
118 0 : if (!r.isVirtReg()) return nullptr;
119 :
120 : VirtReg* vr = getVirtReg(r);
121 0 : return newNodeT<CCHint>(vr, hint, value);
122 : }
123 :
124 : // ============================================================================
125 : // [asmjit::CodeCompiler - Func]
126 : // ============================================================================
127 :
128 1944 : CCFunc* CodeCompiler::newFunc(const FuncSignature& sign) noexcept {
129 : Error err;
130 :
131 : CCFunc* func = newNodeT<CCFunc>();
132 1944 : if (!func) goto _NoMemory;
133 :
134 1944 : err = registerLabelNode(func);
135 1944 : if (ASMJIT_UNLIKELY(err)) {
136 : // TODO: Calls setLastError, maybe rethink noexcept?
137 0 : setLastError(err);
138 0 : return nullptr;
139 : }
140 :
141 : // Create helper nodes.
142 1944 : func->_exitNode = newLabelNode();
143 1944 : func->_end = newNodeT<CBSentinel>();
144 :
145 1944 : if (!func->_exitNode || !func->_end)
146 0 : goto _NoMemory;
147 :
148 : // Function prototype.
149 1944 : err = func->getDetail().init(sign);
150 1944 : if (err != kErrorOk) {
151 0 : setLastError(err);
152 0 : return nullptr;
153 : }
154 :
155 : // If the CodeInfo guarantees higher alignment honor it.
156 1944 : if (_codeInfo.getStackAlignment() > func->_funcDetail._callConv.getNaturalStackAlignment())
157 : func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.getStackAlignment());
158 :
159 : // Allocate space for function arguments.
160 1944 : func->_args = nullptr;
161 1944 : if (func->getArgCount() != 0) {
162 0 : func->_args = _cbHeap.allocT<VirtReg*>(func->getArgCount() * sizeof(VirtReg*));
163 0 : if (!func->_args) goto _NoMemory;
164 :
165 0 : ::memset(func->_args, 0, func->getArgCount() * sizeof(VirtReg*));
166 : }
167 :
168 : return func;
169 :
170 0 : _NoMemory:
171 0 : setLastError(DebugUtils::errored(kErrorNoHeapMemory));
172 0 : return nullptr;
173 : }
174 :
175 1944 : CCFunc* CodeCompiler::addFunc(CCFunc* func) {
176 : ASMJIT_ASSERT(_func == nullptr);
177 1944 : _func = func;
178 :
179 1944 : addNode(func); // Function node.
180 : CBNode* cursor = getCursor(); // {CURSOR}.
181 1944 : addNode(func->getExitNode()); // Function exit label.
182 1944 : addNode(func->getEnd()); // Function end marker.
183 :
184 : _setCursor(cursor);
185 1944 : return func;
186 : }
187 :
188 1944 : CCFunc* CodeCompiler::addFunc(const FuncSignature& sign) {
189 1944 : CCFunc* func = newFunc(sign);
190 :
191 1944 : if (!func) {
192 0 : setLastError(DebugUtils::errored(kErrorNoHeapMemory));
193 0 : return nullptr;
194 : }
195 :
196 1944 : return addFunc(func);
197 : }
198 :
199 1944 : CBSentinel* CodeCompiler::endFunc() {
200 : CCFunc* func = getFunc();
201 1944 : if (!func) {
202 : // TODO:
203 : return nullptr;
204 : }
205 :
206 : // Add the local constant pool at the end of the function (if exists).
207 1944 : if (_localConstPool) {
208 0 : setCursor(func->getEnd()->getPrev());
209 0 : addNode(_localConstPool);
210 0 : _localConstPool = nullptr;
211 : }
212 :
213 : // Mark as finished.
214 1944 : func->_isFinished = true;
215 1944 : _func = nullptr;
216 :
217 : CBSentinel* end = func->getEnd();
218 1944 : setCursor(end);
219 1944 : return end;
220 : }
221 :
222 : // ============================================================================
223 : // [asmjit::CodeCompiler - Ret]
224 : // ============================================================================
225 :
226 1944 : CCFuncRet* CodeCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept {
227 1944 : CCFuncRet* node = newNodeT<CCFuncRet>(o0, o1);
228 1944 : if (!node) {
229 0 : setLastError(DebugUtils::errored(kErrorNoHeapMemory));
230 0 : return nullptr;
231 : }
232 : return node;
233 : }
234 :
235 1944 : CCFuncRet* CodeCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept {
236 1944 : CCFuncRet* node = newRet(o0, o1);
237 1944 : if (!node) return nullptr;
238 1944 : return static_cast<CCFuncRet*>(addNode(node));
239 : }
240 :
241 : // ============================================================================
242 : // [asmjit::CodeCompiler - Call]
243 : // ============================================================================
244 :
245 1636 : CCFuncCall* CodeCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
246 : Error err;
247 : uint32_t nArgs;
248 :
249 1636 : CCFuncCall* node = _cbHeap.allocT<CCFuncCall>(sizeof(CCFuncCall) + sizeof(Operand));
250 1636 : Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CCFuncCall));
251 :
252 1636 : if (ASMJIT_UNLIKELY(!node))
253 0 : goto _NoMemory;
254 :
255 1636 : opArray[0].copyFrom(o0);
256 : new (node) CCFuncCall(this, instId, 0, opArray, 1);
257 :
258 1636 : if ((err = node->getDetail().init(sign)) != kErrorOk) {
259 0 : setLastError(err);
260 0 : return nullptr;
261 : }
262 :
263 : // If there are no arguments skip the allocation.
264 1636 : if ((nArgs = sign.getArgCount()) == 0)
265 : return node;
266 :
267 1636 : node->_args = static_cast<Operand*>(_cbHeap.alloc(nArgs * sizeof(Operand)));
268 1636 : if (!node->_args) goto _NoMemory;
269 :
270 : ::memset(node->_args, 0, nArgs * sizeof(Operand));
271 1636 : return node;
272 :
273 0 : _NoMemory:
274 0 : setLastError(DebugUtils::errored(kErrorNoHeapMemory));
275 0 : return nullptr;
276 : }
277 :
278 1636 : CCFuncCall* CodeCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
279 1636 : CCFuncCall* node = newCall(instId, o0, sign);
280 1636 : if (!node) return nullptr;
281 1636 : return static_cast<CCFuncCall*>(addNode(node));
282 : }
283 :
284 : // ============================================================================
285 : // [asmjit::CodeCompiler - Vars]
286 : // ============================================================================
287 :
288 0 : Error CodeCompiler::setArg(uint32_t argIndex, const Reg& r) {
289 : CCFunc* func = getFunc();
290 :
291 0 : if (!func)
292 0 : return setLastError(DebugUtils::errored(kErrorInvalidState));
293 :
294 0 : if (!isVirtRegValid(r))
295 0 : return setLastError(DebugUtils::errored(kErrorInvalidVirtId));
296 :
297 : VirtReg* vr = getVirtReg(r);
298 : func->setArg(argIndex, vr);
299 :
300 0 : return kErrorOk;
301 : }
302 :
303 : // ============================================================================
304 : // [asmjit::CodeCompiler - Hint]
305 : // ============================================================================
306 :
307 0 : Error CodeCompiler::_hint(Reg& r, uint32_t hint, uint32_t value) {
308 0 : if (!r.isVirtReg()) return kErrorOk;
309 :
310 0 : CCHint* node = newHintNode(r, hint, value);
311 0 : if (!node) return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
312 :
313 0 : addNode(node);
314 0 : return kErrorOk;
315 : }
316 :
317 : // ============================================================================
318 : // [asmjit::CodeCompiler - Vars]
319 : // ============================================================================
320 :
321 23740 : VirtReg* CodeCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept {
322 : size_t index = _vRegArray.getLength();
323 23740 : if (ASMJIT_UNLIKELY(index > Operand::kPackedIdCount))
324 : return nullptr;
325 :
326 : VirtReg* vreg;
327 28978 : if (_vRegArray.willGrow(&_cbHeap, 1) != kErrorOk || !(vreg = _vRegZone.allocZeroedT<VirtReg>()))
328 0 : return nullptr;
329 :
330 23740 : vreg->_id = Operand::packId(static_cast<uint32_t>(index));
331 23740 : vreg->_regInfo._signature = signature;
332 23740 : vreg->_name = noName;
333 :
334 : #if !defined(ASMJIT_DISABLE_LOGGING)
335 23740 : if (name && name[0] != '\0')
336 0 : vreg->_name = static_cast<char*>(_cbDataZone.dup(name, ::strlen(name), true));
337 : #endif // !ASMJIT_DISABLE_LOGGING
338 :
339 23740 : vreg->_size = TypeId::sizeOf(typeId);
340 23740 : vreg->_typeId = typeId;
341 23740 : vreg->_alignment = static_cast<uint8_t>(std::min<uint32_t>(vreg->_size, 64));
342 23740 : vreg->_priority = 10;
343 :
344 : // The following are only used by `RAPass`.
345 23740 : vreg->_raId = kInvalidValue;
346 23740 : vreg->_state = VirtReg::kStateNone;
347 23740 : vreg->_physId = Globals::kInvalidRegId;
348 :
349 : _vRegArray.appendUnsafe(vreg);
350 23740 : return vreg;
351 : }
352 :
353 23740 : Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* name) {
354 : RegInfo regInfo;
355 :
356 23740 : Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
357 23740 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
358 :
359 23740 : VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
360 23740 : if (ASMJIT_UNLIKELY(!vReg)) {
361 : out.reset();
362 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
363 : }
364 :
365 : out._initReg(regInfo.getSignature(), vReg->getId());
366 23740 : return kErrorOk;
367 : }
368 :
369 0 : Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap) {
370 : StringBuilderTmp<256> sb;
371 : sb.appendFormatVA(nameFmt, ap);
372 0 : return _newReg(out, typeId, sb.getData());
373 : }
374 :
375 0 : Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* name) {
376 : RegInfo regInfo;
377 : uint32_t typeId;
378 :
379 0 : if (isVirtRegValid(ref)) {
380 : VirtReg* vRef = getVirtReg(ref);
381 0 : typeId = vRef->getTypeId();
382 :
383 : // NOTE: It's possible to cast one register type to another if it's the
384 : // same register kind. However, VirtReg always contains the TypeId that
385 : // was used to create the register. This means that in some cases we may
386 : // end up having different size of `ref` and `vRef`. In such case we
387 : // adjust the TypeId to match the `ref` register type instead of the
388 : // original register type, which should be the expected behavior.
389 : uint32_t typeSize = TypeId::sizeOf(typeId);
390 : uint32_t refSize = ref.getSize();
391 :
392 0 : if (typeSize != refSize) {
393 0 : if (TypeId::isInt(typeId)) {
394 : // GP register - change TypeId to match `ref`, but keep sign of `vRef`.
395 0 : switch (refSize) {
396 0 : case 1: typeId = TypeId::kI8 | (typeId & 1); break;
397 0 : case 2: typeId = TypeId::kI16 | (typeId & 1); break;
398 0 : case 4: typeId = TypeId::kI32 | (typeId & 1); break;
399 0 : case 8: typeId = TypeId::kI64 | (typeId & 1); break;
400 0 : default: typeId = TypeId::kVoid; break;
401 : }
402 : }
403 0 : else if (TypeId::isMmx(typeId)) {
404 : // MMX register - always use 64-bit.
405 0 : typeId = TypeId::kMmx64;
406 : }
407 0 : else if (TypeId::isMask(typeId)) {
408 : // Mask register - change TypeId to match `ref` size.
409 0 : switch (refSize) {
410 0 : case 1: typeId = TypeId::kMask8; break;
411 0 : case 2: typeId = TypeId::kMask16; break;
412 0 : case 4: typeId = TypeId::kMask32; break;
413 0 : case 8: typeId = TypeId::kMask64; break;
414 0 : default: typeId = TypeId::kVoid; break;
415 : }
416 : }
417 : else {
418 : // VEC register - change TypeId to match `ref` size, keep vector metadata.
419 : uint32_t elementTypeId = TypeId::elementOf(typeId);
420 :
421 0 : switch (refSize) {
422 0 : case 16: typeId = TypeId::_kVec128Start + (elementTypeId - TypeId::kI8); break;
423 0 : case 32: typeId = TypeId::_kVec256Start + (elementTypeId - TypeId::kI8); break;
424 0 : case 64: typeId = TypeId::_kVec512Start + (elementTypeId - TypeId::kI8); break;
425 0 : default: typeId = TypeId::kVoid; break;
426 : }
427 : }
428 :
429 0 : if (typeId == TypeId::kVoid)
430 0 : return setLastError(DebugUtils::errored(kErrorInvalidState));
431 : }
432 : }
433 : else {
434 0 : typeId = ref.getType();
435 : }
436 :
437 0 : Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
438 0 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
439 :
440 0 : VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
441 0 : if (ASMJIT_UNLIKELY(!vReg)) {
442 : out.reset();
443 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
444 : }
445 :
446 : out._initReg(regInfo.getSignature(), vReg->getId());
447 0 : return kErrorOk;
448 : }
449 :
450 0 : Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap) {
451 : StringBuilderTmp<256> sb;
452 : sb.appendFormatVA(nameFmt, ap);
453 0 : return _newReg(out, ref, sb.getData());
454 : }
455 :
456 0 : Error CodeCompiler::_newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name) {
457 0 : if (size == 0)
458 0 : return setLastError(DebugUtils::errored(kErrorInvalidArgument));
459 :
460 : if (alignment == 0) alignment = 1;
461 : if (!Utils::isPowerOf2(alignment))
462 0 : return setLastError(DebugUtils::errored(kErrorInvalidArgument));
463 :
464 : if (alignment > 64) alignment = 64;
465 :
466 0 : VirtReg* vReg = newVirtReg(0, 0, name);
467 0 : if (ASMJIT_UNLIKELY(!vReg)) {
468 : out.reset();
469 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
470 : }
471 :
472 0 : vReg->_size = size;
473 0 : vReg->_isStack = true;
474 0 : vReg->_alignment = static_cast<uint8_t>(alignment);
475 :
476 : // Set the memory operand to GPD/GPQ and its id to VirtReg.
477 0 : out = Mem(Init, _nativeGpReg.getType(), vReg->getId(), Reg::kRegNone, kInvalidValue, 0, 0, Mem::kSignatureMemRegHomeFlag);
478 0 : return kErrorOk;
479 : }
480 :
481 0 : Error CodeCompiler::_newConst(Mem& out, uint32_t scope, const void* data, size_t size) {
482 : CBConstPool** pPool;
483 0 : if (scope == kConstScopeLocal)
484 0 : pPool = &_localConstPool;
485 0 : else if (scope == kConstScopeGlobal)
486 0 : pPool = &_globalConstPool;
487 : else
488 0 : return setLastError(DebugUtils::errored(kErrorInvalidArgument));
489 :
490 0 : if (!*pPool && !(*pPool = newConstPool()))
491 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
492 :
493 0 : CBConstPool* pool = *pPool;
494 : size_t off;
495 :
496 : Error err = pool->add(data, size, off);
497 0 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
498 :
499 0 : out = Mem(Init,
500 : Label::kLabelTag, // Base type.
501 : pool->getId(), // Base id.
502 : 0, // Index type.
503 : kInvalidValue, // Index id.
504 : static_cast<int32_t>(off), // Offset.
505 : static_cast<uint32_t>(size), // Size.
506 : 0); // Flags.
507 0 : return kErrorOk;
508 : }
509 :
510 0 : Error CodeCompiler::alloc(Reg& reg) {
511 0 : if (!reg.isVirtReg()) return kErrorOk;
512 0 : return _hint(reg, CCHint::kHintAlloc, kInvalidValue);
513 : }
514 :
515 0 : Error CodeCompiler::alloc(Reg& reg, uint32_t physId) {
516 0 : if (!reg.isVirtReg()) return kErrorOk;
517 0 : return _hint(reg, CCHint::kHintAlloc, physId);
518 : }
519 :
520 0 : Error CodeCompiler::alloc(Reg& reg, const Reg& physReg) {
521 0 : if (!reg.isVirtReg()) return kErrorOk;
522 0 : return _hint(reg, CCHint::kHintAlloc, physReg.getId());
523 : }
524 :
525 0 : Error CodeCompiler::save(Reg& reg) {
526 0 : if (!reg.isVirtReg()) return kErrorOk;
527 0 : return _hint(reg, CCHint::kHintSave, kInvalidValue);
528 : }
529 :
530 0 : Error CodeCompiler::spill(Reg& reg) {
531 0 : if (!reg.isVirtReg()) return kErrorOk;
532 0 : return _hint(reg, CCHint::kHintSpill, kInvalidValue);
533 : }
534 :
535 0 : Error CodeCompiler::unuse(Reg& reg) {
536 0 : if (!reg.isVirtReg()) return kErrorOk;
537 0 : return _hint(reg, CCHint::kHintUnuse, kInvalidValue);
538 : }
539 :
540 0 : uint32_t CodeCompiler::getPriority(Reg& reg) const {
541 0 : if (!reg.isVirtReg()) return 0;
542 0 : return getVirtRegById(reg.getId())->getPriority();
543 : }
544 :
545 0 : void CodeCompiler::setPriority(Reg& reg, uint32_t priority) {
546 0 : if (!reg.isVirtReg()) return;
547 : if (priority > 255) priority = 255;
548 :
549 : VirtReg* vreg = getVirtRegById(reg.getId());
550 0 : if (vreg) vreg->_priority = static_cast<uint8_t>(priority);
551 : }
552 :
553 0 : bool CodeCompiler::getSaveOnUnuse(Reg& reg) const {
554 0 : if (!reg.isVirtReg()) return false;
555 :
556 : VirtReg* vreg = getVirtRegById(reg.getId());
557 0 : return static_cast<bool>(vreg->_saveOnUnuse);
558 : }
559 :
560 0 : void CodeCompiler::setSaveOnUnuse(Reg& reg, bool value) {
561 0 : if (!reg.isVirtReg()) return;
562 :
563 : VirtReg* vreg = getVirtRegById(reg.getId());
564 0 : if (!vreg) return;
565 :
566 0 : vreg->_saveOnUnuse = value;
567 : }
568 :
569 0 : void CodeCompiler::rename(Reg& reg, const char* fmt, ...) {
570 0 : if (!reg.isVirtReg()) return;
571 :
572 : VirtReg* vreg = getVirtRegById(reg.getId());
573 0 : if (!vreg) return;
574 :
575 0 : vreg->_name = noName;
576 0 : if (fmt && fmt[0] != '\0') {
577 : char buf[64];
578 :
579 : va_list ap;
580 0 : va_start(ap, fmt);
581 :
582 : vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
583 0 : buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
584 :
585 0 : vreg->_name = static_cast<char*>(_cbDataZone.dup(buf, ::strlen(buf), true));
586 0 : va_end(ap);
587 : }
588 : }
589 :
590 : } // asmjit namespace
591 : } // namespace PLMD
592 :
593 : // [Api-End]
594 : #include "./asmjit_apiend.h"
595 :
596 : // [Guard]
597 : #endif // !ASMJIT_DISABLE_COMPILER
598 : #pragma GCC diagnostic pop
599 : #endif // __PLUMED_HAS_ASMJIT
|