VirtualBox

Changeset 101640 in vbox for trunk/src


Ignore:
Timestamp:
Oct 28, 2023 1:01:28 AM (16 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
159729
Message:

VMM/IEM: Emit native code for BltIn_CheckIrq. bugref:10371

Location:
trunk/src/VBox/VMM
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp

    r101626 r101640  
    15881588    pReNative->cCondDepth                  = 0;
    15891589    pReNative->uCondSeqNo                  = 0;
     1590    pReNative->uCheckIrqSeqNo              = 0;
    15901591
    15911592    pReNative->Core.bmHstRegs              = IEMNATIVE_REG_FIXED_MASK
     
    19941995 * Debug Info: Record info about a threaded call.
    19951996 */
    1996 static bool iemNativeDbgInfoAddThreadedCall(PIEMRECOMPILERSTATE pReNative, IEMTHREADEDFUNCS enmCall) RT_NOEXCEPT
     1997static bool iemNativeDbgInfoAddThreadedCall(PIEMRECOMPILERSTATE pReNative, IEMTHREADEDFUNCS enmCall, bool fRecompiled) RT_NOEXCEPT
    19971998{
    19981999    PIEMTBDBGENTRY const pEntry = iemNativeDbgInfoAddNewEntry(pReNative, pReNative->pDbgInfo);
    19992000    AssertReturn(pEntry, false);
    20002001
    2001     pEntry->ThreadedCall.uType   = kIemTbDbgEntryType_ThreadedCall;
    2002     pEntry->ThreadedCall.uUnused = 0;
    2003     pEntry->ThreadedCall.enmCall = (uint16_t)enmCall;
     2002    pEntry->ThreadedCall.uType       = kIemTbDbgEntryType_ThreadedCall;
     2003    pEntry->ThreadedCall.fRecompiled = fRecompiled;
     2004    pEntry->ThreadedCall.uUnused     = 0;
     2005    pEntry->ThreadedCall.enmCall     = (uint16_t)enmCall;
    20042006
    20052007    return true;
     
    25262528
    25272529
    2528 
    2529 /**
    2530  * Intended use statement for iemNativeRegAllocTmpForGuestReg().
    2531  */
    2532 typedef enum IEMNATIVEGSTREGUSE
    2533 {
    2534     /** The usage is read-only, the register holding the guest register
    2535      * shadow copy will not be modified by the caller. */
    2536     kIemNativeGstRegUse_ReadOnly = 0,
    2537     /** The caller will update the guest register (think: PC += cbInstr).
    2538      * The guest shadow copy will follow the returned register. */
    2539     kIemNativeGstRegUse_ForUpdate,
    2540     /** The caller will use the guest register value as input in a calculation
    2541      * and the host register will be modified.
    2542      * This means that the returned host register will not be marked as a shadow
    2543      * copy of the guest register. */
    2544     kIemNativeGstRegUse_Calculation
    2545 } IEMNATIVEGSTREGUSE;
    2546 
    2547 /**
    2548  * Allocates a temporary host general purpose register for updating a guest
     2530/**
     2531 * Allocates a temporary host general purpose register for keeping a guest
    25492532 * register value.
    25502533 *
     
    25612544 * @param   enmGstReg       The guest register that will is to be updated.
    25622545 * @param   enmIntendedUse  How the caller will be using the host register.
     2546 * @sa      iemNativeRegAllocTmpForGuestRegIfAlreadyPresent
    25632547 */
    25642548DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuestReg(PIEMRECOMPILERSTATE pReNative, uint32_t *poff,
     
    26782662
    26792663    return idxRegNew;
     2664}
     2665
     2666
     2667/**
     2668 * Allocates a temporary host general purpose register that already holds the
     2669 * given guest register value.
     2670 *
     2671 * The use case for this function is places where the shadowing state cannot be
     2672 * modified due to branching and such.  This will fail if the we don't have a
     2673 * current shadow copy handy or if it's incompatible.  The only code that will
     2674 * be emitted here is value checking code in strict builds.
     2675 *
     2676 * The intended use can only be readonly!
     2677 *
     2678 * @returns The host register number, UINT8_MAX on failure.
     2679 * @param   pReNative       The native recompile state.
     2680 * @param   poff            Pointer to the instruction buffer offset.
     2681 *                          Will be updated in strict builds if a register is
     2682 *                          found.
     2683 * @param   enmGstReg       The guest register that will is to be updated.
     2684 * @sa iemNativeRegAllocTmpForGuestReg
     2685 */
     2686DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuestRegIfAlreadyPresent(PIEMRECOMPILERSTATE pReNative, uint32_t *poff,
     2687                                                                    IEMNATIVEGSTREG enmGstReg) RT_NOEXCEPT
     2688{
     2689    Assert(enmGstReg < kIemNativeGstReg_End && g_aGstShadowInfo[enmGstReg].cb != 0);
     2690
     2691    /*
     2692     * First check if the guest register value is already in a host register.
     2693     */
     2694    if (pReNative->Core.bmGstRegShadows & RT_BIT_64(enmGstReg))
     2695    {
     2696        uint8_t idxReg = pReNative->Core.aidxGstRegShadows[enmGstReg];
     2697        Assert(idxReg < RT_ELEMENTS(pReNative->Core.aHstRegs));
     2698        Assert(pReNative->Core.aHstRegs[idxReg].fGstRegShadows & RT_BIT_64(enmGstReg));
     2699        Assert(pReNative->Core.bmHstRegsWithGstShadow & RT_BIT_32(idxReg));
     2700
     2701        if (!(pReNative->Core.bmHstRegs & RT_BIT_32(idxReg)))
     2702        {
     2703            /*
     2704             * We only do readonly use here, so easy compared to the other
     2705             * variant of this code.
     2706             */
     2707            pReNative->Core.bmHstRegs |= RT_BIT_32(idxReg);
     2708            pReNative->Core.aHstRegs[idxReg].enmWhat = kIemNativeWhat_Tmp;
     2709            pReNative->Core.aHstRegs[idxReg].idxVar  = UINT8_MAX;
     2710            Log12(("iemNativeRegAllocTmpForGuestRegIfAlreadyPresent: Reusing %s for guest %s readonly\n",
     2711                   g_apszIemNativeHstRegNames[idxReg], g_aGstShadowInfo[enmGstReg].pszName));
     2712
     2713#ifdef VBOX_STRICT
     2714            /* Strict builds: Check that the value is correct. */
     2715            uint32_t off = *poff;
     2716            *poff = off = iemNativeEmitGuestRegValueCheck(pReNative, off, idxReg, enmGstReg);
     2717            AssertReturn(off != UINT32_MAX, UINT8_MAX);
     2718#else
     2719            RT_NOREF(poff);
     2720#endif
     2721            return idxReg;
     2722        }
     2723    }
     2724
     2725    return UINT8_MAX;
    26802726}
    26812727
     
    48834929
    48844930/**
     4931 * Built-in function that checks for pending interrupts that can be delivered or
     4932 * forced action flags.
     4933 *
     4934 * This triggers after the completion of an instruction, so EIP is already at
     4935 * the next instruction.  If an IRQ or important FF is pending, this will return
     4936 * a non-zero status that stops TB execution.
     4937 */
     4938static IEM_DECL_IEMNATIVERECOMPFUNC_DEF(iemNativeRecompFunc_BltIn_CheckIrq)
     4939{
     4940    RT_NOREF(pCallEntry);
     4941//pReNative->pInstrBuf[off++] = 0xcc;
     4942
     4943    /* It's too convenient to use iemNativeEmitTestBitInGprAndJmpToLabelIfNotSet below
     4944       and I'm too lazy to create a 'Fixed' version of that one. */
     4945    uint32_t const idxLabelVmCheck = iemNativeLabelCreate(pReNative, kIemNativeLabelType_CheckIrq,
     4946                                                          UINT32_MAX, pReNative->uCheckIrqSeqNo++);
     4947    AssertReturn(idxLabelVmCheck != UINT32_MAX, UINT32_MAX);
     4948
     4949    uint32_t const idxLabelReturnBreak = iemNativeLabelCreate(pReNative, kIemNativeLabelType_ReturnBreak);
     4950    AssertReturn(idxLabelReturnBreak != UINT32_MAX, UINT32_MAX);
     4951
     4952    /* Again, we need to load the extended EFLAGS before we actually need them
     4953       in case we jump.  We couldn't use iemNativeRegAllocTmpForGuestReg if we
     4954       loaded them inside the check, as the shadow state would not be correct
     4955       when the code branches before the load.  Ditto PC. */
     4956    uint8_t const idxEflReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_EFlags,
     4957                                                              kIemNativeGstRegUse_ReadOnly);
     4958    AssertReturn(idxEflReg != UINT8_MAX, UINT32_MAX);
     4959
     4960    uint8_t const idxPcReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_Pc,
     4961                                                             kIemNativeGstRegUse_ReadOnly);
     4962    AssertReturn(idxPcReg != UINT8_MAX, UINT32_MAX);
     4963
     4964    uint8_t idxTmpReg = iemNativeRegAllocTmp(pReNative, &off);
     4965    AssertReturn(idxTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX);
     4966
     4967    /*
     4968     * Start by checking the local forced actions of the EMT we're on for IRQs
     4969     * and other FFs that needs servicing.
     4970     */
     4971    /** @todo this isn't even close to the NMI and interrupt conditions in EM! */
     4972    /* Load FFs in to idxTmpReg and AND with all relevant flags. */
     4973    off = iemNativeEmitLoadGprFromVCpuU64(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, fLocalForcedActions));
     4974    off = iemNativeEmitAndGprByImm(pReNative, off, idxTmpReg,
     4975                                   VMCPU_FF_ALL_MASK & ~(  VMCPU_FF_PGM_SYNC_CR3
     4976                                                         | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
     4977                                                         | VMCPU_FF_TLB_FLUSH
     4978                                                         | VMCPU_FF_UNHALT ),
     4979                                   true /*fSetFlags*/);
     4980    /* If we end up with ZERO in idxTmpReg there is nothing to do.*/
     4981    uint32_t const offFixupJumpToVmCheck1 = off;
     4982    off = iemNativeEmitJzToFixed(pReNative, off, 0);
     4983
     4984    /* Some relevant FFs are set, but if's only APIC or/and PIC being set,
     4985       these may be supressed by EFLAGS.IF or CPUMIsInInterruptShadow. */
     4986    off = iemNativeEmitAndGprByImm(pReNative, off, idxTmpReg,
     4987                                   ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC), true /*fSetFlags*/);
     4988    /* Return VINF_IEM_REEXEC_BREAK if other FFs are set. */
     4989    off = iemNativeEmitJnzToLabel(pReNative, off, idxLabelReturnBreak);
     4990
     4991    /* So, it's only interrupt releated FFs and we need to see if IRQs are being
     4992       suppressed by the CPU or not. */
     4993    off = iemNativeEmitTestBitInGprAndJmpToLabelIfNotSet(pReNative, off, idxEflReg, X86_EFL_IF_BIT, idxLabelVmCheck);
     4994    off = iemNativeEmitTestAnyBitsInGprAndJmpToLabelIfNoneSet(pReNative, off, idxEflReg, CPUMCTX_INHIBIT_SHADOW,
     4995                                                              idxLabelReturnBreak);
     4996
     4997    /* We've got shadow flags set, so we must check that the PC they are valid
     4998       for matches our current PC value. */
     4999    /** @todo AMD64 can do this more efficiently w/o loading uRipInhibitInt into
     5000     *        a register. */
     5001    off = iemNativeEmitLoadGprFromVCpuU64(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, cpum.GstCtx.uRipInhibitInt));
     5002    off = iemNativeEmitTestIfGprNotEqualGprAndJmpToLabel(pReNative, off, idxTmpReg, idxPcReg, idxLabelReturnBreak);
     5003
     5004    /*
     5005     * Now check the force flags of the VM.
     5006     */
     5007    iemNativeLabelDefine(pReNative, idxLabelVmCheck, off);
     5008    iemNativeFixupFixedJump(pReNative, offFixupJumpToVmCheck1, off);
     5009    off = iemNativeEmitLoadGprFromVCpuU64(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, CTX_SUFF(pVM))); /* idxTmpReg = pVM */
     5010    off = iemNativeEmitLoadGpr32ByGpr(pReNative, off, idxTmpReg, idxTmpReg, RT_UOFFSETOF(VMCC, fGlobalForcedActions));
     5011    off = iemNativeEmitAndGpr32ByImm(pReNative, off, idxTmpReg, VM_FF_ALL_MASK, true /*fSetFlags*/);
     5012    off = iemNativeEmitJnzToLabel(pReNative, off, idxLabelReturnBreak);
     5013
     5014    /** @todo STAM_REL_COUNTER_INC(&pVCpu->iem.s.StatCheckIrqBreaks); */
     5015
     5016    /*
     5017     * We're good, no IRQs or FFs pending.
     5018     */
     5019    iemNativeRegFreeTmp(pReNative, idxTmpReg);
     5020    iemNativeRegFreeTmp(pReNative, idxEflReg);
     5021    iemNativeRegFreeTmp(pReNative, idxPcReg);
     5022
     5023    return off;
     5024}
     5025
     5026
     5027/**
    48855028 * Built-in function checks if IEMCPU::fExec has the expected value.
    48865029 */
     
    48885031{
    48895032    uint32_t const fExpectedExec = (uint32_t)pCallEntry->auParams[0];
    4890 
    48915033    uint8_t idxTmpReg = iemNativeRegAllocTmp(pReNative, &off);
     5034
    48925035    AssertReturn(idxTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX);
    48935036    off = iemNativeEmitLoadGprFromVCpuU32(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, iem.s.fExec));
     
    51675310                        case kIemTbDbgEntryType_ThreadedCall:
    51685311                            pHlp->pfnPrintf(pHlp,
    5169                                             "  Call #%u to %s (%u args)\n",
     5312                                            "  Call #%u to %s (%u args)%s\n",
    51705313                                            idxThreadedCall,
    51715314                                            g_apszIemThreadedFunctions[pDbgInfo->aEntries[iDbgEntry].ThreadedCall.enmCall],
    5172                                             g_acIemThreadedFunctionUsedArgs[pDbgInfo->aEntries[iDbgEntry].ThreadedCall.enmCall]);
     5315                                            g_acIemThreadedFunctionUsedArgs[pDbgInfo->aEntries[iDbgEntry].ThreadedCall.enmCall],
     5316                                            pDbgInfo->aEntries[iDbgEntry].ThreadedCall.fRecompiled ? " - recompiled" : "");
    51735317                            idxThreadedCall++;
    51745318                            continue;
     
    52045348                                    pszName = "ReturnBreak";
    52055349                                    break;
     5350                                case kIemNativeLabelType_NonZeroRetOrPassUp:
     5351                                    pszName = "NonZeroRetOrPassUp";
     5352                                    break;
     5353                                case kIemNativeLabelType_RaiseGp0:
     5354                                    pszName = "RaiseGp0";
     5355                                    break;
    52065356                                case kIemNativeLabelType_If:
    52075357                                    pszName = "If";
     
    52175367                                    fNumbered = true;
    52185368                                    break;
    5219                                 case kIemNativeLabelType_NonZeroRetOrPassUp:
    5220                                     pszName = "NonZeroRetOrPassUp";
    5221                                     break;
    5222                                 case kIemNativeLabelType_RaiseGp0:
    5223                                     pszName = "RaiseGp0";
     5369                                case kIemNativeLabelType_CheckIrq:
     5370                                    pszName = "CheckIrq_CheckVM";
     5371                                    fNumbered = true;
    52245372                                    break;
    52255373                                case kIemNativeLabelType_Invalid:
     
    52595407                    uint32_t const uInfo = *(uint32_t const *)&Dis.Instr.ab[3];
    52605408                    if (RT_HIWORD(uInfo) < kIemThreadedFunc_End)
    5261                         pHlp->pfnPrintf(pHlp, "    %p: nop ; marker: call #%u to %s (%u args)\n",
    5262                                         &paNative[offNative], RT_LOWORD(uInfo), g_apszIemThreadedFunctions[RT_HIWORD(uInfo)],
    5263                                         g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)]);
     5409                        pHlp->pfnPrintf(pHlp, "    %p: nop ; marker: call #%u to %s (%u args)%s\n",
     5410                                        &paNative[offNative], uInfo & 0x7fff, g_apszIemThreadedFunctions[RT_HIWORD(uInfo)],
     5411                                        g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)],
     5412                                        uInfo & 0x8000 ? " - recompiled" : "");
    52645413                    else
    52655414                        pHlp->pfnPrintf(pHlp, "    %p: nop ; unknown marker: %#x (%d)\n", &paNative[offNative], uInfo, uInfo);
     
    53465495                    uint32_t const uInfo = *(uint32_t const *)&Dis.Instr.ab[3];
    53475496                    if (RT_HIWORD(uInfo) < kIemThreadedFunc_End)
    5348                         pHlp->pfnPrintf(pHlp, "\n    %p: nop ; marker: call #%u to %s (%u args)\n",
    5349                                         &paNative[offNative], RT_LOWORD(uInfo), g_apszIemThreadedFunctions[RT_HIWORD(uInfo)],
    5350                                         g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)]);
     5497                        pHlp->pfnPrintf(pHlp, "\n    %p: nop ; marker: call #%u to %s (%u args)%s\n",
     5498                                        &paNative[offNative], uInfo & 0x7fff, g_apszIemThreadedFunctions[RT_HIWORD(uInfo)],
     5499                                        g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)],
     5500                                        uInfo & 0x8000 ? " - recompiled" : "");
    53515501                    else
    53525502                        pHlp->pfnPrintf(pHlp, "    %p: nop ; unknown marker: %#x (%d)\n", &paNative[offNative], uInfo, uInfo);
     
    54265576    while (cCallsLeft-- > 0)
    54275577    {
     5578        PFNIEMNATIVERECOMPFUNC const pfnRecom = g_apfnIemNativeRecompileFunctions[pCallEntry->enmFunction];
     5579
    54285580        /*
    54295581         * Debug info and assembly markup.
     
    54415593            iGstInstr = pCallEntry->idxInstr;
    54425594        }
    5443         iemNativeDbgInfoAddThreadedCall(pReNative, (IEMTHREADEDFUNCS)pCallEntry->enmFunction);
     5595        iemNativeDbgInfoAddThreadedCall(pReNative, (IEMTHREADEDFUNCS)pCallEntry->enmFunction, pfnRecom != NULL);
    54445596#endif
    54455597
    54465598#ifdef VBOX_STRICT
    5447         off = iemNativeEmitMarker(pReNative, off, RT_MAKE_U32(pTb->Thrd.cCalls - cCallsLeft - 1, pCallEntry->enmFunction));
     5599        off = iemNativeEmitMarker(pReNative, off,
     5600                                  RT_MAKE_U32((pTb->Thrd.cCalls - cCallsLeft - 1) | (pfnRecom ? 0x8000 : 0),
     5601                                              pCallEntry->enmFunction));
    54485602        AssertReturn(off != UINT32_MAX, pTb);
    54495603#endif
     5604
    54505605        /*
    54515606         * Actual work.
    54525607         */
    5453         PFNIEMNATIVERECOMPFUNC const pfnRecom = g_apfnIemNativeRecompileFunctions[pCallEntry->enmFunction];
    54545608        if (pfnRecom) /** @todo stats on this.   */
    54555609        {
  • trunk/src/VBox/VMM/VMMAll/IEMAllThrdFuncsBltIn.cpp

    r101182 r101640  
    128128    return VINF_IEM_REEXEC_BREAK;
    129129}
    130 
    131130
    132131
  • trunk/src/VBox/VMM/VMMAll/IEMAllThrdPython.py

    r101626 r101640  
    18771877    katBltIns = (
    18781878        ( 'DeferToCImpl0',                                      2, True  ),
    1879         ( 'CheckIrq',                                           0, False ),
     1879        ( 'CheckIrq',                                           0, True ),
    18801880        ( 'CheckMode',                                          1, True  ),
    18811881        ( 'CheckHwInstrBps',                                    0, False ),
  • trunk/src/VBox/VMM/include/IEMInternal.h

    r101547 r101640  
    929929    {
    930930        /* kIemTbDbgEntryType_ThreadedCall. */
    931         uint32_t    uType      : 4;
    932         uint32_t    uUnused    : 12;
     931        uint32_t    uType       : 4;
     932        /** Set if the call was recompiled to native code, clear if just calling
     933         *  threaded function. */
     934        uint32_t    fRecompiled : 1;
     935        uint32_t    uUnused     : 11;
    933936        /** The threaded call number (IEMTHREADEDFUNCS). */
    934         uint32_t    enmCall    : 16;
     937        uint32_t    enmCall     : 16;
    935938    } ThreadedCall;
    936939
  • trunk/src/VBox/VMM/include/IEMN8veRecompiler.h

    r101626 r101640  
    263263{
    264264    kIemNativeLabelType_Invalid = 0,
     265    /* Labels w/o data, only once instance per TB: */
    265266    kIemNativeLabelType_Return,
    266267    kIemNativeLabelType_ReturnBreak,
     268    kIemNativeLabelType_NonZeroRetOrPassUp,
     269    kIemNativeLabelType_RaiseGp0,
     270    /* Labels with data, potentially multiple instances per TB: */
    267271    kIemNativeLabelType_If,
    268272    kIemNativeLabelType_Else,
    269273    kIemNativeLabelType_Endif,
    270     kIemNativeLabelType_NonZeroRetOrPassUp,
    271     kIemNativeLabelType_RaiseGp0,
     274    kIemNativeLabelType_CheckIrq,
    272275    kIemNativeLabelType_End
    273276} IEMNATIVELABELTYPE;
     
    338341    kIemNativeGstReg_End
    339342} IEMNATIVEGSTREG;
     343
     344/**
     345 * Intended use statement for iemNativeRegAllocTmpForGuestReg().
     346 */
     347typedef enum IEMNATIVEGSTREGUSE
     348{
     349    /** The usage is read-only, the register holding the guest register
     350     * shadow copy will not be modified by the caller. */
     351    kIemNativeGstRegUse_ReadOnly = 0,
     352    /** The caller will update the guest register (think: PC += cbInstr).
     353     * The guest shadow copy will follow the returned register. */
     354    kIemNativeGstRegUse_ForUpdate,
     355    /** The caller will use the guest register value as input in a calculation
     356     * and the host register will be modified.
     357     * This means that the returned host register will not be marked as a shadow
     358     * copy of the guest register. */
     359    kIemNativeGstRegUse_Calculation
     360} IEMNATIVEGSTREGUSE;
    340361
    341362/**
     
    591612    /** Condition sequence number (for generating unique labels). */
    592613    uint16_t                    uCondSeqNo;
    593     uint32_t                    uPadding3;
     614    /** Check IRQ seqeunce number (for generating unique lables). */
     615    uint16_t                    uCheckIrqSeqNo;
     616    uint16_t                    uPadding3;
    594617
    595618    /** Core state requiring care with branches. */
     
    624647#define IEM_DECL_IEMNATIVERECOMPFUNC_PROTO(a_Name) FNIEMNATIVERECOMPFUNC a_Name
    625648
    626 
    627649DECLHIDDEN(uint32_t)        iemNativeLabelCreate(PIEMRECOMPILERSTATE pReNative, IEMNATIVELABELTYPE enmType,
    628650                                                 uint32_t offWhere = UINT32_MAX, uint16_t uData = 0) RT_NOEXCEPT;
     
    637659DECLHIDDEN(uint8_t)         iemNativeRegAllocTmpImm(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, uint64_t uImm,
    638660                                                    bool fPreferVolatile = true) RT_NOEXCEPT;
    639 DECLHIDDEN(uint8_t)         iemNativeRegAllocTmpForGuest(PIEMRECOMPILERSTATE pReNative, uint32_t *poff,
    640                                                          IEMNATIVEGSTREG enmGstReg) RT_NOEXCEPT;
     661DECLHIDDEN(uint8_t)         iemNativeRegAllocTmpForGuestReg(PIEMRECOMPILERSTATE pReNative, uint32_t *poff,
     662                                                            IEMNATIVEGSTREG enmGstReg,
     663                                                            IEMNATIVEGSTREGUSE enmIntendedUse) RT_NOEXCEPT;
     664DECLHIDDEN(uint8_t)         iemNativeRegAllocTmpForGuestRegIfAlreadyPresent(PIEMRECOMPILERSTATE pReNative, uint32_t *poff,
     665                                                                            IEMNATIVEGSTREG enmGstReg) RT_NOEXCEPT;
     666
    641667DECLHIDDEN(uint8_t)         iemNativeRegAllocVar(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, uint8_t idxVar) RT_NOEXCEPT;
    642668DECLHIDDEN(uint32_t)        iemNativeRegAllocArgs(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t cArgs) RT_NOEXCEPT;
     
    970996        pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
    971997    pbCodeBuf[off++] = 0x8b;
    972     off = iemNativeEmitGprByVCpuDisp(pbCodeBuf,off,iGpr, offVCpu);
     998    off = iemNativeEmitGprByVCpuDisp(pbCodeBuf, off,iGpr, offVCpu);
    973999    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    9741000
     
    12631289 * Emits a load effective address to a GRP with an BP relative source address.
    12641290 */
    1265 DECLINLINE(uint32_t) iemNativeEmitLeaGrpByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
     1291DECLINLINE(uint32_t) iemNativeEmitLeaGprByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
    12661292{
    12671293    /* lea gprdst, [rbp + offDisp] */
     
    13741400
    13751401
     1402#ifdef RT_ARCH_AMD64
     1403/**
     1404 * Common bit of iemNativeEmitLoadGprByGpr and friends.
     1405 */
     1406DECL_FORCE_INLINE(uint32_t) iemNativeEmitGprByGprDisp(uint8_t *pbCodeBuf, uint32_t off,
     1407                                                      uint8_t iGprReg, uint8_t iGprBase, int32_t offDisp)
     1408{
     1409    if (offDisp == 0 && (iGprBase & 7) != X86_GREG_xBP) /* Can use encoding w/o displacement field. */
     1410    {
     1411        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM0, iGprReg & 7, iGprBase & 7);
     1412        if ((iGprBase & 7) == X86_GREG_xSP) /* for RSP/R12 relative addressing we have to use a SIB byte. */
     1413            pbCodeBuf[off++] = X86_SIB_MAKE(X86_GREG_xSP, X86_GREG_xSP, 0); /* -> [RSP/R12] */
     1414    }
     1415    else if (offDisp == (int8_t)offDisp)
     1416    {
     1417        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGprReg & 7, iGprBase & 7);
     1418        if ((iGprBase & 7) == X86_GREG_xSP) /* for RSP/R12 relative addressing we have to use a SIB byte. */
     1419            pbCodeBuf[off++] = X86_SIB_MAKE(X86_GREG_xSP, X86_GREG_xSP, 0); /* -> [RSP/R12] */
     1420        pbCodeBuf[off++] = (uint8_t)offDisp;
     1421    }
     1422    else
     1423    {
     1424        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGprReg & 7, iGprBase & 7);
     1425        if ((iGprBase & 7) == X86_GREG_xSP) /* for RSP/R12 relative addressing we have to use a SIB byte. */
     1426            pbCodeBuf[off++] = X86_SIB_MAKE(X86_GREG_xSP, X86_GREG_xSP, 0); /* -> [RSP/R12] */
     1427        pbCodeBuf[off++] = RT_BYTE1((uint32_t)offDisp);
     1428        pbCodeBuf[off++] = RT_BYTE2((uint32_t)offDisp);
     1429        pbCodeBuf[off++] = RT_BYTE3((uint32_t)offDisp);
     1430        pbCodeBuf[off++] = RT_BYTE4((uint32_t)offDisp);
     1431    }
     1432    return off;
     1433}
     1434#elif RT_ARCH_ARM64
     1435/**
     1436 * Common bit of iemNativeEmitLoadGprFromVCpuU64 and friends.
     1437 */
     1438DECL_FORCE_INLINE(uint32_t) iemNativeEmitGprByGprLdSt(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprReg,
     1439                                                      uint8_t iGprBase, int32_t offDisp,
     1440                                                      ARMV8A64INSTRLDSTTYPE enmOperation, unsigned cbData)
     1441{
     1442    /*
     1443     * There are a couple of ldr variants that takes an immediate offset, so
     1444     * try use those if we can, otherwise we have to use the temporary register
     1445     * help with the addressing.
     1446     */
     1447    if ((uint32_t)offDisp < _4K * cbData && !((uint32_t)offDisp & (cbData - 1)))
     1448    {
     1449        /* Use the unsigned variant of ldr Wt, [<Xn|SP>, #off]. */
     1450        uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
     1451        AssertReturn(pu32CodeBuf, UINT32_MAX);
     1452        pu32CodeBuf[off++] = Armv8A64MkInstrStLdRUOff(enmOperation, iGprReg, iGprBase, (uint32_t)offDisp / cbData);
     1453    }
     1454    else
     1455    {
     1456        /* The offset is too large, so we must load it into a register and use
     1457           ldr Wt, [<Xn|SP>, (<Wm>|<Xm>)]. */
     1458        /** @todo reduce by offVCpu by >> 3 or >> 2? if it saves instructions? */
     1459        uint8_t const idxTmpReg = iemNativeRegAllocTmpImm(pReNative, off, (uint64)offDisp);
     1460        AssertReturn(idxTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX);
     1461
     1462        uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
     1463        AssertReturn(pu32CodeBuf, UINT32_MAX);
     1464        pu32CodeBuf[off++] = Armv8A64MkInstrStLdRegIdx(enmOperation, iGprReg, iGprBase, idxTmpReg);
     1465
     1466        iemNativeRegFreeTmpImm(pReNative, idxTmpReg);
     1467    }
     1468    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     1469    return off;
     1470}
     1471#endif
     1472
     1473
     1474/**
     1475 * Emits a 64-bit GPR load via a GPR base address with a displacement.
     1476 */
     1477DECLINLINE(uint32_t) iemNativeEmitLoadGprByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off,
     1478                                               uint8_t iGprDst, uint8_t iGprBase, int32_t offDisp)
     1479{
     1480#ifdef RT_ARCH_AMD64
     1481    /* mov reg64, mem64 */
     1482    uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 8);
     1483    AssertReturn(pbCodeBuf, UINT32_MAX);
     1484    pbCodeBuf[off++] = X86_OP_REX_W | (iGprDst < 8 ? 0 : X86_OP_REX_R) | (iGprBase < 8 ? 0 : X86_OP_REX_B);
     1485    pbCodeBuf[off++] = 0x8b;
     1486    off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, iGprDst, iGprBase, offDisp);
     1487    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     1488
     1489#elif RT_ARCH_ARM64
     1490    off = iemNativeEmitGprByGprLdSt(pReNative, off, iGprDst, offDisp, kArmv8A64InstrLdStType_Ld_Dword, sizeof(uint64_t));
     1491
     1492#else
     1493# error "port me"
     1494#endif
     1495    return off;
     1496}
     1497
     1498
     1499/**
     1500 * Emits a 32-bit GPR load via a GPR base address with a displacement.
     1501 * @note Bits 63 thru 32 in @a iGprDst will be cleared.
     1502 */
     1503DECLINLINE(uint32_t) iemNativeEmitLoadGpr32ByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off,
     1504                                                 uint8_t iGprDst, uint8_t iGprBase, int32_t offDisp)
     1505{
     1506#ifdef RT_ARCH_AMD64
     1507    /* mov reg32, mem32 */
     1508    uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 8);
     1509    AssertReturn(pbCodeBuf, UINT32_MAX);
     1510    if (iGprDst >= 8 || iGprBase >= 8)
     1511        pbCodeBuf[off++] = (iGprDst < 8 ? 0 : X86_OP_REX_R) | (iGprBase < 8 ? 0 : X86_OP_REX_B);
     1512    pbCodeBuf[off++] = 0x8b;
     1513    off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, iGprDst, iGprBase, offDisp);
     1514    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     1515
     1516#elif RT_ARCH_ARM64
     1517    off = iemNativeEmitGprByGprLdSt(pReNative, off, iGprDst, offDisp, kArmv8A64InstrLdStType_Ld_Word, sizeof(uint32_t));
     1518
     1519#else
     1520# error "port me"
     1521#endif
     1522    return off;
     1523}
     1524
     1525
    13761526/*********************************************************************************************************************************
    13771527*   Subtraction and Additions                                                                                                    *
     
    16831833/**
    16841834 * Emits code for AND'ing two 64-bit GPRs.
    1685  */
    1686 DECLINLINE(uint32_t ) iemNativeEmitAndGprByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint8_t iGprSrc)
     1835 *
     1836 * @note When fSetFlags=true, JZ/JNZ jumps can be used afterwards on both AMD64
     1837 *       and ARM64 hosts.
     1838 */
     1839DECLINLINE(uint32_t ) iemNativeEmitAndGprByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint8_t iGprSrc,
     1840                                               bool fSetFlags = false)
    16871841{
    16881842#if defined(RT_ARCH_AMD64)
     
    16931847    pbCodeBuf[off++] = 0x23;
    16941848    pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGprDst & 7, iGprSrc & 7);
     1849    RT_NOREF(fSetFlags);
    16951850
    16961851#elif defined(RT_ARCH_ARM64)
    16971852    uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
    16981853    AssertReturn(pu32CodeBuf, UINT32_MAX);
    1699     pu32CodeBuf[off++] = Armv8A64MkInstrAnd(iGprDst, iGprDst, iGprSrc);
     1854    if (!fSetFlags)
     1855        pu32CodeBuf[off++] = Armv8A64MkInstrAnd(iGprDst, iGprDst, iGprSrc);
     1856    else
     1857        pu32CodeBuf[off++] = Armv8A64MkInstrAnds(iGprDst, iGprDst, iGprSrc);
    17001858
    17011859#else
     
    17351893
    17361894/**
    1737  * Emits code for AND'ing an 32-bit GPRs with a constant.
    1738  */
    1739 DECLINLINE(uint32_t ) iemNativeEmitAndGpr32ByImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint32_t uImm)
     1895 * Emits code for AND'ing a 64-bit GPRs with a constant.
     1896 *
     1897 * @note When fSetFlags=true, JZ/JNZ jumps can be used afterwards on both AMD64
     1898 *       and ARM64 hosts.
     1899 */
     1900DECLINLINE(uint32_t ) iemNativeEmitAndGprByImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint64_t uImm,
     1901                                               bool fSetFlags = false)
    17401902{
    17411903#if defined(RT_ARCH_AMD64)
    1742     /* and Ev, imm */
    1743     uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
    1744     AssertReturn(pbCodeBuf, UINT32_MAX);
    1745     if (iGprDst >= 8)
    1746         pbCodeBuf[off++] = X86_OP_REX_R;
    1747     if (uImm < 128)
    1748     {
     1904    if ((int64_t)uImm == (int8_t)uImm)
     1905    {
     1906        /* and Ev, imm8 */
     1907        uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 4);
     1908        AssertReturn(pbCodeBuf, UINT32_MAX);
     1909        pbCodeBuf[off++] = X86_OP_REX_W | (iGprDst < 8 ? 0 : X86_OP_REX_R);
    17491910        pbCodeBuf[off++] = 0x83;
    17501911        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7);
    17511912        pbCodeBuf[off++] = (uint8_t)uImm;
    17521913    }
    1753     else
    1754     {
     1914    else if ((int64_t)uImm == (int32_t)uImm)
     1915    {
     1916        /* and Ev, imm32 */
     1917        uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
     1918        AssertReturn(pbCodeBuf, UINT32_MAX);
     1919        pbCodeBuf[off++] = X86_OP_REX_W | (iGprDst < 8 ? 0 : X86_OP_REX_R);
    17551920        pbCodeBuf[off++] = 0x81;
    17561921        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7);
     
    17601925        pbCodeBuf[off++] = RT_BYTE4(uImm);
    17611926    }
     1927    else
     1928    {
     1929        /* Use temporary register for the 64-bit immediate. */
     1930        uint8_t iTmpReg = iemNativeRegAllocTmpImm(pReNative, &off, uImm);
     1931        AssertReturn(iTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX);
     1932        off = iemNativeEmitAndGprByGpr(pReNative, off, iGprDst, iTmpReg);
     1933        iemNativeRegFreeTmpImm(pReNative, iTmpReg);
     1934    }
     1935    RT_NOREF(fSetFlags);
    17621936
    17631937#elif defined(RT_ARCH_ARM64)
     
    17681942        uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
    17691943        AssertReturn(pu32CodeBuf, UINT32_MAX);
    1770         pu32CodeBuf[off++] = Armv8A64MkInstrAndImm(iGprDst, iGprDst, uImmNandS, uImmR, false /*f64Bit*/);
    1771     }
    1772     else
    1773     {
    1774         /* Use temporary register for the immediate. */
     1944        if (!fSetFlags)
     1945            pu32CodeBuf[off++] = Armv8A64MkInstrAndImm(iGprDst, iGprDst, uImmNandS, uImmR);
     1946        else
     1947            pu32CodeBuf[off++] = Armv8A64MkInstrAndsImm(iGprDst, iGprDst, uImmNandS, uImmR);
     1948    }
     1949    else
     1950    {
     1951        /* Use temporary register for the 64-bit immediate. */
    17751952        uint8_t iTmpReg = iemNativeRegAllocTmpImm(pReNative, &off, uImm);
    17761953        AssertReturn(iTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX);
    1777 
    1778         /* and gprdst, gprdst, tmpreg */
     1954        off = iemNativeEmitAndGprByGpr(pReNative, off, iGprDst, iTmpReg, fSetFlags);
     1955        iemNativeRegFreeTmpImm(pReNative, iTmpReg);
     1956    }
     1957
     1958#else
     1959# error "Port me"
     1960#endif
     1961    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     1962    return off;
     1963}
     1964
     1965
     1966/**
     1967 * Emits code for AND'ing an 32-bit GPRs with a constant.
     1968 */
     1969DECLINLINE(uint32_t ) iemNativeEmitAndGpr32ByImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint32_t uImm,
     1970                                                 bool fSetFlags = false)
     1971{
     1972#if defined(RT_ARCH_AMD64)
     1973    /* and Ev, imm */
     1974    uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
     1975    AssertReturn(pbCodeBuf, UINT32_MAX);
     1976    if (iGprDst >= 8)
     1977        pbCodeBuf[off++] = X86_OP_REX_R;
     1978    if ((int32_t)uImm == (int8_t)uImm)
     1979    {
     1980        pbCodeBuf[off++] = 0x83;
     1981        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7);
     1982        pbCodeBuf[off++] = (uint8_t)uImm;
     1983    }
     1984    else
     1985    {
     1986        pbCodeBuf[off++] = 0x81;
     1987        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7);
     1988        pbCodeBuf[off++] = RT_BYTE1(uImm);
     1989        pbCodeBuf[off++] = RT_BYTE2(uImm);
     1990        pbCodeBuf[off++] = RT_BYTE3(uImm);
     1991        pbCodeBuf[off++] = RT_BYTE4(uImm);
     1992    }
     1993    RT_NOREF(fSetFlags);
     1994
     1995#elif defined(RT_ARCH_ARM64)
     1996    uint32_t uImmR     = 0;
     1997    uint32_t uImmNandS = 0;
     1998    if (Armv8A64ConvertMaskToImmRImmS(uImm, &uImmNandS, &uImmR))
     1999    {
    17792000        uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
    17802001        AssertReturn(pu32CodeBuf, UINT32_MAX);
    1781         pu32CodeBuf[off++] = Armv8A64MkInstrAnd(iGprDst, iGprDst, iTmpReg, false /*f64Bit*/);
    1782 
     2002        if (!fSetFlags)
     2003            pu32CodeBuf[off++] = Armv8A64MkInstrAndImm(iGprDst, iGprDst, uImmNandS, uImmR, false /*f64Bit*/);
     2004        else
     2005            pu32CodeBuf[off++] = Armv8A64MkInstrAndsImm(iGprDst, iGprDst, uImmNandS, uImmR, false /*f64Bit*/);
     2006    }
     2007    else
     2008    {
     2009        /* Use temporary register for the 64-bit immediate. */
     2010        uint8_t iTmpReg = iemNativeRegAllocTmpImm(pReNative, &off, uImm);
     2011        AssertReturn(iTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX);
     2012        if (!fSetFlags)
     2013            off = iemNativeEmitAndGpr32ByGpr32(pReNative, off, iGprDst, iTmpReg);
     2014        else
     2015            off = iemNativeEmitAndsGpr32ByGpr32(pReNative, off, iGprDst, iTmpReg);
    17832016        iemNativeRegFreeTmpImm(pReNative, iTmpReg);
    17842017    }
     
    27242957        iemNativeRegFreeTmpImm(pReNative, iTmpReg);
    27252958    }
    2726     else
     2959    else if (fBits <= UINT32_MAX)
    27272960    {
    27282961        /* test Eb, imm8 or test Ev, imm32 */
     
    27472980        }
    27482981    }
     2982    /** @todo implement me. */
     2983    else
     2984        AssertFailedReturn(UINT32_MAX);
    27492985
    27502986#elif defined(RT_ARCH_ARM64)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette