LCOV - code coverage report
Current view: top level - asmjit - a64emithelper.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 0 160 0.0 %
Date: 2026-11-05 10:19:06 Functions: 0 10 0.0 %

          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             : #if !defined(ASMJIT_NO_AARCH64)
       9             : 
      10             : #include "formatter.h"
      11             : #include "funcargscontext_p.h"
      12             : #include "moved_string.h"
      13             : #include "support.h"
      14             : #include "type.h"
      15             : #include "a64emithelper_p.h"
      16             : #include "a64formatter_p.h"
      17             : #include "a64instapi_p.h"
      18             : #include "a64operand.h"
      19             : 
      20             : ASMJIT_BEGIN_SUB_NAMESPACE(a64)
      21             : 
      22             : // a64::EmitHelper - Emit Operations
      23             : // =================================
      24             : 
      25           0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove(
      26             :   const Operand_& dst_,
      27             :   const Operand_& src_, TypeId typeId, const char* comment) {
      28             : 
      29           0 :   Emitter* emitter = _emitter->as<Emitter>();
      30             : 
      31             :   // Invalid or abstract TypeIds are not allowed.
      32             :   ASMJIT_ASSERT(TypeUtils::isValid(typeId) && !TypeUtils::isAbstract(typeId));
      33             : 
      34             :   emitter->setInlineComment(comment);
      35             : 
      36           0 :   if (dst_.isReg() && src_.isMem()) {
      37             :     Reg dst(dst_.as<Reg>());
      38             :     Mem src(src_.as<Mem>());
      39             : 
      40           0 :     switch (typeId) {
      41           0 :       case TypeId::kInt8:
      42             :       case TypeId::kUInt8:
      43           0 :         return emitter->ldrb(dst.as<Gp>(), src);
      44             : 
      45           0 :       case TypeId::kInt16:
      46             :       case TypeId::kUInt16:
      47           0 :         return emitter->ldrh(dst.as<Gp>(), src);
      48             : 
      49           0 :       case TypeId::kInt32:
      50             :       case TypeId::kUInt32:
      51           0 :         return emitter->ldr(dst.as<Gp>().w(), src);
      52             : 
      53           0 :       case TypeId::kInt64:
      54             :       case TypeId::kUInt64:
      55           0 :         return emitter->ldr(dst.as<Gp>().x(), src);
      56             : 
      57             :       default: {
      58           0 :         if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId))
      59           0 :           return emitter->ldr(dst.as<Vec>().s(), src);
      60             : 
      61           0 :         if (TypeUtils::isFloat64(typeId) || TypeUtils::isVec64(typeId))
      62           0 :           return emitter->ldr(dst.as<Vec>().d(), src);
      63             : 
      64           0 :         if (TypeUtils::isVec128(typeId))
      65           0 :           return emitter->ldr(dst.as<Vec>().q(), src);
      66             : 
      67             :         break;
      68             :       }
      69             :     }
      70             :   }
      71             : 
      72           0 :   if (dst_.isMem() && src_.isReg()) {
      73             :     Mem dst(dst_.as<Mem>());
      74             :     Reg src(src_.as<Reg>());
      75             : 
      76           0 :     switch (typeId) {
      77           0 :       case TypeId::kInt8:
      78             :       case TypeId::kUInt8:
      79           0 :         return emitter->strb(src.as<Gp>(), dst);
      80             : 
      81           0 :       case TypeId::kInt16:
      82             :       case TypeId::kUInt16:
      83           0 :         return emitter->strh(src.as<Gp>(), dst);
      84             : 
      85           0 :       case TypeId::kInt32:
      86             :       case TypeId::kUInt32:
      87           0 :         return emitter->str(src.as<Gp>().w(), dst);
      88             : 
      89           0 :       case TypeId::kInt64:
      90             :       case TypeId::kUInt64:
      91           0 :         return emitter->str(src.as<Gp>().x(), dst);
      92             : 
      93             :       default: {
      94           0 :         if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId))
      95           0 :           return emitter->str(src.as<Vec>().s(), dst);
      96             : 
      97           0 :         if (TypeUtils::isFloat64(typeId) || TypeUtils::isVec64(typeId))
      98           0 :           return emitter->str(src.as<Vec>().d(), dst);
      99             : 
     100           0 :         if (TypeUtils::isVec128(typeId))
     101           0 :           return emitter->str(src.as<Vec>().q(), dst);
     102             : 
     103             :         break;
     104             :       }
     105             :     }
     106             :   }
     107             : 
     108           0 :   if (dst_.isReg() && src_.isReg()) {
     109             :     Reg dst(dst_.as<Reg>());
     110             :     Reg src(src_.as<Reg>());
     111             : 
     112           0 :     switch (typeId) {
     113           0 :       case TypeId::kInt8:
     114             :       case TypeId::kUInt8:
     115             :       case TypeId::kInt16:
     116             :       case TypeId::kUInt16:
     117             :       case TypeId::kInt32:
     118             :       case TypeId::kUInt32:
     119             :       case TypeId::kInt64:
     120             :       case TypeId::kUInt64:
     121           0 :         return emitter->mov(dst.as<Gp>().x(), src.as<Gp>().x());
     122             : 
     123             :       default: {
     124           0 :         if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId))
     125           0 :           return emitter->fmov(dst.as<Vec>().s(), src.as<Vec>().s());
     126             : 
     127           0 :         if (TypeUtils::isFloat64(typeId) || TypeUtils::isVec64(typeId))
     128           0 :           return emitter->mov(dst.as<Vec>().b8(), src.as<Vec>().b8());
     129             : 
     130           0 :         if (TypeUtils::isVec128(typeId))
     131           0 :           return emitter->mov(dst.as<Vec>().b16(), src.as<Vec>().b16());
     132             : 
     133             :         break;
     134             :       }
     135             :     }
     136             :   }
     137             : 
     138             :   emitter->setInlineComment(nullptr);
     139           0 :   return DebugUtils::errored(kErrorInvalidState);
     140             : }
     141             : 
     142           0 : Error EmitHelper::emitRegSwap(
     143             :   const BaseReg& a,
     144             :   const BaseReg& b, const char* comment) {
     145             : 
     146             :   DebugUtils::unused(a, b, comment);
     147           0 :   return DebugUtils::errored(kErrorInvalidState);
     148             : }
     149             : 
     150             : // TODO: [ARM] EmitArgMove is unfinished.
     151           0 : Error EmitHelper::emitArgMove(
     152             :   const BaseReg& dst_, TypeId dstTypeId,
     153             :   const Operand_& src_, TypeId srcTypeId, const char* comment) {
     154             : 
     155             :   // Deduce optional `dstTypeId`, which may be `TypeId::kVoid` in some cases.
     156           0 :   if (dstTypeId == TypeId::kVoid) {
     157           0 :     const ArchTraits& archTraits = ArchTraits::byArch(_emitter->arch());
     158             :     dstTypeId = archTraits.regTypeToTypeId(dst_.type());
     159             :   }
     160             : 
     161             :   // Invalid or abstract TypeIds are not allowed.
     162             :   ASMJIT_ASSERT(TypeUtils::isValid(dstTypeId) && !TypeUtils::isAbstract(dstTypeId));
     163             :   ASMJIT_ASSERT(TypeUtils::isValid(srcTypeId) && !TypeUtils::isAbstract(srcTypeId));
     164             : 
     165             :   Reg dst(dst_.as<Reg>());
     166             :   Operand src(src_);
     167             : 
     168             :   uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
     169             :   uint32_t srcSize = TypeUtils::sizeOf(srcTypeId);
     170             : 
     171             :   if (TypeUtils::isInt(dstTypeId)) {
     172             :     if (TypeUtils::isInt(srcTypeId)) {
     173             :       uint32_t x = dstSize == 8;
     174             : 
     175           0 :       dst.setSignature(OperandSignature{x ? uint32_t(GpX::kSignature) : uint32_t(GpW::kSignature)});
     176           0 :       _emitter->setInlineComment(comment);
     177             : 
     178           0 :       if (src.isReg()) {
     179             :         src.setSignature(dst.signature());
     180           0 :         return _emitter->emit(Inst::kIdMov, dst, src);
     181             :       }
     182           0 :       else if (src.isMem()) {
     183             :         InstId instId = Inst::kIdNone;
     184           0 :           switch (srcTypeId) {
     185             :           case TypeId::kInt8: instId = Inst::kIdLdrsb; break;
     186           0 :           case TypeId::kUInt8: instId = Inst::kIdLdrb; break;
     187           0 :           case TypeId::kInt16: instId = Inst::kIdLdrsh; break;
     188           0 :           case TypeId::kUInt16: instId = Inst::kIdLdrh; break;
     189           0 :           case TypeId::kInt32: instId = x ? Inst::kIdLdrsw : Inst::kIdLdr; break;
     190           0 :           case TypeId::kUInt32: instId = Inst::kIdLdr; x = 0; break;
     191           0 :           case TypeId::kInt64: instId = Inst::kIdLdr; break;
     192           0 :           case TypeId::kUInt64: instId = Inst::kIdLdr; break;
     193             :           default:
     194             :             return DebugUtils::errored(kErrorInvalidState);
     195             :         }
     196           0 :         return _emitter->emit(instId, dst, src);
     197             :       }
     198             :     }
     199             :   }
     200             : 
     201             :   if (TypeUtils::isFloat(dstTypeId) || TypeUtils::isVec(dstTypeId)) {
     202             :     if (TypeUtils::isFloat(srcTypeId) || TypeUtils::isVec(srcTypeId)) {
     203           0 :       switch (srcSize) {
     204           0 :         case 2: dst.as<Vec>().setSignature(OperandSignature{VecH::kSignature}); break;
     205           0 :         case 4: dst.as<Vec>().setSignature(OperandSignature{VecS::kSignature}); break;
     206           0 :         case 8: dst.as<Vec>().setSignature(OperandSignature{VecD::kSignature}); break;
     207           0 :         case 16: dst.as<Vec>().setSignature(OperandSignature{VecV::kSignature}); break;
     208             :         default:
     209             :           return DebugUtils::errored(kErrorInvalidState);
     210             :       }
     211             : 
     212           0 :       _emitter->setInlineComment(comment);
     213             : 
     214           0 :       if (src.isReg()) {
     215           0 :         InstId instId = srcSize <= 4 ? Inst::kIdFmov_v : Inst::kIdMov_v;
     216             :         src.setSignature(dst.signature());
     217           0 :         return _emitter->emit(instId, dst, src);
     218             :       }
     219           0 :       else if (src.isMem()) {
     220           0 :         return _emitter->emit(Inst::kIdLdr_v, dst, src);
     221             :       }
     222             :     }
     223             :   }
     224             : 
     225             :   return DebugUtils::errored(kErrorInvalidState);
     226             : }
     227             : 
     228             : // a64::EmitHelper - Emit Prolog & Epilog
     229             : // ======================================
     230             : 
     231             : struct LoadStoreInstructions {
     232             :   InstId singleInstId;
     233             :   InstId pairInstId;
     234             : };
     235             : 
     236             : struct PrologEpilogInfo {
     237             :   struct RegPair {
     238             :     uint8_t ids[2];
     239             :     uint16_t offset;
     240             :   };
     241             : 
     242             :   struct GroupData {
     243             :     RegPair pairs[16];
     244             :     uint32_t pairCount;
     245             :   };
     246             : 
     247             :   Support::Array<GroupData, 2> groups;
     248             :   uint32_t sizeTotal;
     249             : 
     250           0 :   Error init(const FuncFrame& frame) noexcept {
     251             :     uint32_t offset = 0;
     252             : 
     253           0 :     for (RegGroup group : Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kVec>{}) {
     254             :       GroupData& data = groups[group];
     255             : 
     256             :       uint32_t n = 0;
     257             :       uint32_t pairCount = 0;
     258           0 :       RegPair* pairs = data.pairs;
     259             : 
     260             :       uint32_t slotSize = frame.saveRestoreRegSize(group);
     261             :       uint32_t savedRegs = frame.savedRegs(group);
     262             : 
     263           0 :       if (group == RegGroup::kGp && frame.hasPreservedFP()) {
     264             :         // Must be at the beginning of the push/pop sequence.
     265             :         ASMJIT_ASSERT(pairCount == 0);
     266             : 
     267           0 :         pairs[0].offset = uint16_t(offset);
     268           0 :         pairs[0].ids[0] = Gp::kIdFp;
     269           0 :         pairs[0].ids[1] = Gp::kIdLr;
     270           0 :         offset += slotSize * 2;
     271             :         pairCount++;
     272             : 
     273           0 :         savedRegs &= ~Support::bitMask(Gp::kIdFp, Gp::kIdLr);
     274             :       }
     275             : 
     276             :       Support::BitWordIterator<uint32_t> it(savedRegs);
     277           0 :       while (it.hasNext()) {
     278           0 :         pairs[pairCount].ids[n] = uint8_t(it.next());
     279             : 
     280           0 :         if (++n == 2) {
     281           0 :           pairs[pairCount].offset = uint16_t(offset);
     282           0 :           offset += slotSize * 2;
     283             : 
     284             :           n = 0;
     285           0 :           pairCount++;
     286             :         }
     287             :       }
     288             : 
     289           0 :       if (n == 1) {
     290           0 :         pairs[pairCount].ids[1] = uint8_t(BaseReg::kIdBad);
     291           0 :         pairs[pairCount].offset = uint16_t(offset);
     292           0 :         offset += slotSize * 2;
     293           0 :         pairCount++;
     294             :       }
     295             : 
     296           0 :       data.pairCount = pairCount;
     297             :     }
     298             : 
     299           0 :     sizeTotal = offset;
     300           0 :     return kErrorOk;
     301             :   }
     302             : };
     303             : 
     304           0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
     305           0 :   Emitter* emitter = _emitter->as<Emitter>();
     306             : 
     307             :   PrologEpilogInfo pei;
     308           0 :   ASMJIT_PROPAGATE(pei.init(frame));
     309             : 
     310             :   static const Support::Array<Reg, 2> groupRegs = {{ x0, d0 }};
     311             :   static const Support::Array<LoadStoreInstructions, 2> groupInsts = {{
     312             :     { Inst::kIdStr  , Inst::kIdStp   },
     313             :     { Inst::kIdStr_v, Inst::kIdStp_v }
     314             :   }};
     315             : 
     316           0 :   uint32_t adjustInitialOffset = pei.sizeTotal;
     317             : 
     318           0 :   for (RegGroup group : Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kVec>{}) {
     319             :     const PrologEpilogInfo::GroupData& data = pei.groups[group];
     320           0 :     uint32_t pairCount = data.pairCount;
     321             : 
     322             :     Reg regs[2] = { groupRegs[group], groupRegs[group] };
     323           0 :     Mem mem = ptr(sp);
     324             : 
     325             :     const LoadStoreInstructions& insts = groupInsts[group];
     326           0 :     for (uint32_t i = 0; i < pairCount; i++) {
     327             :       const PrologEpilogInfo::RegPair& pair = data.pairs[i];
     328             : 
     329           0 :       regs[0].setId(pair.ids[0]);
     330           0 :       regs[1].setId(pair.ids[1]);
     331           0 :       mem.setOffsetLo32(pair.offset);
     332             : 
     333           0 :       if (pair.offset == 0 && adjustInitialOffset) {
     334           0 :         mem.setOffset(-int(adjustInitialOffset));
     335           0 :         mem.makePreIndex();
     336             :       }
     337             : 
     338           0 :       if (pair.ids[1] == BaseReg::kIdBad)
     339           0 :         ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
     340             :       else
     341           0 :         ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
     342             : 
     343             :       mem.resetToFixedOffset();
     344             : 
     345           0 :       if (i == 0 && frame.hasPreservedFP()) {
     346           0 :         ASMJIT_PROPAGATE(emitter->mov(x29, sp));
     347             :       }
     348             :     }
     349             :   }
     350             : 
     351           0 :   if (frame.hasStackAdjustment()) {
     352             :     uint32_t adj = frame.stackAdjustment();
     353           0 :     if (adj <= 0xFFFu) {
     354           0 :       ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj));
     355             :     }
     356           0 :     else if (adj <= 0xFFFFFFu)  {
     357             :       // TODO: [ARM] Prolog - we must touch the pages otherwise it's undefined.
     358           0 :       ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0x000FFFu));
     359           0 :       ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0xFFF000u));
     360             :     }
     361             :     else {
     362             :       return DebugUtils::errored(kErrorInvalidState);
     363             :     }
     364             :   }
     365             : 
     366             :   return kErrorOk;
     367             : }
     368             : 
     369             : // TODO: [ARM] Emit epilog.
     370           0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
     371           0 :   Emitter* emitter = _emitter->as<Emitter>();
     372             : 
     373             :   PrologEpilogInfo pei;
     374           0 :   ASMJIT_PROPAGATE(pei.init(frame));
     375             : 
     376             :   static const Support::Array<Reg, 2> groupRegs = {{ x0, d0 }};
     377             :   static const Support::Array<LoadStoreInstructions, 2> groupInsts = {{
     378             :     { Inst::kIdLdr  , Inst::kIdLdp   },
     379             :     { Inst::kIdLdr_v, Inst::kIdLdp_v }
     380             :   }};
     381             : 
     382           0 :   uint32_t adjustInitialOffset = pei.sizeTotal;
     383             : 
     384           0 :   if (frame.hasStackAdjustment()) {
     385             :     uint32_t adj = frame.stackAdjustment();
     386           0 :     if (adj <= 0xFFFu) {
     387           0 :       ASMJIT_PROPAGATE(emitter->add(sp, sp, adj));
     388             :     }
     389           0 :     else if (adj <= 0xFFFFFFu)  {
     390           0 :       ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0x000FFFu));
     391           0 :       ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0xFFF000u));
     392             :     }
     393             :     else {
     394             :       return DebugUtils::errored(kErrorInvalidState);
     395             :     }
     396             :   }
     397             : 
     398           0 :   for (int g = 1; g >= 0; g--) {
     399             :     RegGroup group = RegGroup(g);
     400             :     const PrologEpilogInfo::GroupData& data = pei.groups[group];
     401           0 :     uint32_t pairCount = data.pairCount;
     402             : 
     403             :     Reg regs[2] = { groupRegs[group], groupRegs[group] };
     404           0 :     Mem mem = ptr(sp);
     405             : 
     406             :     const LoadStoreInstructions& insts = groupInsts[group];
     407             : 
     408           0 :     for (int i = int(pairCount) - 1; i >= 0; i--) {
     409             :       const PrologEpilogInfo::RegPair& pair = data.pairs[i];
     410             : 
     411           0 :       regs[0].setId(pair.ids[0]);
     412           0 :       regs[1].setId(pair.ids[1]);
     413           0 :       mem.setOffsetLo32(pair.offset);
     414             : 
     415           0 :       if (pair.offset == 0 && adjustInitialOffset) {
     416           0 :         mem.setOffset(int(adjustInitialOffset));
     417           0 :         mem.makePostIndex();
     418             :       }
     419             : 
     420           0 :       if (pair.ids[1] == BaseReg::kIdBad)
     421           0 :         ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
     422             :       else
     423           0 :         ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
     424             : 
     425             :       mem.resetToFixedOffset();
     426             :     }
     427             :   }
     428             : 
     429           0 :   ASMJIT_PROPAGATE(emitter->ret(x30));
     430             : 
     431             :   return kErrorOk;
     432             : }
     433             : 
     434           0 : static Error ASMJIT_CDECL Emitter_emitProlog(BaseEmitter* emitter, const FuncFrame& frame) {
     435             :   EmitHelper emitHelper(emitter);
     436           0 :   return emitHelper.emitProlog(frame);
     437             : }
     438             : 
     439           0 : static Error ASMJIT_CDECL Emitter_emitEpilog(BaseEmitter* emitter, const FuncFrame& frame) {
     440             :   EmitHelper emitHelper(emitter);
     441           0 :   return emitHelper.emitEpilog(frame);
     442             : }
     443             : 
     444           0 : static Error ASMJIT_CDECL Emitter_emitArgsAssignment(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args) {
     445             :   EmitHelper emitHelper(emitter);
     446           0 :   return emitHelper.emitArgsAssignment(frame, args);
     447             : }
     448             : 
     449           0 : void assignEmitterFuncs(BaseEmitter* emitter) {
     450           0 :   emitter->_funcs.emitProlog = Emitter_emitProlog;
     451           0 :   emitter->_funcs.emitEpilog = Emitter_emitEpilog;
     452           0 :   emitter->_funcs.emitArgsAssignment = Emitter_emitArgsAssignment;
     453             : 
     454             : #ifndef ASMJIT_NO_LOGGING
     455           0 :   emitter->_funcs.formatInstruction = FormatterInternal::formatInstruction;
     456             : #endif
     457             : 
     458             : #ifndef ASMJIT_NO_VALIDATION
     459           0 :   emitter->_funcs.validate = InstInternal::validate;
     460             : #endif
     461           0 : }
     462             : 
     463             : ASMJIT_END_SUB_NAMESPACE
     464             : 
     465             : #endif // !ASMJIT_NO_AARCH64
     466             : 
     467             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16