LCOV - code coverage report
Current view: top level - asmjit - assembler.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 40 174 23.0 %
Date: 2024-10-18 14:00:27 Functions: 6 18 33.3 %

          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             : // [Dependencies]
      33             : #include "./assembler.h"
      34             : #include "./constpool.h"
      35             : #include "./utils.h"
      36             : #include "./vmem.h"
      37             : 
      38             : // [Api-Begin]
      39             : #include "./asmjit_apibegin.h"
      40             : 
      41             : namespace PLMD {
      42             : namespace asmjit {
      43             : 
      44             : // ============================================================================
      45             : // [asmjit::Assembler - Construction / Destruction]
      46             : // ============================================================================
      47             : 
      48       32111 : Assembler::Assembler() noexcept
      49             :   : CodeEmitter(kTypeAssembler),
      50       32111 :     _section(nullptr),
      51       32111 :     _bufferData(nullptr),
      52       32111 :     _bufferEnd(nullptr),
      53       32111 :     _bufferPtr(nullptr),
      54       32111 :     _op4(),
      55       32111 :     _op5() {}
      56             : 
      57       32111 : Assembler::~Assembler() noexcept {
      58       32111 :   if (_code) sync();
      59       32111 : }
      60             : 
      61             : // ============================================================================
      62             : // [asmjit::Assembler - Events]
      63             : // ============================================================================
      64             : 
      65       32111 : Error Assembler::onAttach(CodeHolder* code) noexcept {
      66             :   // Attach to the end of the .text section.
      67       32111 :   _section = code->_sections[0];
      68       32111 :   uint8_t* p = _section->_buffer._data;
      69             : 
      70       32111 :   _bufferData = p;
      71       32111 :   _bufferEnd  = p + _section->_buffer._capacity;
      72       32111 :   _bufferPtr  = p + _section->_buffer._length;
      73             : 
      74             :   _op4.reset();
      75             :   _op5.reset();
      76             : 
      77       32111 :   return Base::onAttach(code);
      78             : }
      79             : 
      80           0 : Error Assembler::onDetach(CodeHolder* code) noexcept {
      81           0 :   _section    = nullptr;
      82           0 :   _bufferData = nullptr;
      83           0 :   _bufferEnd  = nullptr;
      84           0 :   _bufferPtr  = nullptr;
      85             : 
      86             :   _op4.reset();
      87             :   _op5.reset();
      88             : 
      89           0 :   return Base::onDetach(code);
      90             : }
      91             : 
      92             : // ============================================================================
      93             : // [asmjit::Assembler - Code-Generation]
      94             : // ============================================================================
      95             : 
      96           0 : Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
      97           0 :   _op4 = o4;
      98           0 :   _op5 = o5;
      99           0 :   _options |= kOptionOp4Op5Used;
     100           0 :   return _emit(instId, o0, o1, o2, o3);
     101             : }
     102             : 
     103      593300 : Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
     104             :   const Operand_* op = opArray;
     105      593300 :   switch (opCount) {
     106       32111 :     case 0: return _emit(instId, _none, _none, _none, _none);
     107       27434 :     case 1: return _emit(instId, op[0], _none, _none, _none);
     108      531485 :     case 2: return _emit(instId, op[0], op[1], _none, _none);
     109        2270 :     case 3: return _emit(instId, op[0], op[1], op[2], _none);
     110           0 :     case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
     111             : 
     112           0 :     case 5:
     113           0 :       _op4 = op[4];
     114             :       _op5.reset();
     115           0 :       _options |= kOptionOp4Op5Used;
     116           0 :       return _emit(instId, op[0], op[1], op[2], op[3]);
     117             : 
     118           0 :     case 6:
     119           0 :       _op4 = op[4];
     120           0 :       _op5 = op[5];
     121           0 :       _options |= kOptionOp4Op5Used;
     122           0 :       return _emit(instId, op[0], op[1], op[2], op[3]);
     123             : 
     124             :     default:
     125             :       return DebugUtils::errored(kErrorInvalidArgument);
     126             :   }
     127             : }
     128             : 
     129             : // ============================================================================
     130             : // [asmjit::Assembler - Sync]
     131             : // ============================================================================
     132             : 
     133       64222 : void Assembler::sync() noexcept {
     134             :   ASMJIT_ASSERT(_code != nullptr);                       // Only called by CodeHolder, so we must be attached.
     135             :   ASMJIT_ASSERT(_section != nullptr);                    // One section must always be active, no matter what.
     136             :   ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`.
     137             : 
     138             :   // Update only if the current offset is greater than the section length.
     139       64222 :   size_t offset = (size_t)(_bufferPtr - _bufferData);
     140       64222 :   if (_section->getBuffer().getLength() < offset)
     141       32111 :     _section->_buffer._length = offset;
     142       64222 : }
     143             : 
     144             : // ============================================================================
     145             : // [asmjit::Assembler - Code-Buffer]
     146             : // ============================================================================
     147             : 
     148           0 : Error Assembler::setOffset(size_t offset) {
     149           0 :   if (_lastError) return _lastError;
     150             : 
     151           0 :   size_t length = std::max(_section->getBuffer().getLength(), getOffset());
     152           0 :   if (ASMJIT_UNLIKELY(offset > length))
     153           0 :     return setLastError(DebugUtils::errored(kErrorInvalidArgument));
     154             : 
     155             :   // If the `Assembler` generated any code the `_bufferPtr` may be higher than
     156             :   // the section length stored in `CodeHolder` as it doesn't update it each
     157             :   // time it generates machine code. This is the same as calling `sync()`.
     158           0 :   if (_section->_buffer._length < length)
     159           0 :     _section->_buffer._length = length;
     160             : 
     161           0 :   _bufferPtr = _bufferData + offset;
     162           0 :   return kErrorOk;
     163             : }
     164             : 
     165             : // ============================================================================
     166             : // [asmjit::Assembler - Comment]
     167             : // ============================================================================
     168             : 
     169           0 : Error Assembler::comment(const char* s, size_t len) {
     170           0 :   if (_lastError) return _lastError;
     171             : 
     172             : #if !defined(ASMJIT_DISABLE_LOGGING)
     173           0 :   if (_globalOptions & kOptionLoggingEnabled) {
     174           0 :     Logger* logger = _code->getLogger();
     175             :     logger->log(s, len);
     176             :     logger->log("\n", 1);
     177           0 :     return kErrorOk;
     178             :   }
     179             : #else
     180             :   ASMJIT_UNUSED(s);
     181             :   ASMJIT_UNUSED(len);
     182             : #endif
     183             : 
     184             :   return kErrorOk;
     185             : }
     186             : 
     187             : // ============================================================================
     188             : // [asmjit::Assembler - Building Blocks]
     189             : // ============================================================================
     190             : 
     191           0 : Label Assembler::newLabel() {
     192           0 :   uint32_t id = 0;
     193           0 :   if (!_lastError) {
     194             :     ASMJIT_ASSERT(_code != nullptr);
     195           0 :     Error err = _code->newLabelId(id);
     196           0 :     if (ASMJIT_UNLIKELY(err)) setLastError(err);
     197             :   }
     198           0 :   return Label(id);
     199             : }
     200             : 
     201           0 : Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
     202           0 :   uint32_t id = 0;
     203           0 :   if (!_lastError) {
     204             :     ASMJIT_ASSERT(_code != nullptr);
     205           0 :     Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
     206           0 :     if (ASMJIT_UNLIKELY(err)) setLastError(err);
     207             :   }
     208           0 :   return Label(id);
     209             : }
     210             : 
     211       64222 : Error Assembler::bind(const Label& label) {
     212       64222 :   if (_lastError) return _lastError;
     213             :   ASMJIT_ASSERT(_code != nullptr);
     214             : 
     215       64222 :   LabelEntry* le = _code->getLabelEntry(label);
     216       64222 :   if (ASMJIT_UNLIKELY(!le))
     217           0 :     return setLastError(DebugUtils::errored(kErrorInvalidLabel));
     218             : 
     219             :   // Label can be bound only once.
     220       64222 :   if (ASMJIT_UNLIKELY(le->isBound()))
     221           0 :     return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound));
     222             : 
     223             : #if !defined(ASMJIT_DISABLE_LOGGING)
     224       64222 :   if (_globalOptions & kOptionLoggingEnabled) {
     225             :     StringBuilderTmp<256> sb;
     226           0 :     if (le->hasName())
     227           0 :       sb.setFormat("%s:", le->getName());
     228             :     else
     229           0 :       sb.setFormat("L%u:", Operand::unpackId(label.getId()));
     230             : 
     231             :     size_t binSize = 0;
     232           0 :     if (!_code->_logger->hasOption(Logger::kOptionBinaryForm))
     233             :       binSize = Globals::kInvalidIndex;
     234             : 
     235           0 :     Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment());
     236           0 :     _code->_logger->log(sb.getData(), sb.getLength());
     237             :   }
     238             : #endif // !ASMJIT_DISABLE_LOGGING
     239             : 
     240             :   Error err = kErrorOk;
     241             :   size_t pos = getOffset();
     242             : 
     243       64222 :   LabelLink* link = le->_links;
     244             :   LabelLink* prev = nullptr;
     245             : 
     246       64222 :   while (link) {
     247           0 :     intptr_t offset = link->offset;
     248           0 :     uint32_t relocId = link->relocId;
     249             : 
     250           0 :     if (relocId != RelocEntry::kInvalidId) {
     251             :       // Adjust relocation data.
     252           0 :       RelocEntry* re = _code->_relocations[relocId];
     253           0 :       re->_data += static_cast<uint64_t>(pos);
     254             :     }
     255             :     else {
     256             :       // Not using relocId, this means that we are overwriting a real
     257             :       // displacement in the CodeBuffer.
     258           0 :       int32_t patchedValue = static_cast<int32_t>(
     259           0 :         static_cast<intptr_t>(pos) - offset + link->rel);
     260             : 
     261             :       // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
     262           0 :       uint32_t size = _bufferData[offset];
     263           0 :       if (size == 4)
     264             :         Utils::writeI32u(_bufferData + offset, static_cast<int32_t>(patchedValue));
     265           0 :       else if (size == 1 && Utils::isInt8(patchedValue))
     266           0 :         _bufferData[offset] = static_cast<uint8_t>(patchedValue & 0xFF);
     267             :       else
     268             :         err = DebugUtils::errored(kErrorInvalidDisplacement);
     269             :     }
     270             : 
     271           0 :     prev = link->prev;
     272           0 :     _code->_unresolvedLabelsCount--;
     273           0 :     _code->_baseHeap.release(link, sizeof(LabelLink));
     274             : 
     275             :     link = prev;
     276             :   }
     277             : 
     278             :   // Set as bound.
     279       64222 :   le->_sectionId = _section->getId();
     280       64222 :   le->_offset = pos;
     281       64222 :   le->_links = nullptr;
     282             :   resetInlineComment();
     283             : 
     284       64222 :   if (err != kErrorOk)
     285           0 :     return setLastError(err);
     286             : 
     287             :   return kErrorOk;
     288             : }
     289             : 
     290           0 : Error Assembler::embed(const void* data, uint32_t size) {
     291           0 :   if (_lastError) return _lastError;
     292             : 
     293           0 :   if (getRemainingSpace() < size) {
     294           0 :     Error err = _code->growBuffer(&_section->_buffer, size);
     295           0 :     if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err);
     296             :   }
     297             : 
     298           0 :   ::memcpy(_bufferPtr, data, size);
     299           0 :   _bufferPtr += size;
     300             : 
     301             : #if !defined(ASMJIT_DISABLE_LOGGING)
     302           0 :   if (_globalOptions & kOptionLoggingEnabled)
     303           0 :     _code->_logger->logBinary(data, size);
     304             : #endif // !ASMJIT_DISABLE_LOGGING
     305             : 
     306             :   return kErrorOk;
     307             : }
     308             : 
     309           0 : Error Assembler::embedLabel(const Label& label) {
     310           0 :   if (_lastError) return _lastError;
     311             :   ASMJIT_ASSERT(_code != nullptr);
     312             : 
     313             :   RelocEntry* re;
     314           0 :   LabelEntry* le = _code->getLabelEntry(label);
     315             : 
     316           0 :   if (ASMJIT_UNLIKELY(!le))
     317           0 :     return setLastError(DebugUtils::errored(kErrorInvalidLabel));
     318             : 
     319             :   Error err;
     320             :   uint32_t gpSize = getGpSize();
     321             : 
     322           0 :   if (getRemainingSpace() < gpSize) {
     323           0 :     err = _code->growBuffer(&_section->_buffer, gpSize);
     324           0 :     if (ASMJIT_UNLIKELY(err)) return setLastError(err);
     325             :   }
     326             : 
     327             : #if !defined(ASMJIT_DISABLE_LOGGING)
     328           0 :   if (_globalOptions & kOptionLoggingEnabled)
     329           0 :     _code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId()));
     330             : #endif // !ASMJIT_DISABLE_LOGGING
     331             : 
     332           0 :   err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize);
     333           0 :   if (ASMJIT_UNLIKELY(err)) return setLastError(err);
     334             : 
     335           0 :   re->_sourceSectionId = _section->getId();
     336           0 :   re->_sourceOffset = static_cast<uint64_t>(getOffset());
     337             : 
     338           0 :   if (le->isBound()) {
     339           0 :     re->_targetSectionId = le->getSectionId();
     340           0 :     re->_data = static_cast<uint64_t>(static_cast<int64_t>(le->getOffset()));
     341             :   }
     342             :   else {
     343           0 :     LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0);
     344           0 :     if (ASMJIT_UNLIKELY(!link))
     345           0 :       return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
     346           0 :     link->relocId = re->getId();
     347             :   }
     348             : 
     349             :   // Emit dummy DWORD/QWORD depending on the address size.
     350           0 :   ::memset(_bufferPtr, 0, gpSize);
     351           0 :   _bufferPtr += gpSize;
     352             : 
     353           0 :   return kErrorOk;
     354             : }
     355             : 
     356           0 : Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) {
     357           0 :   if (_lastError) return _lastError;
     358             : 
     359           0 :   if (!isLabelValid(label))
     360             :     return DebugUtils::errored(kErrorInvalidLabel);
     361             : 
     362           0 :   ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
     363           0 :   ASMJIT_PROPAGATE(bind(label));
     364             : 
     365             :   size_t size = pool.getSize();
     366           0 :   if (getRemainingSpace() < size) {
     367           0 :     Error err = _code->growBuffer(&_section->_buffer, size);
     368           0 :     if (ASMJIT_UNLIKELY(err)) return setLastError(err);
     369             :   }
     370             : 
     371           0 :   uint8_t* p = _bufferPtr;
     372           0 :   pool.fill(p);
     373             : 
     374             : #if !defined(ASMJIT_DISABLE_LOGGING)
     375           0 :   if (_globalOptions & kOptionLoggingEnabled)
     376           0 :     _code->_logger->logBinary(p, size);
     377             : #endif // !ASMJIT_DISABLE_LOGGING
     378             : 
     379           0 :   _bufferPtr += size;
     380           0 :   return kErrorOk;
     381             : }
     382             : 
     383             : // ============================================================================
     384             : // [asmjit::Assembler - Emit-Helpers]
     385             : // ============================================================================
     386             : 
     387             : #if !defined(ASMJIT_DISABLE_LOGGING)
     388           0 : void Assembler::_emitLog(
     389             :   uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
     390             :   uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) {
     391             : 
     392           0 :   Logger* logger = _code->getLogger();
     393             :   ASMJIT_ASSERT(logger != nullptr);
     394             :   ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled);
     395             : 
     396             :   StringBuilderTmp<256> sb;
     397             :   uint32_t logOptions = logger->getOptions();
     398             : 
     399           0 :   uint8_t* beforeCursor = _bufferPtr;
     400           0 :   intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
     401             : 
     402             :   sb.appendString(logger->getIndentation());
     403             : 
     404             :   Operand_ opArray[6];
     405             :   opArray[0].copyFrom(o0);
     406             :   opArray[1].copyFrom(o1);
     407             :   opArray[2].copyFrom(o2);
     408             :   opArray[3].copyFrom(o3);
     409             : 
     410           0 :   if (options & kOptionOp4Op5Used) {
     411             :     opArray[4].copyFrom(_op4);
     412             :     opArray[5].copyFrom(_op5);
     413             :   }
     414             :   else {
     415             :     opArray[4].reset();
     416             :     opArray[5].reset();
     417             :   }
     418             : 
     419           0 :   Logging::formatInstruction(
     420             :     sb, logOptions,
     421             :     this, getArchType(),
     422           0 :     Inst::Detail(instId, options, _extraReg), opArray, 6);
     423             : 
     424           0 :   if ((logOptions & Logger::kOptionBinaryForm) != 0)
     425           0 :     Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
     426             :   else
     427           0 :     Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment());
     428             : 
     429             :   logger->log(sb.getData(), sb.getLength());
     430           0 : }
     431             : 
     432           0 : Error Assembler::_emitFailed(
     433             :   Error err,
     434             :   uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
     435             : 
     436             :   StringBuilderTmp<256> sb;
     437           0 :   sb.appendString(DebugUtils::errorAsString(err));
     438             :   sb.appendString(": ");
     439             : 
     440             :   Operand_ opArray[6];
     441             :   opArray[0].copyFrom(o0);
     442             :   opArray[1].copyFrom(o1);
     443             :   opArray[2].copyFrom(o2);
     444             :   opArray[3].copyFrom(o3);
     445             : 
     446           0 :   if (options & kOptionOp4Op5Used) {
     447             :     opArray[4].copyFrom(_op4);
     448             :     opArray[5].copyFrom(_op5);
     449             :   }
     450             :   else {
     451             :     opArray[4].reset();
     452             :     opArray[5].reset();
     453             :   }
     454             : 
     455           0 :   Logging::formatInstruction(
     456             :     sb, 0,
     457             :     this, getArchType(),
     458           0 :     Inst::Detail(instId, options, _extraReg), opArray, 6);
     459             : 
     460             :   resetOptions();
     461             :   resetExtraReg();
     462             :   resetInlineComment();
     463           0 :   return setLastError(err, sb.getData());
     464             : }
     465             : #endif
     466             : 
     467             : } // asmjit namespace
     468             : } // namespace PLMD
     469             : 
     470             : // [Api-End]
     471             : #include "./asmjit_apiend.h"
     472             : #pragma GCC diagnostic pop
     473             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16