LCOV - code coverage report
Current view: top level - asmjit - x86compiler.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 48 151 31.8 %
Date: 2024-10-18 14:00:27 Functions: 5 7 71.4 %

          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_BUILD_X86) && !defined(ASMJIT_DISABLE_COMPILER)
      35             : 
      36             : // [Dependencies]
      37             : #include "./utils.h"
      38             : #include "./x86compiler.h"
      39             : #include "./x86regalloc_p.h"
      40             : 
      41             : // [Api-Begin]
      42             : #include "./asmjit_apibegin.h"
      43             : 
      44             : namespace PLMD {
      45             : namespace asmjit {
      46             : 
      47             : // ============================================================================
      48             : // [asmjit::X86Compiler - Construction / Destruction]
      49             : // ============================================================================
      50             : 
      51       32111 : X86Compiler::X86Compiler(CodeHolder* code) noexcept : CodeCompiler() {
      52       32111 :   if (code)
      53       32111 :     code->attach(this);
      54       32111 : }
      55       32111 : X86Compiler::~X86Compiler() noexcept {}
      56             : 
      57             : // ============================================================================
      58             : // [asmjit::X86Compiler - Events]
      59             : // ============================================================================
      60             : 
      61       32111 : Error X86Compiler::onAttach(CodeHolder* code) noexcept {
      62             :   uint32_t archType = code->getArchType();
      63       32111 :   if (!ArchInfo::isX86Family(archType))
      64             :     return DebugUtils::errored(kErrorInvalidArch);
      65             : 
      66       64222 :   ASMJIT_PROPAGATE(_cbPasses.willGrow(&_cbHeap, 1));
      67       32111 :   ASMJIT_PROPAGATE(Base::onAttach(code));
      68             : 
      69       32111 :   if (archType == ArchInfo::kTypeX86)
      70           0 :     _nativeGpArray = x86OpData.gpd;
      71             :   else
      72       32111 :     _nativeGpArray = x86OpData.gpq;
      73       32111 :   _nativeGpReg = _nativeGpArray[0];
      74             : 
      75       64222 :   return addPassT<X86RAPass>();
      76             : }
      77             : 
      78             : // ============================================================================
      79             : // [asmjit::X86Compiler - Finalize]
      80             : // ============================================================================
      81             : 
      82       32111 : Error X86Compiler::finalize() {
      83       32111 :   if (_lastError) return _lastError;
      84             : 
      85             :   // Flush the global constant pool.
      86       32111 :   if (_globalConstPool) {
      87           0 :     addNode(_globalConstPool);
      88           0 :     _globalConstPool = nullptr;
      89             :   }
      90             : 
      91             :   Error err = kErrorOk;
      92             :   ZoneVector<CBPass*>& passes = _cbPasses;
      93             : 
      94       64222 :   for (size_t i = 0, len = passes.getLength(); i < len; i++) {
      95       32111 :     CBPass* pass = passes[i];
      96       32111 :     err = pass->process(&_cbPassZone);
      97       32111 :     _cbPassZone.reset();
      98       32111 :     if (err) break;
      99             :   }
     100             : 
     101       32111 :   _cbPassZone.reset();
     102       32111 :   if (ASMJIT_UNLIKELY(err)) return setLastError(err);
     103             : 
     104             :   // TODO: There must be possibility to attach more assemblers, this is not so nice.
     105       32111 :   if (_code->_cgAsm) {
     106           0 :     return serialize(_code->_cgAsm);
     107             :   }
     108             :   else {
     109       32111 :     X86Assembler a(_code);
     110       32111 :     return serialize(&a);
     111       32111 :   }
     112             : }
     113             : 
     114             : // ============================================================================
     115             : // [asmjit::X86Compiler - Inst]
     116             : // ============================================================================
     117             : 
     118             : static ASMJIT_INLINE bool isJumpInst(uint32_t instId) noexcept {
     119      580178 :   return (instId >= X86Inst::kIdJa   && instId <= X86Inst::kIdJz    ) ||
     120      580178 :          (instId >= X86Inst::kIdLoop && instId <= X86Inst::kIdLoopne) ;
     121             : }
     122             : 
     123      580178 : Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
     124      580178 :   uint32_t options = getOptions() | getGlobalOptions();
     125             :   const char* inlineComment = getInlineComment();
     126             : 
     127      580178 :   uint32_t opCount = static_cast<uint32_t>(!o0.isNone()) +
     128      580178 :                      static_cast<uint32_t>(!o1.isNone()) +
     129      580178 :                      static_cast<uint32_t>(!o2.isNone()) +
     130      580178 :                      static_cast<uint32_t>(!o3.isNone()) ;
     131             : 
     132             :   // Handle failure and rare cases first.
     133             :   const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter is in error state.
     134             :                                           kOptionStrictValidation ; // Strict validation.
     135             : 
     136      580178 :   if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
     137             :     // Don't do anything if we are in error state.
     138           0 :     if (_lastError) return _lastError;
     139             : 
     140             : #if !defined(ASMJIT_DISABLE_VALIDATION)
     141             :     // Strict validation.
     142           0 :     if (options & kOptionStrictValidation) {
     143             :       Operand opArray[] = {
     144             :         Operand(o0),
     145             :         Operand(o1),
     146             :         Operand(o2),
     147             :         Operand(o3)
     148             :       };
     149             : 
     150             :       Inst::Detail instDetail(instId, options, _extraReg);
     151           0 :       Error err = Inst::validate(getArchType(), instDetail, opArray, opCount);
     152             : 
     153           0 :       if (err) {
     154             : #if !defined(ASMJIT_DISABLE_LOGGING)
     155             :         StringBuilderTmp<256> sb;
     156           0 :         sb.appendString(DebugUtils::errorAsString(err));
     157             :         sb.appendString(": ");
     158           0 :         Logging::formatInstruction(sb, 0, this, getArchType(), instDetail, opArray, opCount);
     159           0 :         return setLastError(err, sb.getData());
     160             : #else
     161             :         return setLastError(err);
     162             : #endif
     163             :       }
     164             : 
     165             :       // Clear it as it must be enabled explicitly on assembler side.
     166           0 :       options &= ~kOptionStrictValidation;
     167             :     }
     168             : #endif // ASMJIT_DISABLE_VALIDATION
     169             :   }
     170             : 
     171             :   resetOptions();
     172             :   resetInlineComment();
     173             : 
     174             :   // decide between `CBInst` and `CBJump`.
     175      580178 :   if (isJumpInst(instId)) {
     176           0 :     CBJump* node = _cbHeap.allocT<CBJump>(sizeof(CBJump) + opCount * sizeof(Operand));
     177           0 :     Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBJump));
     178             : 
     179           0 :     if (ASMJIT_UNLIKELY(!node))
     180           0 :       return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
     181             : 
     182           0 :     if (opCount > 0) opArray[0].copyFrom(o0);
     183           0 :     if (opCount > 1) opArray[1].copyFrom(o1);
     184           0 :     if (opCount > 2) opArray[2].copyFrom(o2);
     185           0 :     if (opCount > 3) opArray[3].copyFrom(o3);
     186             : 
     187             :     new(node) CBJump(this, instId, options, opArray, opCount);
     188           0 :     node->_instDetail.extraReg = _extraReg;
     189             :     _extraReg.reset();
     190             : 
     191           0 :     CBLabel* jTarget = nullptr;
     192           0 :     if (!(options & kOptionUnfollow)) {
     193           0 :       if (opArray[0].isLabel()) {
     194           0 :         Error err = getCBLabel(&jTarget, static_cast<Label&>(opArray[0]));
     195           0 :         if (err) return setLastError(err);
     196             :       }
     197             :       else {
     198           0 :         options |= kOptionUnfollow;
     199             :       }
     200             :     }
     201             :     node->setOptions(options);
     202             : 
     203           0 :     node->orFlags(instId == X86Inst::kIdJmp ? CBNode::kFlagIsJmp | CBNode::kFlagIsTaken : CBNode::kFlagIsJcc);
     204           0 :     node->_target = jTarget;
     205           0 :     node->_jumpNext = nullptr;
     206             : 
     207           0 :     if (jTarget) {
     208           0 :       node->_jumpNext = static_cast<CBJump*>(jTarget->_from);
     209           0 :       jTarget->_from = node;
     210             :       jTarget->addNumRefs();
     211             :     }
     212             : 
     213             :     // The 'jmp' is always taken, conditional jump can contain hint, we detect it.
     214           0 :     if (instId == X86Inst::kIdJmp)
     215             :       node->orFlags(CBNode::kFlagIsTaken);
     216           0 :     else if (options & X86Inst::kOptionTaken)
     217             :       node->orFlags(CBNode::kFlagIsTaken);
     218             : 
     219           0 :     if (inlineComment) {
     220           0 :       inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
     221             :       node->setInlineComment(inlineComment);
     222             :     }
     223             : 
     224           0 :     addNode(node);
     225           0 :     return kErrorOk;
     226             :   }
     227             :   else {
     228      580178 :     CBInst* node = _cbHeap.allocT<CBInst>(sizeof(CBInst) + opCount * sizeof(Operand));
     229      580178 :     Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBInst));
     230             : 
     231      580178 :     if (ASMJIT_UNLIKELY(!node))
     232           0 :       return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
     233             : 
     234      580178 :     if (opCount > 0) opArray[0].copyFrom(o0);
     235      580178 :     if (opCount > 1) opArray[1].copyFrom(o1);
     236      580178 :     if (opCount > 2) opArray[2].copyFrom(o2);
     237      580178 :     if (opCount > 3) opArray[3].copyFrom(o3);
     238             : 
     239             :     node = new(node) CBInst(this, instId, options, opArray, opCount);
     240      580178 :     node->_instDetail.extraReg = _extraReg;
     241             :     _extraReg.reset();
     242             : 
     243      580178 :     if (inlineComment) {
     244           0 :       inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
     245             :       node->setInlineComment(inlineComment);
     246             :     }
     247             : 
     248      580178 :     addNode(node);
     249      580178 :     return kErrorOk;
     250             :   }
     251             : }
     252             : 
     253           0 : Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
     254           0 :   uint32_t options = getOptions() | getGlobalOptions();
     255             :   const char* inlineComment = getInlineComment();
     256             : 
     257           0 :   uint32_t opCount = static_cast<uint32_t>(!o0.isNone()) +
     258           0 :                      static_cast<uint32_t>(!o1.isNone()) +
     259           0 :                      static_cast<uint32_t>(!o2.isNone()) +
     260           0 :                      static_cast<uint32_t>(!o3.isNone()) ;
     261             : 
     262             :   // Count 5th and 6th operands.
     263           0 :   if (!o4.isNone()) opCount = 5;
     264           0 :   if (!o5.isNone()) opCount = 6;
     265             : 
     266             :   // Handle failure and rare cases first.
     267             :   const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter in error state.
     268             :                                           kOptionStrictValidation ; // Strict validation.
     269             : 
     270           0 :   if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
     271             :     // Don't do anything if we are in error state.
     272           0 :     if (_lastError) return _lastError;
     273             : 
     274             : #if !defined(ASMJIT_DISABLE_VALIDATION)
     275             :     // Strict validation.
     276           0 :     if (options & kOptionStrictValidation) {
     277             :       Operand opArray[] = {
     278             :         Operand(o0),
     279             :         Operand(o1),
     280             :         Operand(o2),
     281             :         Operand(o3),
     282             :         Operand(o4),
     283             :         Operand(o5)
     284             :       };
     285             : 
     286             :       Inst::Detail instDetail(instId, options, _extraReg);
     287           0 :       Error err = Inst::validate(getArchType(), instDetail, opArray, opCount);
     288             : 
     289           0 :       if (err) {
     290             : #if !defined(ASMJIT_DISABLE_LOGGING)
     291             :         StringBuilderTmp<256> sb;
     292           0 :         sb.appendString(DebugUtils::errorAsString(err));
     293             :         sb.appendString(": ");
     294           0 :         Logging::formatInstruction(sb, 0, this, getArchType(), instDetail, opArray, opCount);
     295           0 :         return setLastError(err, sb.getData());
     296             : #else
     297             :         return setLastError(err);
     298             : #endif
     299             :       }
     300             : 
     301             :       // Clear it as it must be enabled explicitly on assembler side.
     302           0 :       options &= ~kOptionStrictValidation;
     303             :     }
     304             : #endif // ASMJIT_DISABLE_VALIDATION
     305             :   }
     306             : 
     307             :   resetOptions();
     308             :   resetInlineComment();
     309             : 
     310             :   // decide between `CBInst` and `CBJump`.
     311           0 :   if (isJumpInst(instId)) {
     312           0 :     CBJump* node = _cbHeap.allocT<CBJump>(sizeof(CBJump) + opCount * sizeof(Operand));
     313           0 :     Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBJump));
     314             : 
     315           0 :     if (ASMJIT_UNLIKELY(!node))
     316           0 :       return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
     317             : 
     318           0 :     if (opCount > 0) opArray[0].copyFrom(o0);
     319           0 :     if (opCount > 1) opArray[1].copyFrom(o1);
     320           0 :     if (opCount > 2) opArray[2].copyFrom(o2);
     321           0 :     if (opCount > 3) opArray[3].copyFrom(o3);
     322           0 :     if (opCount > 4) opArray[4].copyFrom(o4);
     323           0 :     if (opCount > 5) opArray[5].copyFrom(o5);
     324             : 
     325             :     new(node) CBJump(this, instId, options, opArray, opCount);
     326           0 :     node->_instDetail.extraReg = _extraReg;
     327             :     _extraReg.reset();
     328             : 
     329           0 :     CBLabel* jTarget = nullptr;
     330           0 :     if (!(options & kOptionUnfollow)) {
     331           0 :       if (opArray[0].isLabel()) {
     332           0 :         Error err = getCBLabel(&jTarget, static_cast<Label&>(opArray[0]));
     333           0 :         if (err) return setLastError(err);
     334             :       }
     335             :       else {
     336           0 :         options |= kOptionUnfollow;
     337             :       }
     338             :     }
     339             :     node->setOptions(options);
     340             : 
     341           0 :     node->orFlags(instId == X86Inst::kIdJmp ? CBNode::kFlagIsJmp | CBNode::kFlagIsTaken : CBNode::kFlagIsJcc);
     342           0 :     node->_target = jTarget;
     343           0 :     node->_jumpNext = nullptr;
     344             : 
     345           0 :     if (jTarget) {
     346           0 :       node->_jumpNext = static_cast<CBJump*>(jTarget->_from);
     347           0 :       jTarget->_from = node;
     348             :       jTarget->addNumRefs();
     349             :     }
     350             : 
     351             :     // The 'jmp' is always taken, conditional jump can contain hint, we detect it.
     352           0 :     if (instId == X86Inst::kIdJmp)
     353             :       node->orFlags(CBNode::kFlagIsTaken);
     354           0 :     else if (options & X86Inst::kOptionTaken)
     355             :       node->orFlags(CBNode::kFlagIsTaken);
     356             : 
     357           0 :     if (inlineComment) {
     358           0 :       inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
     359             :       node->setInlineComment(inlineComment);
     360             :     }
     361             : 
     362           0 :     addNode(node);
     363           0 :     return kErrorOk;
     364             :   }
     365             :   else {
     366           0 :     CBInst* node = _cbHeap.allocT<CBInst>(sizeof(CBInst) + opCount * sizeof(Operand));
     367           0 :     Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBInst));
     368             : 
     369           0 :     if (ASMJIT_UNLIKELY(!node))
     370           0 :       return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
     371             : 
     372           0 :     if (opCount > 0) opArray[0].copyFrom(o0);
     373           0 :     if (opCount > 1) opArray[1].copyFrom(o1);
     374           0 :     if (opCount > 2) opArray[2].copyFrom(o2);
     375           0 :     if (opCount > 3) opArray[3].copyFrom(o3);
     376           0 :     if (opCount > 4) opArray[4].copyFrom(o4);
     377           0 :     if (opCount > 5) opArray[5].copyFrom(o5);
     378             : 
     379             :     node = new(node) CBInst(this, instId, options, opArray, opCount);
     380           0 :     node->_instDetail.extraReg = _extraReg;
     381             :     _extraReg.reset();
     382             : 
     383           0 :     if (inlineComment) {
     384           0 :       inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
     385             :       node->setInlineComment(inlineComment);
     386             :     }
     387             : 
     388           0 :     addNode(node);
     389           0 :     return kErrorOk;
     390             :   }
     391             : }
     392             : 
     393             : } // asmjit namespace
     394             : } // namespace PLMD
     395             : 
     396             : // [Api-End]
     397             : #include "./asmjit_apiend.h"
     398             : 
     399             : // [Guard]
     400             : #endif // ASMJIT_BUILD_X86 && !ASMJIT_DISABLE_COMPILER
     401             : #pragma GCC diagnostic pop
     402             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16