LCOV - code coverage report
Current view: top level - asmjit - a64rapass.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 0 254 0.0 %
Date: 2026-11-05 10:19:06 Functions: 0 23 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) && !defined(ASMJIT_NO_COMPILER)
       9             : 
      10             : #include "cpuinfo.h"
      11             : #include "support.h"
      12             : #include "type.h"
      13             : #include "a64assembler.h"
      14             : #include "a64compiler.h"
      15             : #include "a64emithelper_p.h"
      16             : #include "a64instapi_p.h"
      17             : #include "a64instdb_p.h"
      18             : #include "a64rapass_p.h"
      19             : 
      20             : ASMJIT_BEGIN_SUB_NAMESPACE(a64)
      21             : 
      22             : // a64::ARMRAPass - Helpers
      23             : // ========================
      24             : 
      25             : // TODO: [ARM] These should be shared with all backends.
      26             : ASMJIT_MAYBE_UNUSED
      27             : static inline uint64_t raImmMaskFromSize(uint32_t size) noexcept {
      28             :   ASMJIT_ASSERT(size > 0 && size < 256);
      29             :   static const uint64_t masks[] = {
      30             :     0x00000000000000FFu, //   1
      31             :     0x000000000000FFFFu, //   2
      32             :     0x00000000FFFFFFFFu, //   4
      33             :     0xFFFFFFFFFFFFFFFFu, //   8
      34             :     0x0000000000000000u, //  16
      35             :     0x0000000000000000u, //  32
      36             :     0x0000000000000000u, //  64
      37             :     0x0000000000000000u, // 128
      38             :     0x0000000000000000u  // 256
      39             :   };
      40             :   return masks[Support::ctz(size)];
      41             : }
      42             : 
      43             : static const RegMask raConsecutiveLeadCountToRegMaskFilter[5] = {
      44             :   0xFFFFFFFFu, // [0] No consecutive.
      45             :   0x00000000u, // [1] Invalid, never used.
      46             :   0x7FFFFFFFu, // [2] 2 consecutive registers.
      47             :   0x3FFFFFFFu, // [3] 3 consecutive registers.
      48             :   0x1FFFFFFFu  // [4] 4 consecutive registers.
      49             : };
      50             : 
      51             : static inline RATiedFlags raUseOutFlagsFromRWFlags(OpRWFlags rwFlags) noexcept {
      52             :   static constexpr RATiedFlags map[] = {
      53             :     RATiedFlags::kNone,
      54             :     RATiedFlags::kRead  | RATiedFlags::kUse, // kRead
      55             :     RATiedFlags::kWrite | RATiedFlags::kOut, // kWrite
      56             :     RATiedFlags::kRW    | RATiedFlags::kUse, // kRW
      57             :   };
      58             : 
      59           0 :   return map[uint32_t(rwFlags & OpRWFlags::kRW)];
      60             : }
      61             : 
      62             : static inline RATiedFlags raRegRwFlags(OpRWFlags flags) noexcept {
      63             :   return raUseOutFlagsFromRWFlags(flags);
      64             : }
      65             : 
      66             : static inline RATiedFlags raMemBaseRwFlags(OpRWFlags flags) noexcept {
      67             :   constexpr uint32_t shift = Support::ConstCTZ<uint32_t(OpRWFlags::kMemBaseRW)>::value;
      68           0 :   return raUseOutFlagsFromRWFlags(OpRWFlags(uint32_t(flags) >> shift) & OpRWFlags::kRW);
      69             : }
      70             : 
      71             : static inline RATiedFlags raMemIndexRwFlags(OpRWFlags flags) noexcept {
      72             :   constexpr uint32_t shift = Support::ConstCTZ<uint32_t(OpRWFlags::kMemIndexRW)>::value;
      73           0 :   return raUseOutFlagsFromRWFlags(OpRWFlags(uint32_t(flags) >> shift) & OpRWFlags::kRW);
      74             : }
      75             : // a64::RACFGBuilder
      76             : // =================
      77             : 
      78             : class RACFGBuilder : public RACFGBuilderT<RACFGBuilder> {
      79             : public:
      80             :   Arch _arch;
      81             : 
      82             :   inline RACFGBuilder(ARMRAPass* pass) noexcept
      83           0 :     : RACFGBuilderT<RACFGBuilder>(pass),
      84           0 :       _arch(pass->cc()->arch()) {}
      85             : 
      86           0 :   inline Compiler* cc() const noexcept { return static_cast<Compiler*>(_cc); }
      87             : 
      88             :   Error onInst(InstNode* inst, InstControlFlow& controlType, RAInstBuilder& ib) noexcept;
      89             : 
      90             :   Error onBeforeInvoke(InvokeNode* invokeNode) noexcept;
      91             :   Error onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept;
      92             : 
      93             :   Error moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept;
      94             :   Error moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept;
      95             :   Error moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept;
      96             : 
      97             :   Error onBeforeRet(FuncRetNode* funcRet) noexcept;
      98             :   Error onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept;
      99             : };
     100             : 
     101             : // a64::RACFGBuilder - OnInst
     102             : // ==========================
     103             : 
     104             : // TODO: [ARM] This is just a workaround...
     105           0 : static InstControlFlow getControlFlowType(InstId instId) noexcept {
     106           0 :   switch (BaseInst::extractRealId(instId)) {
     107             :     case Inst::kIdB:
     108             :     case Inst::kIdBr:
     109           0 :       if (BaseInst::extractARMCondCode(instId) == CondCode::kAL)
     110             :         return InstControlFlow::kJump;
     111             :       else
     112           0 :         return InstControlFlow::kBranch;
     113             :     case Inst::kIdBl:
     114             :     case Inst::kIdBlr:
     115             :       return InstControlFlow::kCall;
     116           0 :     case Inst::kIdCbz:
     117             :     case Inst::kIdCbnz:
     118             :     case Inst::kIdTbz:
     119             :     case Inst::kIdTbnz:
     120           0 :       return InstControlFlow::kBranch;
     121           0 :     case Inst::kIdRet:
     122           0 :       return InstControlFlow::kReturn;
     123           0 :     default:
     124           0 :       return InstControlFlow::kRegular;
     125             :   }
     126             : }
     127             : 
     128           0 : Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstBuilder& ib) noexcept {
     129             :   InstRWInfo rwInfo;
     130             : 
     131           0 :   if (Inst::isDefinedId(inst->realId())) {
     132             :     InstId instId = inst->id();
     133             :     uint32_t opCount = inst->opCount();
     134             :     const Operand* opArray = inst->operands();
     135           0 :     ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_arch, inst->baseInst(), opArray, opCount, &rwInfo));
     136             : 
     137             :     const InstDB::InstInfo& instInfo = InstDB::infoById(instId);
     138             :     uint32_t singleRegOps = 0;
     139             : 
     140             :     ib.addInstRWFlags(rwInfo.instFlags());
     141             : 
     142           0 :     if (opCount) {
     143             :       uint32_t consecutiveOffset = 0xFFFFFFFFu;
     144             :       uint32_t consecutiveParent = Globals::kInvalidId;
     145             : 
     146           0 :       for (uint32_t i = 0; i < opCount; i++) {
     147           0 :         const Operand& op = opArray[i];
     148             :         const OpRWInfo& opRwInfo = rwInfo.operand(i);
     149             : 
     150           0 :         if (op.isReg()) {
     151             :           // Register Operand
     152             :           // ----------------
     153             :           const Reg& reg = op.as<Reg>();
     154             : 
     155             :           RATiedFlags flags = raRegRwFlags(opRwInfo.opFlags());
     156             :           uint32_t vIndex = Operand::virtIdToIndex(reg.id());
     157             : 
     158           0 :           if (vIndex < Operand::kVirtIdCount) {
     159             :             RAWorkReg* workReg;
     160           0 :             ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
     161             : 
     162             :             // Use RW instead of Write in case that not the whole register is overwritten. This is important for
     163             :             // liveness as we cannot kill a register that will be used.
     164           0 :             if ((flags & RATiedFlags::kRW) == RATiedFlags::kWrite) {
     165           0 :               if (workReg->regByteMask() & ~(opRwInfo.writeByteMask() | opRwInfo.extendByteMask())) {
     166             :                 // Not write-only operation.
     167             :                 flags = (flags & ~RATiedFlags::kOut) | (RATiedFlags::kRead | RATiedFlags::kUse);
     168             :               }
     169             :             }
     170             : 
     171           0 :             RegGroup group = workReg->group();
     172             : 
     173           0 :             RegMask useRegs = _pass->_availableRegs[group];
     174             :             RegMask outRegs = useRegs;
     175             : 
     176             :             uint32_t useId = BaseReg::kIdBad;
     177             :             uint32_t outId = BaseReg::kIdBad;
     178             : 
     179             :             uint32_t useRewriteMask = 0;
     180             :             uint32_t outRewriteMask = 0;
     181             : 
     182           0 :             if (opRwInfo.consecutiveLeadCount()) {
     183             :               // There must be a single consecutive register lead, otherwise the RW data is invalid.
     184           0 :               if (consecutiveOffset != 0xFFFFFFFFu)
     185             :                 return DebugUtils::errored(kErrorInvalidState);
     186             : 
     187             :               // A consecutive lead register cannot be used as a consecutive +1/+2/+3 register, the registers must be distinct.
     188           0 :               if (RATiedReg::consecutiveDataFromFlags(flags) != 0)
     189             :                 return DebugUtils::errored(kErrorNotConsecutiveRegs);
     190             : 
     191           0 :               flags |= RATiedFlags::kLeadConsecutive | RATiedReg::consecutiveDataToFlags(opRwInfo.consecutiveLeadCount() - 1);
     192             :               consecutiveOffset = 0;
     193             : 
     194           0 :               RegMask filter = raConsecutiveLeadCountToRegMaskFilter[opRwInfo.consecutiveLeadCount()];
     195           0 :               if (Support::test(flags, RATiedFlags::kUse)) {
     196             :                 flags |= RATiedFlags::kUseConsecutive;
     197           0 :                 useRegs &= filter;
     198             :               }
     199             :               else {
     200             :                 flags |= RATiedFlags::kOutConsecutive;
     201           0 :                 outRegs &= filter;
     202             :               }
     203             :             }
     204             : 
     205           0 :             if (Support::test(flags, RATiedFlags::kUse)) {
     206           0 :               useRewriteMask = Support::bitMask(inst->getRewriteIndex(&reg._baseId));
     207           0 :               if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
     208             :                 useId = opRwInfo.physId();
     209             :                 flags |= RATiedFlags::kUseFixed;
     210             :               }
     211           0 :               else if (opRwInfo.hasOpFlag(OpRWFlags::kConsecutive)) {
     212           0 :                 if (consecutiveOffset == 0xFFFFFFFFu)
     213             :                   return DebugUtils::errored(kErrorInvalidState);
     214           0 :                 flags |= RATiedFlags::kUseConsecutive | RATiedReg::consecutiveDataToFlags(++consecutiveOffset);
     215             :               }
     216             :             }
     217             :             else {
     218           0 :               outRewriteMask = Support::bitMask(inst->getRewriteIndex(&reg._baseId));
     219           0 :               if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
     220             :                 outId = opRwInfo.physId();
     221             :                 flags |= RATiedFlags::kOutFixed;
     222             :               }
     223           0 :               else if (opRwInfo.hasOpFlag(OpRWFlags::kConsecutive)) {
     224           0 :                 if (consecutiveOffset == 0xFFFFFFFFu)
     225             :                   return DebugUtils::errored(kErrorInvalidState);
     226           0 :                 flags |= RATiedFlags::kOutConsecutive | RATiedReg::consecutiveDataToFlags(++consecutiveOffset);
     227             :               }
     228             :             }
     229             : 
     230             :             // Special cases regarding element access.
     231           0 :             if (reg.as<Vec>().hasElementIndex()) {
     232             :               // Only the first 0..15 registers can be used if the register uses
     233             :               // element accessor that accesses half-words (h[0..7] elements).
     234           0 :               if (instInfo.hasFlag(InstDB::kInstFlagVH0_15) && reg.as<Vec>().elementType() == Vec::kElementTypeH) {
     235           0 :                 if (Support::test(flags, RATiedFlags::kUse))
     236           0 :                   useId &= 0x0000FFFFu;
     237             :                 else
     238           0 :                   outId &= 0x0000FFFFu;
     239             :               }
     240             :             }
     241             : 
     242           0 :             ASMJIT_PROPAGATE(ib.add(workReg, flags, useRegs, useId, useRewriteMask, outRegs, outId, outRewriteMask, opRwInfo.rmSize(), consecutiveParent));
     243           0 :             if (singleRegOps == i)
     244           0 :               singleRegOps++;
     245             : 
     246           0 :             if (Support::test(flags, RATiedFlags::kLeadConsecutive | RATiedFlags::kUseConsecutive | RATiedFlags::kOutConsecutive))
     247           0 :               consecutiveParent = workReg->workId();
     248             :           }
     249             :         }
     250           0 :         else if (op.isMem()) {
     251             :           // Memory Operand
     252             :           // --------------
     253             :           const Mem& mem = op.as<Mem>();
     254             : 
     255           0 :           if (mem.isRegHome()) {
     256             :             RAWorkReg* workReg;
     257           0 :             ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(mem.baseId()), &workReg));
     258           0 :             _pass->getOrCreateStackSlot(workReg);
     259             :           }
     260           0 :           else if (mem.hasBaseReg()) {
     261             :             uint32_t vIndex = Operand::virtIdToIndex(mem.baseId());
     262           0 :             if (vIndex < Operand::kVirtIdCount) {
     263             :               RAWorkReg* workReg;
     264           0 :               ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
     265             : 
     266             :               RATiedFlags flags = raMemBaseRwFlags(opRwInfo.opFlags());
     267           0 :               RegGroup group = workReg->group();
     268           0 :               RegMask allocable = _pass->_availableRegs[group];
     269             : 
     270             :               // Base registers have never fixed id on ARM.
     271             :               const uint32_t useId = BaseReg::kIdBad;
     272             :               const uint32_t outId = BaseReg::kIdBad;
     273             : 
     274             :               uint32_t useRewriteMask = 0;
     275             :               uint32_t outRewriteMask = 0;
     276             : 
     277           0 :               if (Support::test(flags, RATiedFlags::kUse))
     278           0 :                 useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._baseId));
     279             :               else
     280           0 :                 outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._baseId));
     281             : 
     282           0 :               ASMJIT_PROPAGATE(ib.add(workReg, flags, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
     283             :             }
     284             :           }
     285             : 
     286           0 :           if (mem.hasIndexReg()) {
     287             :             uint32_t vIndex = Operand::virtIdToIndex(mem.indexId());
     288           0 :             if (vIndex < Operand::kVirtIdCount) {
     289             :               RAWorkReg* workReg;
     290           0 :               ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
     291             : 
     292             :               RATiedFlags flags = raMemIndexRwFlags(opRwInfo.opFlags());
     293           0 :               RegGroup group = workReg->group();
     294           0 :               RegMask allocable = _pass->_availableRegs[group];
     295             : 
     296             :               // Index registers have never fixed id on ARM.
     297             :               const uint32_t useId = BaseReg::kIdBad;
     298             :               const uint32_t outId = BaseReg::kIdBad;
     299             : 
     300             :               uint32_t useRewriteMask = 0;
     301             :               uint32_t outRewriteMask = 0;
     302             : 
     303           0 :               if (Support::test(flags, RATiedFlags::kUse))
     304           0 :                 useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
     305             :               else
     306           0 :                 outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
     307             : 
     308           0 :               ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
     309             :             }
     310             :           }
     311             :         }
     312             :       }
     313             :     }
     314             : 
     315           0 :     controlType = getControlFlowType(instId);
     316             :   }
     317             : 
     318             :   return kErrorOk;
     319             : }
     320             : 
     321             : // a64::RACFGBuilder - OnInvoke
     322             : // ============================
     323             : 
     324           0 : Error RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept {
     325             :   const FuncDetail& fd = invokeNode->detail();
     326             :   uint32_t argCount = invokeNode->argCount();
     327             : 
     328             :   cc()->_setCursor(invokeNode->prev());
     329             : 
     330           0 :   for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
     331           0 :     const FuncValuePack& argPack = fd.argPack(argIndex);
     332           0 :     for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
     333           0 :       if (!argPack[valueIndex])
     334             :         break;
     335             : 
     336             :       const FuncValue& arg = argPack[valueIndex];
     337             :       const Operand& op = invokeNode->arg(argIndex, valueIndex);
     338             : 
     339           0 :       if (op.isNone())
     340           0 :         continue;
     341             : 
     342           0 :       if (op.isReg()) {
     343             :         const Reg& reg = op.as<Reg>();
     344             :         RAWorkReg* workReg;
     345           0 :         ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
     346             : 
     347           0 :         if (arg.isReg()) {
     348           0 :           RegGroup regGroup = workReg->group();
     349             :           RegGroup argGroup = Reg::groupOf(arg.regType());
     350             : 
     351           0 :           if (regGroup != argGroup) {
     352             :             // TODO: [ARM] Conversion is not supported.
     353             :             return DebugUtils::errored(kErrorInvalidAssignment);
     354             :           }
     355             :         }
     356             :         else {
     357           0 :           ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg));
     358             :         }
     359             :       }
     360           0 :       else if (op.isImm()) {
     361           0 :         if (arg.isReg()) {
     362           0 :           BaseReg reg;
     363           0 :           ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, op.as<Imm>(), &reg));
     364           0 :           invokeNode->_args[argIndex][valueIndex] = reg;
     365             :         }
     366             :         else {
     367           0 :           ASMJIT_PROPAGATE(moveImmToStackArg(invokeNode, arg, op.as<Imm>()));
     368             :         }
     369             :       }
     370             :     }
     371             :   }
     372             : 
     373             :   cc()->_setCursor(invokeNode);
     374             : 
     375           0 :   if (fd.hasRet()) {
     376           0 :     for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
     377           0 :       const FuncValue& ret = fd.ret(valueIndex);
     378           0 :       if (!ret)
     379             :         break;
     380             : 
     381             :       const Operand& op = invokeNode->ret(valueIndex);
     382           0 :       if (op.isReg()) {
     383             :         const Reg& reg = op.as<Reg>();
     384             :         RAWorkReg* workReg;
     385           0 :         ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
     386             : 
     387           0 :         if (ret.isReg()) {
     388           0 :           RegGroup regGroup = workReg->group();
     389             :           RegGroup retGroup = Reg::groupOf(ret.regType());
     390             : 
     391           0 :           if (regGroup != retGroup) {
     392             :             // TODO: [ARM] Conversion is not supported.
     393             :             return DebugUtils::errored(kErrorInvalidAssignment);
     394             :           }
     395             :         }
     396             :       }
     397             :     }
     398             :   }
     399             : 
     400             :   // This block has function call(s).
     401           0 :   _curBlock->addFlags(RABlockFlags::kHasFuncCalls);
     402           0 :   _pass->func()->frame().addAttributes(FuncAttributes::kHasFuncCalls);
     403           0 :   _pass->func()->frame().updateCallStackSize(fd.argStackSize());
     404             : 
     405           0 :   return kErrorOk;
     406             : }
     407             : 
     408           0 : Error RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept {
     409             :   uint32_t argCount = invokeNode->argCount();
     410             :   const FuncDetail& fd = invokeNode->detail();
     411             : 
     412           0 :   for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
     413           0 :     const FuncValuePack& argPack = fd.argPack(argIndex);
     414           0 :     for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
     415           0 :       if (!argPack[valueIndex])
     416           0 :         continue;
     417             : 
     418             :       const FuncValue& arg = argPack[valueIndex];
     419             :       const Operand& op = invokeNode->arg(argIndex, valueIndex);
     420             : 
     421           0 :       if (op.isNone())
     422           0 :         continue;
     423             : 
     424           0 :       if (op.isReg()) {
     425             :         const Reg& reg = op.as<Reg>();
     426             :         RAWorkReg* workReg;
     427           0 :         ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
     428             : 
     429           0 :         if (arg.isIndirect()) {
     430           0 :           RegGroup regGroup = workReg->group();
     431           0 :           if (regGroup != RegGroup::kGp)
     432             :             return DebugUtils::errored(kErrorInvalidState);
     433           0 :           ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId()));
     434             :         }
     435           0 :         else if (arg.isReg()) {
     436           0 :           RegGroup regGroup = workReg->group();
     437             :           RegGroup argGroup = Reg::groupOf(arg.regType());
     438             : 
     439           0 :           if (regGroup == argGroup) {
     440           0 :             ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId()));
     441             :           }
     442             :         }
     443             :       }
     444             :     }
     445             :   }
     446             : 
     447           0 :   for (uint32_t retIndex = 0; retIndex < Globals::kMaxValuePack; retIndex++) {
     448           0 :     const FuncValue& ret = fd.ret(retIndex);
     449           0 :     if (!ret)
     450             :       break;
     451             : 
     452             :     const Operand& op = invokeNode->ret(retIndex);
     453           0 :     if (op.isReg()) {
     454             :       const Reg& reg = op.as<Reg>();
     455             :       RAWorkReg* workReg;
     456           0 :       ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg));
     457             : 
     458           0 :       if (ret.isReg()) {
     459           0 :         RegGroup regGroup = workReg->group();
     460             :         RegGroup retGroup = Reg::groupOf(ret.regType());
     461             : 
     462           0 :         if (regGroup == retGroup) {
     463           0 :           ASMJIT_PROPAGATE(ib.addCallRet(workReg, ret.regId()));
     464             :         }
     465             :       }
     466             :       else {
     467             :         return DebugUtils::errored(kErrorInvalidAssignment);
     468             :       }
     469             :     }
     470             :   }
     471             : 
     472             :   // Setup clobbered registers.
     473           0 :   ib._clobbered[0] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(0)]) & ~fd.preservedRegs(RegGroup(0));
     474           0 :   ib._clobbered[1] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(1)]) & ~fd.preservedRegs(RegGroup(1));
     475           0 :   ib._clobbered[2] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(2)]) & ~fd.preservedRegs(RegGroup(2));
     476           0 :   ib._clobbered[3] = Support::lsbMask<RegMask>(_pass->_physRegCount[RegGroup(3)]) & ~fd.preservedRegs(RegGroup(3));
     477             : 
     478           0 :   return kErrorOk;
     479             : }
     480             : 
     481             : // a64::RACFGBuilder - MoveImmToRegArg
     482             : // ===================================
     483             : 
     484           0 : Error RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept {
     485             :   DebugUtils::unused(invokeNode);
     486             :   ASMJIT_ASSERT(arg.isReg());
     487             : 
     488             :   Imm imm(imm_);
     489             :   TypeId typeId = TypeId::kVoid;
     490             : 
     491           0 :   switch (arg.typeId()) {
     492           0 :     case TypeId::kInt8  : typeId = TypeId::kUInt64; imm.signExtend8Bits(); break;
     493           0 :     case TypeId::kUInt8 : typeId = TypeId::kUInt64; imm.zeroExtend8Bits(); break;
     494           0 :     case TypeId::kInt16 : typeId = TypeId::kUInt64; imm.signExtend16Bits(); break;
     495           0 :     case TypeId::kUInt16: typeId = TypeId::kUInt64; imm.zeroExtend16Bits(); break;
     496           0 :     case TypeId::kInt32 : typeId = TypeId::kUInt64; imm.signExtend32Bits(); break;
     497           0 :     case TypeId::kUInt32: typeId = TypeId::kUInt64; imm.zeroExtend32Bits(); break;
     498             :     case TypeId::kInt64 : typeId = TypeId::kUInt64; break;
     499             :     case TypeId::kUInt64: typeId = TypeId::kUInt64; break;
     500             : 
     501             :     default:
     502             :       return DebugUtils::errored(kErrorInvalidAssignment);
     503             :   }
     504             : 
     505           0 :   ASMJIT_PROPAGATE(cc()->_newReg(out, typeId, nullptr));
     506             :   cc()->virtRegById(out->id())->setWeight(BaseRAPass::kCallArgWeight);
     507           0 :   return cc()->mov(out->as<Gp>(), imm);
     508             : }
     509             : 
     510             : // a64::RACFGBuilder - MoveImmToStackArg
     511             : // =====================================
     512             : 
     513           0 : Error RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept {
     514           0 :   BaseReg reg;
     515             : 
     516           0 :   ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, imm_, &reg));
     517           0 :   ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg));
     518             : 
     519             :   return kErrorOk;
     520             : }
     521             : 
     522             : // a64::RACFGBuilder - MoveRegToStackArg
     523             : // =====================================
     524             : 
     525           0 : Error RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept {
     526             :   DebugUtils::unused(invokeNode);
     527           0 :   Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset());
     528             : 
     529           0 :   if (reg.isGp())
     530           0 :     return cc()->str(reg.as<Gp>(), stackPtr);
     531             : 
     532           0 :   if (reg.isVec())
     533           0 :     return cc()->str(reg.as<Vec>(), stackPtr);
     534             : 
     535             :   return DebugUtils::errored(kErrorInvalidState);
     536             : }
     537             : 
     538             : // a64::RACFGBuilder - OnReg
     539             : // =========================
     540             : 
     541           0 : Error RACFGBuilder::onBeforeRet(FuncRetNode* funcRet) noexcept {
     542             :   DebugUtils::unused(funcRet);
     543           0 :   return kErrorOk;
     544             : }
     545             : 
     546           0 : Error RACFGBuilder::onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept {
     547           0 :   const FuncDetail& funcDetail = _pass->func()->detail();
     548             :   const Operand* opArray = funcRet->operands();
     549             :   uint32_t opCount = funcRet->opCount();
     550             : 
     551           0 :   for (uint32_t i = 0; i < opCount; i++) {
     552           0 :     const Operand& op = opArray[i];
     553           0 :     if (op.isNone()) continue;
     554             : 
     555             :     const FuncValue& ret = funcDetail.ret(i);
     556           0 :     if (ASMJIT_UNLIKELY(!ret.isReg()))
     557             :       return DebugUtils::errored(kErrorInvalidAssignment);
     558             : 
     559           0 :     if (op.isReg()) {
     560             :       // Register return value.
     561             :       const Reg& reg = op.as<Reg>();
     562             :       uint32_t vIndex = Operand::virtIdToIndex(reg.id());
     563             : 
     564           0 :       if (vIndex < Operand::kVirtIdCount) {
     565             :         RAWorkReg* workReg;
     566           0 :         ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(vIndex, &workReg));
     567             : 
     568           0 :         RegGroup group = workReg->group();
     569           0 :         RegMask allocable = _pass->_availableRegs[group];
     570           0 :         ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, ret.regId(), 0, 0, BaseReg::kIdBad, 0));
     571             :       }
     572             :     }
     573             :     else {
     574             :       return DebugUtils::errored(kErrorInvalidAssignment);
     575             :     }
     576             :   }
     577             : 
     578             :   return kErrorOk;
     579             : }
     580             : 
     581             : // a64::ARMRAPass - Construction & Destruction
     582             : // ===========================================
     583             : 
     584           0 : ARMRAPass::ARMRAPass() noexcept
     585           0 :   : BaseRAPass() { _iEmitHelper = &_emitHelper; }
     586           0 : ARMRAPass::~ARMRAPass() noexcept {}
     587             : 
     588             : // a64::ARMRAPass - OnInit / OnDone
     589             : // ================================
     590             : 
     591           0 : void ARMRAPass::onInit() noexcept {
     592             :   Arch arch = cc()->arch();
     593             : 
     594           0 :   _emitHelper._emitter = _cb;
     595             : 
     596           0 :   _archTraits = &ArchTraits::byArch(arch);
     597             :   _physRegCount.set(RegGroup::kGp, 32);
     598             :   _physRegCount.set(RegGroup::kVec, 32);
     599             :   _physRegCount.set(RegGroup::kExtraVirt2, 0);
     600             :   _physRegCount.set(RegGroup::kExtraVirt3, 0);
     601           0 :   _buildPhysIndex();
     602             : 
     603           0 :   _availableRegCount = _physRegCount;
     604           0 :   _availableRegs[RegGroup::kGp] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kGp));
     605           0 :   _availableRegs[RegGroup::kVec] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kVec));
     606             :   _availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kExtraVirt2));
     607           0 :   _availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kExtraVirt3));
     608             : 
     609           0 :   _scratchRegIndexes[0] = uint8_t(27);
     610           0 :   _scratchRegIndexes[1] = uint8_t(28);
     611             : 
     612             :   // The architecture specific setup makes implicitly all registers available. So
     613             :   // make unavailable all registers that are special and cannot be used in general.
     614           0 :   bool hasFP = _func->frame().hasPreservedFP();
     615             : 
     616           0 :   if (hasFP)
     617             :     makeUnavailable(RegGroup::kGp, Gp::kIdFp);
     618             : 
     619             :   makeUnavailable(RegGroup::kGp, Gp::kIdSp);
     620             :   makeUnavailable(RegGroup::kGp, Gp::kIdOs); // OS-specific use, usually TLS.
     621             : 
     622           0 :   _sp = sp;
     623           0 :   _fp = x29;
     624           0 : }
     625             : 
     626           0 : void ARMRAPass::onDone() noexcept {}
     627             : 
     628             : // a64::ARMRAPass - BuildCFG
     629             : // =========================
     630             : 
     631           0 : Error ARMRAPass::buildCFG() noexcept {
     632           0 :   return RACFGBuilder(this).run();
     633             : }
     634             : 
     635             : // a64::ARMRAPass - Rewrite
     636             : // ========================
     637             : 
     638           0 : ASMJIT_FAVOR_SPEED Error ARMRAPass::_rewrite(BaseNode* first, BaseNode* stop) noexcept {
     639             :   uint32_t virtCount = cc()->_vRegArray.size();
     640             : 
     641             :   BaseNode* node = first;
     642           0 :   while (node != stop) {
     643             :     BaseNode* next = node->next();
     644           0 :     if (node->isInst()) {
     645             :       InstNode* inst = node->as<InstNode>();
     646             :       RAInst* raInst = node->passData<RAInst>();
     647             : 
     648             :       Operand* operands = inst->operands();
     649             :       uint32_t opCount = inst->opCount();
     650             : 
     651             :       uint32_t i;
     652             : 
     653             :       // Rewrite virtual registers into physical registers.
     654           0 :       if (raInst) {
     655             :         // If the instruction contains pass data (raInst) then it was a subject
     656             :         // for register allocation and must be rewritten to use physical regs.
     657             :         RATiedReg* tiedRegs = raInst->tiedRegs();
     658             :         uint32_t tiedCount = raInst->tiedCount();
     659             : 
     660           0 :         for (i = 0; i < tiedCount; i++) {
     661           0 :           RATiedReg* tiedReg = &tiedRegs[i];
     662             : 
     663             :           Support::BitWordIterator<uint32_t> useIt(tiedReg->useRewriteMask());
     664             :           uint32_t useId = tiedReg->useId();
     665           0 :           while (useIt.hasNext())
     666             :             inst->rewriteIdAtIndex(useIt.next(), useId);
     667             : 
     668             :           Support::BitWordIterator<uint32_t> outIt(tiedReg->outRewriteMask());
     669             :           uint32_t outId = tiedReg->outId();
     670           0 :           while (outIt.hasNext())
     671             :             inst->rewriteIdAtIndex(outIt.next(), outId);
     672             :         }
     673             : 
     674             :         // This data is allocated by Zone passed to `runOnFunction()`, which
     675             :         // will be reset after the RA pass finishes. So reset this data to
     676             :         // prevent having a dead pointer after the RA pass is complete.
     677             :         node->resetPassData();
     678             : 
     679           0 :         if (ASMJIT_UNLIKELY(node->type() != NodeType::kInst)) {
     680             :           // FuncRet terminates the flow, it must either be removed if the exit
     681             :           // label is next to it (optimization) or patched to an architecture
     682             :           // dependent jump instruction that jumps to the function's exit before
     683             :           // the epilog.
     684           0 :           if (node->type() == NodeType::kFuncRet) {
     685             :             RABlock* block = raInst->block();
     686           0 :             if (!isNextTo(node, _func->exitNode())) {
     687             :               cc()->_setCursor(node->prev());
     688           0 :               ASMJIT_PROPAGATE(emitJump(_func->exitNode()->label()));
     689             :             }
     690             : 
     691             :             BaseNode* prev = node->prev();
     692           0 :             cc()->removeNode(node);
     693             :             block->setLast(prev);
     694             :           }
     695             :         }
     696             :       }
     697             : 
     698             :       // Rewrite stack slot addresses.
     699           0 :       for (i = 0; i < opCount; i++) {
     700           0 :         Operand& op = operands[i];
     701           0 :         if (op.isMem()) {
     702             :           BaseMem& mem = op.as<BaseMem>();
     703           0 :           if (mem.isRegHome()) {
     704             :             uint32_t virtIndex = Operand::virtIdToIndex(mem.baseId());
     705           0 :             if (ASMJIT_UNLIKELY(virtIndex >= virtCount))
     706             :               return DebugUtils::errored(kErrorInvalidVirtId);
     707             : 
     708             :             VirtReg* virtReg = cc()->virtRegByIndex(virtIndex);
     709             :             RAWorkReg* workReg = virtReg->workReg();
     710             :             ASMJIT_ASSERT(workReg != nullptr);
     711             : 
     712             :             RAStackSlot* slot = workReg->stackSlot();
     713             :             int32_t offset = slot->offset();
     714             : 
     715             :             mem._setBase(_sp.type(), slot->baseRegId());
     716             :             mem.clearRegHome();
     717             :             mem.addOffsetLo32(offset);
     718             :           }
     719             :         }
     720             :       }
     721             : 
     722             :       // Rewrite `loadAddressOf()` construct.
     723           0 :       if (inst->realId() == Inst::kIdAdr && inst->opCount() == 2 && inst->op(1).isMem()) {
     724             :         BaseMem mem = inst->op(1).as<BaseMem>();
     725             :         int64_t offset = mem.offset();
     726             : 
     727           0 :         if (!mem.hasBaseOrIndex()) {
     728             :           inst->setId(Inst::kIdMov);
     729           0 :           inst->setOp(1, Imm(offset));
     730             :         }
     731             :         else {
     732           0 :           if (mem.hasIndex())
     733           0 :             return DebugUtils::errored(kErrorInvalidAddressIndex);
     734             : 
     735             :           GpX dst(inst->op(0).as<Gp>().id());
     736             :           GpX base(mem.baseId());
     737             : 
     738           0 :           InstId arithInstId = offset < 0 ? Inst::kIdSub : Inst::kIdAdd;
     739           0 :           uint64_t absOffset = offset < 0 ? Support::neg(uint64_t(offset)) : uint64_t(offset);
     740             : 
     741             :           inst->setId(arithInstId);
     742             :           inst->setOpCount(3);
     743             :           inst->setOp(1, base);
     744           0 :           inst->setOp(2, Imm(absOffset));
     745             : 
     746             :           // Use two operations if the offset cannot be encoded with ADD/SUB.
     747           0 :           if (absOffset > 0xFFFu && (absOffset & ~uint64_t(0xFFF000u)) != 0) {
     748           0 :             if (absOffset <= 0xFFFFFFu) {
     749             :               cc()->_setCursor(inst->prev());
     750           0 :               ASMJIT_PROPAGATE(cc()->emit(arithInstId, dst, base, Imm(absOffset & 0xFFFu)));
     751             : 
     752             :               inst->setOp(1, dst);
     753           0 :               inst->setOp(2, Imm(absOffset & 0xFFF000u));
     754             :             }
     755             :             else {
     756             :               cc()->_setCursor(inst->prev());
     757           0 :               ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, inst->op(0), Imm(absOffset)));
     758             : 
     759             :               inst->setOp(1, base);
     760             :               inst->setOp(2, dst);
     761             :             }
     762             :           }
     763             :         }
     764             :       }
     765             :     }
     766             : 
     767             :     node = next;
     768             :   }
     769             : 
     770             :   return kErrorOk;
     771             : }
     772             : 
     773             : // a64::ARMRAPass - Prolog & Epilog
     774             : // ================================
     775             : 
     776           0 : Error ARMRAPass::updateStackFrame() noexcept {
     777           0 :   if (_func->frame().hasFuncCalls())
     778             :     _func->frame().addDirtyRegs(RegGroup::kGp, Support::bitMask(Gp::kIdLr));
     779             : 
     780           0 :   return BaseRAPass::updateStackFrame();
     781             : }
     782             : 
     783             : // a64::ARMRAPass - OnEmit
     784             : // =======================
     785             : 
     786           0 : Error ARMRAPass::emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
     787             :   RAWorkReg* wReg = workRegById(workId);
     788             :   BaseReg dst(wReg->signature(), dstPhysId);
     789             :   BaseReg src(wReg->signature(), srcPhysId);
     790             : 
     791             :   const char* comment = nullptr;
     792             : 
     793             : #ifndef ASMJIT_NO_LOGGING
     794           0 :   if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
     795           0 :     _tmpString.assignFormat("<MOVE> %s", workRegById(workId)->name());
     796             :     comment = _tmpString.data();
     797             :   }
     798             : #endif
     799             : 
     800           0 :   return _emitHelper.emitRegMove(dst, src, wReg->typeId(), comment);
     801             : }
     802             : 
     803           0 : Error ARMRAPass::emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
     804             :   DebugUtils::unused(aWorkId, aPhysId, bWorkId, bPhysId);
     805           0 :   return DebugUtils::errored(kErrorInvalidState);
     806             : }
     807             : 
     808           0 : Error ARMRAPass::emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept {
     809             :   RAWorkReg* wReg = workRegById(workId);
     810             :   BaseReg dstReg(wReg->signature(), dstPhysId);
     811           0 :   BaseMem srcMem(workRegAsMem(wReg));
     812             : 
     813             :   const char* comment = nullptr;
     814             : 
     815             : #ifndef ASMJIT_NO_LOGGING
     816           0 :   if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
     817           0 :     _tmpString.assignFormat("<LOAD> %s", workRegById(workId)->name());
     818             :     comment = _tmpString.data();
     819             :   }
     820             : #endif
     821             : 
     822           0 :   return _emitHelper.emitRegMove(dstReg, srcMem, wReg->typeId(), comment);
     823             : }
     824             : 
     825           0 : Error ARMRAPass::emitSave(uint32_t workId, uint32_t srcPhysId) noexcept {
     826             :   RAWorkReg* wReg = workRegById(workId);
     827           0 :   BaseMem dstMem(workRegAsMem(wReg));
     828             :   BaseReg srcReg(wReg->signature(), srcPhysId);
     829             : 
     830             :   const char* comment = nullptr;
     831             : 
     832             : #ifndef ASMJIT_NO_LOGGING
     833           0 :   if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
     834           0 :     _tmpString.assignFormat("<SAVE> %s", workRegById(workId)->name());
     835             :     comment = _tmpString.data();
     836             :   }
     837             : #endif
     838             : 
     839           0 :   return _emitHelper.emitRegMove(dstMem, srcReg, wReg->typeId(), comment);
     840             : }
     841             : 
     842           0 : Error ARMRAPass::emitJump(const Label& label) noexcept {
     843           0 :   return cc()->b(label);
     844             : }
     845             : 
     846           0 : Error ARMRAPass::emitPreCall(InvokeNode* invokeNode) noexcept {
     847             :   DebugUtils::unused(invokeNode);
     848           0 :   return kErrorOk;
     849             : }
     850             : 
     851             : ASMJIT_END_SUB_NAMESPACE
     852             : 
     853             : #endif // !ASMJIT_NO_AARCH64 && !ASMJIT_NO_COMPILER
     854             : 
     855             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16