VirtualBox

Changeset 106180 in vbox


Ignore:
Timestamp:
Sep 30, 2024 1:51:48 PM (5 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
164964
Message:

VMM/IEM: Refactoring TbExits and other early eflags calculation postponement changes. bugref:10720

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstPython.py

    r106179 r106180  
    29442944        if sRet:
    29452945            asRet.append(sRet);
     2946
     2947        ## @todo Check that IEM_MC_REF_EFLAGS isn't used before memory fetches and does
     2948        # not have any stores or conditional raises afterwards.
    29462949
    29472950        return asRet;
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstVexMap2.cpp.h

    r106061 r106180  
    313313            IEM_MC_REF_XREG_U128_CONST(puSrc2, IEM_GET_MODRM_RM(pVCpu, bRm)); \
    314314            IEM_MC_REF_EFLAGS(pEFlags); \
    315                 IEM_MC_CALL_VOID_AIMPL_3(IEM_SELECT_HOST_OR_FALLBACK(fAvx, iemAImpl_ ## a_Instr ## _u128, \
    316                                                                            iemAImpl_ ## a_Instr ## _u128_fallback), \
    317                                          puSrc1, puSrc2, pEFlags); \
     315            IEM_MC_CALL_VOID_AIMPL_3(IEM_SELECT_HOST_OR_FALLBACK(fAvx, iemAImpl_ ## a_Instr ## _u128, \
     316                                                                       iemAImpl_ ## a_Instr ## _u128_fallback), \
     317                                     puSrc1, puSrc2, pEFlags); \
    318318            IEM_MC_ADVANCE_RIP_AND_FINISH(); \
    319319            IEM_MC_END(); \
     
    362362            IEM_MC_REF_XREG_U128_CONST(puSrc1,  IEM_GET_MODRM_REG(pVCpu, bRm)); \
    363363            IEM_MC_REF_EFLAGS(pEFlags); \
    364                 IEM_MC_CALL_VOID_AIMPL_3(IEM_SELECT_HOST_OR_FALLBACK(fAvx, iemAImpl_ ## a_Instr ## _u128, \
    365                                                                            iemAImpl_ ## a_Instr ## _u128_fallback), \
    366                                          puSrc1, puSrc2, pEFlags); \
     364            IEM_MC_CALL_VOID_AIMPL_3(IEM_SELECT_HOST_OR_FALLBACK(fAvx, iemAImpl_ ## a_Instr ## _u128, \
     365                                                                       iemAImpl_ ## a_Instr ## _u128_fallback), \
     366                                     puSrc1, puSrc2, pEFlags); \
    367367            IEM_MC_ADVANCE_RIP_AND_FINISH(); \
    368368            IEM_MC_END(); \
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompBltIn.cpp

    r106144 r106180  
    5656#include "IEMN8veRecompilerEmit.h"
    5757#include "IEMN8veRecompilerTlbLookup.h"
     58#include "target-x86/IEMAllN8veEmit-x86.h"
    5859
    5960
     
    213214    uint8_t const         idxTmpReg1 = iemNativeRegAllocTmp(pReNative, &off);
    214215    uint8_t const         idxTmpReg2 = a_fCheckIrqs ? iemNativeRegAllocTmp(pReNative, &off) : UINT8_MAX;
    215     PIEMNATIVEINSTR const pCodeBuf   = iemNativeInstrBufEnsure(pReNative, off, RT_ARCH_VAL == RT_ARCH_VAL_AMD64 ? 72 : 32);
     216    PIEMNATIVEINSTR const pCodeBuf   = iemNativeInstrBufEnsure(pReNative, off,
     217                                                                 (RT_ARCH_VAL == RT_ARCH_VAL_AMD64 ? 72 : 32)
     218                                                               + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS * 3);
    216219
    217220    /*
     
    226229
    227230        /* jz   ReturnBreakFF */
    228         off = iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, kIemNativeLabelType_ReturnBreakFF, kIemNativeInstrCond_e);
     231        off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_ReturnBreakFF>(pReNative, pCodeBuf, off, kIemNativeInstrCond_e);
    229232
    230233# elif defined(RT_ARCH_ARM64)
     
    235238
    236239        /* cbz reg1, ReturnBreakFF */
    237         off = iemNativeEmitTestIfGprIsZeroAndTbExitEx(pReNative, pCodeBuf, off, idxTmpReg1, false /*f64Bit*/,
    238                                                       kIemNativeLabelType_ReturnBreakFF);
     240        off = iemNativeEmitTbExitIfGprIsZeroEx<kIemNativeLabelType_ReturnBreakFF>(pReNative, pCodeBuf, off,
     241                                                                                  idxTmpReg1, false /*f64Bit*/);
    239242
    240243# else
     
    341344        off = iemNativeEmitCmpGprWithImmEx(pCodeBuf, off, idxTmpReg1, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC);
    342345        /* ja ReturnBreakFF */
    343         off = iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, kIemNativeLabelType_ReturnBreakFF, kIemNativeInstrCond_nbe);
     346        off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_ReturnBreakFF>(pReNative, pCodeBuf, off, kIemNativeInstrCond_nbe);
    344347
    345348        /*
     
    357360# ifdef RT_ARCH_AMD64
    358361        /* jz   ReturnBreakFF */
    359         off = iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, kIemNativeLabelType_ReturnBreakFF, kIemNativeInstrCond_e);
     362        off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_ReturnBreakFF>(pReNative, pCodeBuf, off, kIemNativeInstrCond_e);
    360363
    361364# elif defined(RT_ARCH_ARM64)
    362365        /* cbz  reg1, ReturnBreakFF */
    363         off = iemNativeEmitTestIfGprIsZeroAndTbExitEx(pReNative, pCodeBuf, off, idxTmpReg1, false /*f64Bit*/,
    364                                                       kIemNativeLabelType_ReturnBreakFF);
     366        off = iemNativeEmitTbExitIfGprIsZeroEx<kIemNativeLabelType_ReturnBreakFF>(pReNative, pCodeBuf, off,
     367                                                                                  idxTmpReg1, false /*f64Bit*/);
    365368# else
    366369#  error "port me"
     
    475478    off = iemNativeEmitLoadGprFromVCpuU32(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, iem.s.fExec));
    476479    off = iemNativeEmitAndGpr32ByImm(pReNative, off, idxTmpReg, IEMTB_F_KEY_MASK);
    477     off = iemNativeEmitTestIfGpr32NotEqualImmAndTbExit(pReNative, off, idxTmpReg, fExpectedExec & IEMTB_F_KEY_MASK,
    478                                                        kIemNativeLabelType_ReturnBreak);
     480    off = iemNativeEmitTbExitIfGpr32NotEqualImm<kIemNativeLabelType_ReturnBreak>(pReNative, off, idxTmpReg,
     481                                                                                 fExpectedExec & IEMTB_F_KEY_MASK);
    479482    iemNativeRegFreeTmp(pReNative, idxTmpReg);
    480483
     
    606609
    607610    /* 3. Jump if greater. */
    608     off = iemNativeEmitJaTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0);
     611    off = iemNativeEmitTbExitJa<kIemNativeLabelType_RaiseGp0>(pReNative, off);
    609612
    610613    iemNativeRegFreeTmp(pReNative, idxRegCsLim);
     
    694697    /* Compare the two and jump out if we're too close to the limit. */
    695698    off = iemNativeEmitCmpGprWithGpr(pReNative, off, idxRegLeft, idxRegRight);
    696     off = iemNativeEmitJlTbExit(pReNative, off, kIemNativeLabelType_NeedCsLimChecking);
     699    off = iemNativeEmitTbExitJl<kIemNativeLabelType_NeedCsLimChecking>(pReNative, off);
    697700
    698701    iemNativeRegFreeTmp(pReNative, idxRegRight);
     
    754757        } while (0)
    755758
    756 # define NEAR_JMP_SIZE 5
    757 
    758759# define CHECK_OPCODES_CMP_JMP() /* cost: 7 bytes first time, then 2 bytes */ do { \
    759760            if (offConsolidatedJump != UINT32_MAX) \
     
    766767            else \
    767768            { \
    768                 pbCodeBuf[off++] = 0x74; /* jz near +NEAR_JMP_SIZE */ \
    769                 pbCodeBuf[off++] = NEAR_JMP_SIZE + BP_ON_OBSOLETION; \
    770                 offConsolidatedJump = off; \
     769                pbCodeBuf[off++] = 0x74; /* jz near +5 */ \
     770                offConsolidatedJump = ++off; \
    771771                if (BP_ON_OBSOLETION) pbCodeBuf[off++] = 0xcc; \
    772                 off = iemNativeEmitTbExitEx(pReNative, pbCodeBuf, off, kIemNativeLabelType_ObsoleteTb); \
     772                off = iemNativeEmitTbExitEx<kIemNativeLabelType_ObsoleteTb, false /*a_fActuallyExitingTb*/>(pReNative, \
     773                                                                                                            pbCodeBuf, off); \
     774                pbCodeBuf[offConsolidatedJump - 1]  = off - offConsolidatedJump; \
    773775            } \
    774776        } while (0)
     
    836838        }
    837839
    838         uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6 + 14 + 54 + 8 + 6 + BP_ON_OBSOLETION /* = 88 */);
     840        uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6 + 14 + 54 + 8 + 6 + BP_ON_OBSOLETION /* = 88 */
     841                                                            + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
    839842
    840843        if (cbLeft > 8)
     
    880883        uint8_t const idxRegCx = iemNativeRegAllocTmpEx(pReNative, &off, RT_BIT_32(X86_GREG_xCX));
    881884
    882         uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6 + 10 + 5 + 5 + 3 + 4 + 3 + BP_ON_OBSOLETION /*= 36*/);
     885        uint8_t * const pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6 + 10 + 5 + 5 + 3 + 4 + 3 + BP_ON_OBSOLETION /*= 36*/
     886                                                            + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
    883887
    884888        /** @todo profile and optimize this further.  Maybe an idea to align by
     
    943947    uint8_t const idxRegSrc1Val = iemNativeRegAllocTmp(pReNative, &off);
    944948
    945     uint32_t * const pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 64);
     949    uint32_t * const pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 64 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS * 2);
    946950
    947951    /* One byte compare can be done with the opcode byte as an immediate. We'll
     
    10141018                if (fPendingJmp)
    10151019                {
    1016                     off = iemNativeEmitJccTbExitEx(pReNative, pu32CodeBuf, off, kIemNativeLabelType_ObsoleteTb,
    1017                                                    kArmv8InstrCond_Ne);
     1020                    off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_ObsoleteTb>(pReNative, pu32CodeBuf, off,
     1021                                                                                   kArmv8InstrCond_Ne);
    10181022                    fPendingJmp = false;
    10191023                }
     
    10511055                                                            ARMA64_NZCV_F_N0_Z0_C0_V0, kArmv8InstrCond_Eq);
    10521056
    1053                 off = iemNativeEmitJccTbExitEx(pReNative, pu32CodeBuf, off, kIemNativeLabelType_ObsoleteTb,
    1054                                                kArmv8InstrCond_Ne);
     1057                off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_ObsoleteTb>(pReNative, pu32CodeBuf, off, kArmv8InstrCond_Ne);
    10551058
    10561059                /* Advance and loop. */
     
    11851188     */
    11861189    if (fPendingJmp)
    1187         off = iemNativeEmitJnzTbExit(pReNative, off, kIemNativeLabelType_ObsoleteTb);
     1190        off = iemNativeEmitTbExitJnz<kIemNativeLabelType_ObsoleteTb>(pReNative, off);
    11881191
    11891192    RT_NOREF(pu32CodeBuf, cbLeft, offPage, pbOpcodes, offConsolidatedJump);
     
    13461349    /* 3. Check that off is less than X86_PAGE_SIZE/cbInstrBufTotal. */
    13471350    off = iemNativeEmitCmpGprWithImm(pReNative, off, idxRegTmp, X86_PAGE_SIZE - 1);
    1348     off = iemNativeEmitJaTbExit(pReNative, off, kIemNativeLabelType_CheckBranchMiss);
     1351    off = iemNativeEmitTbExitJa<kIemNativeLabelType_CheckBranchMiss>(pReNative, off);
    13491352
    13501353    /* 4. Add iem.s.GCPhysInstrBuf and compare with GCPhysRangePageWithOffset. */
     
    13771380                                                | pTb->aRanges[idxRange].offPhysPage)
    13781381                                             + offRange;
    1379     off = iemNativeEmitTestIfGprNotEqualImmAndTbExit(pReNative, off, idxRegTmp, GCPhysRangePageWithOffset,
    1380                                                      kIemNativeLabelType_CheckBranchMiss);
     1382    off = iemNativeEmitTbExitIfGprNotEqualImm<kIemNativeLabelType_CheckBranchMiss>(pReNative, off, idxRegTmp,
     1383                                                                                   GCPhysRangePageWithOffset);
    13811384
    13821385    iemNativeRegFreeTmp(pReNative, idxRegTmp);
     
    14871490     */
    14881491    RTGCPHYS const GCPhysNewPage = iemTbGetRangePhysPageAddr(pTb, idxRange);
    1489     off = iemNativeEmitTestIfGprNotEqualImmAndTbExit(pReNative, off, idxRegGCPhys, GCPhysNewPage,
    1490                                                      kIemNativeLabelType_ObsoleteTb);
     1492    off = iemNativeEmitTbExitIfGprNotEqualImm<kIemNativeLabelType_ObsoleteTb>(pReNative, off, idxRegGCPhys, GCPhysNewPage);
    14911493
    14921494    iemNativeRegFreeTmp(pReNative, idxRegGCPhys);
     
    16991701    off = iemNativeEmitLoadGprImm64(pReNative, off, idxRegTmp2, GCPhysRangePageWithOffset);
    17001702    off = iemNativeEmitCmpGprWithGpr(pReNative, off, idxRegTmp, idxRegTmp2);
    1701     off = iemNativeEmitJnzTbExit(pReNative, off, kIemNativeLabelType_CheckBranchMiss);
     1703    off = iemNativeEmitTbExitJnz<kIemNativeLabelType_CheckBranchMiss>(pReNative, off);
    17021704    uint32_t const offFixedJumpToEnd = off;
    17031705    off = iemNativeEmitJmpToFixed(pReNative, off, off + 512 /* force rel32 */);
     
    17111713
    17121714    /* Check that we haven't been here before. */
    1713     off = iemNativeEmitTestIfGprIsNotZeroAndTbExit(pReNative, off, idxRegTmp2,  false /*f64Bit*/,
    1714                                                    kIemNativeLabelType_CheckBranchMiss);
     1715    off = iemNativeEmitTbExitIfGprIsNotZero<kIemNativeLabelType_CheckBranchMiss>(pReNative, off, idxRegTmp2, false /*f64Bit*/);
    17151716
    17161717    /* Jump to the TLB lookup code. */
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompFuncs.h

    r106179 r106180  
    6060#include "IEMN8veRecompilerTlbLookup.h"
    6161#include "IEMNativeFunctions.h"
     62#include "target-x86/IEMAllN8veEmit-x86.h"
    6263
    6364
     
    442443                                                                 RT_BIT_64(IEMLIVENESSBIT_IDX_EFL_OTHER),
    443444                                                                 RT_BIT_64(IEMLIVENESSBIT_IDX_EFL_OTHER));
    444     off = iemNativeEmitTestAnyBitsInGprAndTbExitIfAnySet(pReNative, off, idxEflReg,
    445                                                          X86_EFL_TF | CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK,
    446                                                          kIemNativeLabelType_ReturnWithFlags);
     445    off = iemNativeEmitTbExitIfAnyBitsSetInGpr<kIemNativeLabelType_ReturnWithFlags>(pReNative, off, idxEflReg,
     446                                                                                      X86_EFL_TF
     447                                                                                    | CPUMCTX_DBG_HIT_DRX_MASK
     448                                                                                    | CPUMCTX_DBG_DBGF_MASK);
    447449    off = iemNativeEmitAndGpr32ByImm(pReNative, off, idxEflReg, ~(uint32_t)(X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW));
    448450    off = iemNativeEmitStoreGprToVCpuU32(pReNative, off, idxEflReg, RT_UOFFSETOF(VMCPU, cpum.GstCtx.eflags));
     
    556558
    557559                if (pReNative->idxLastCheckIrqCallNo != UINT32_MAX)
    558                     return iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_ReturnBreakViaLookup);
    559                 return iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_ReturnBreakViaLookupWithIrq);
     560                    return iemNativeEmitTbExit<kIemNativeLabelType_ReturnBreakViaLookup>(pReNative, off);
     561                return iemNativeEmitTbExit<kIemNativeLabelType_ReturnBreakViaLookupWithIrq>(pReNative, off);
    560562            }
    561563        }
    562564        if (pReNative->idxLastCheckIrqCallNo != UINT32_MAX)
    563             return iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_ReturnBreakViaLookupWithTlb);
    564         return iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_ReturnBreakViaLookupWithTlbAndIrq);
     565            return iemNativeEmitTbExit<kIemNativeLabelType_ReturnBreakViaLookupWithTlb>(pReNative, off);
     566        return iemNativeEmitTbExit<kIemNativeLabelType_ReturnBreakViaLookupWithTlbAndIrq>(pReNative, off);
    565567#endif
    566568    }
     
    749751    off = iemNativeEmitAddGpr32Imm(pReNative, off, iTmpReg, (int32_t)0x8000);
    750752    off = iemNativeEmitShiftGprRight(pReNative, off, iTmpReg, 16);
    751     off = iemNativeEmitJnzTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0);
     753    off = iemNativeEmitTbExitJnz<kIemNativeLabelType_RaiseGp0>(pReNative, off);
    752754
    753755    iemNativeRegFreeTmp(pReNative, iTmpReg);
     
    768770    off = iemNativeEmitAddTwoGprs(pReNative, off, iTmpReg, idxAddrReg);
    769771    off = iemNativeEmitCmpArm64(pReNative, off, ARMV8_A64_REG_XZR, iTmpReg, true /*f64Bit*/, 48 /*cShift*/, kArmv8A64InstrShift_Lsr);
    770     off = iemNativeEmitJnzTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0);
     772    off = iemNativeEmitTbExitJnz<kIemNativeLabelType_RaiseGp0>(pReNative, off);
    771773
    772774    iemNativeRegFreeTmp(pReNative, iTmpReg);
     
    854856    off = iemNativeEmitStoreGprToVCpuU64(pReNative, off, idxAddrReg, RT_UOFFSETOF(VMCPU, cpum.GstCtx.rip));
    855857
    856     off = iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0, false /*fActuallyExitingTb*/);
     858    off = iemNativeEmitTbExit<kIemNativeLabelType_RaiseGp0, false /*a_fActuallyExitingTb*/>(pReNative, off);
    857859
    858860    /* .Lnoexcept: */
     
    950952        off = iemNativeEmitStoreGprToVCpuU64(pReNative, off, idxOldPcReg, RT_UOFFSETOF(VMCPU, cpum.GstCtx.rip));
    951953
    952         off = iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0, false /*fActuallyExitingTb*/);
     954        off = iemNativeEmitTbExit<kIemNativeLabelType_RaiseGp0, false /*a_fActuallyExitingTb*/>(pReNative, off);
    953955        iemNativeFixupFixedJump(pReNative, offFixup, off);
    954956    }
    955957    else
    956958#endif
    957         off = iemNativeEmitJnzTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0);
     959        off = iemNativeEmitTbExitJnz<kIemNativeLabelType_RaiseGp0>(pReNative, off);
    958960
    959961    iemNativeRegFreeTmp(pReNative, iTmpReg);
     
    995997
    996998    off = iemNativeEmitCmpGpr32WithGpr(pReNative, off, idxAddrReg, idxRegCsLim);
    997     off = iemNativeEmitJaTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0);
     999    off = iemNativeEmitTbExitJa<kIemNativeLabelType_RaiseGp0>(pReNative, off);
    9981000
    9991001    iemNativeRegFreeTmp(pReNative, idxRegCsLim);
     
    10581060        off = iemNativeEmitStoreImmToVCpuU8(pReNative, off, idxInstr, RT_UOFFSETOF(VMCPUCC, iem.s.idxTbCurInstr));
    10591061# endif
    1060         off = iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0, false /*fActuallyExitingTb*/);
     1062        off = iemNativeEmitTbExit<kIemNativeLabelType_RaiseGp0, false /*a_fActuallyExitingTb*/>(pReNative, off);
    10611063        iemNativeFixupFixedJump(pReNative, offFixup, off);
    10621064    }
    10631065    else
    10641066#endif
    1065         off = iemNativeEmitJaTbExit(pReNative, off, kIemNativeLabelType_RaiseGp0);
     1067        off = iemNativeEmitTbExitJa<kIemNativeLabelType_RaiseGp0>(pReNative, off);
    10661068
    10671069    iemNativeRegFreeTmp(pReNative, idxRegCsLim);
     
    25992601         */
    26002602        /* Test and jump. */
    2601         off = iemNativeEmitTestAnyBitsInGprAndTbExitIfAnySet(pReNative, off, idxCr0Reg, X86_CR0_EM | X86_CR0_TS,
    2602                                                              kIemNativeLabelType_RaiseNm);
     2603        off = iemNativeEmitTbExitIfAnyBitsSetInGpr<kIemNativeLabelType_RaiseNm>(pReNative, off, idxCr0Reg,
     2604                                                                                X86_CR0_EM | X86_CR0_TS);
    26032605
    26042606        /* Free but don't flush the CR0 register. */
     
    26592661        off = iemNativeEmitAndGpr32ByImm(pReNative, off, idxCr0Reg, X86_CR0_MP | X86_CR0_TS);
    26602662        /* Test and jump. */
    2661         off = iemNativeEmitTestIfGpr32EqualsImmAndTbExit(pReNative, off, idxCr0Reg, X86_CR0_MP | X86_CR0_TS,
    2662                                                          kIemNativeLabelType_RaiseNm);
     2663        off = iemNativeEmitTbExitIfGpr32EqualsImm<kIemNativeLabelType_RaiseNm>(pReNative, off, idxCr0Reg, X86_CR0_MP | X86_CR0_TS);
    26632664
    26642665        /* Free the CR0 register. */
     
    27122713     */
    27132714    /* Test and jump. */
    2714     off = iemNativeEmitTestBitInGprAndTbExitIfSet(pReNative, off, idxFpuFswReg, X86_FSW_ES_BIT, kIemNativeLabelType_RaiseMf);
     2715    off = iemNativeEmitTbExitIfBitSetInGpr<kIemNativeLabelType_RaiseMf>(pReNative, off, idxFpuFswReg, X86_FSW_ES_BIT);
    27152716
    27162717    /* Free but don't flush the FSW register. */
     
    27692770         * be a safe assumption.
    27702771         */
    2771         PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1+6+3+3+7+7+6);
     2772        PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off,
     2773                                                                 1+6+3+3+7+7+6 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
    27722774        //pCodeBuf[off++] = 0xcc;
    27732775        off = iemNativeEmitLoadGpr32ImmEx(pCodeBuf, off,    idxTmpReg, X86_CR4_OSFXSR); /* Isolate CR4.OSFXSR as CR4.TSD and */
     
    27762778        off = iemNativeEmitAndGpr32ByImmEx(pCodeBuf, off,   idxTmpReg, X86_CR0_EM | X86_CR0_TS | X86_CR4_OSFXSR);
    27772779        off = iemNativeEmitXorGpr32ByImmEx(pCodeBuf, off,   idxTmpReg, X86_CR4_OSFXSR);
    2778         off = iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, kIemNativeLabelType_RaiseSseRelated, kIemNativeInstrCond_ne);
     2780        off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_RaiseSseRelated>(pReNative, pCodeBuf, off, kIemNativeInstrCond_ne);
    27792781
    27802782#elif defined(RT_ARCH_ARM64)
     
    27842786         *  else                                                                                { goto RaiseSseRelated; }
    27852787         */
    2786         PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1+5);
     2788        PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off,
     2789                                                                 1+5 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
    27872790        //pCodeBuf[off++] = Armv8A64MkInstrBrk(0x1111);
    27882791        Assert(Armv8A64ConvertImmRImmS2Mask32(1, 32 - X86_CR0_EM_BIT) == (X86_CR0_EM | X86_CR0_TS));
     
    27932796        pCodeBuf[off++] = Armv8A64MkInstrEorImm(idxTmpReg, idxTmpReg, 0, 0, false /*f64Bit*/);
    27942797        /* -> idxTmpReg[0]=~OSFXSR; idxTmpReg[2]=EM; idxTmpReg[3]=TS; (the rest is zero) */
    2795         off = iemNativeEmitTestIfGprIsNotZeroAndTbExitEx(pReNative, pCodeBuf, off, idxTmpReg, false /*f64Bit*/,
    2796                                                          kIemNativeLabelType_RaiseSseRelated);
     2798        off = iemNativeEmitTbExitIfGprIsNotZeroEx<kIemNativeLabelType_RaiseSseRelated>(pReNative, pCodeBuf, off,
     2799                                                                                       idxTmpReg, false /*f64Bit*/);
    27972800
    27982801#else
     
    28702873                  ^ 0x1a) ) { likely }
    28712874            else            { goto RaiseAvxRelated; } */
    2872         PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1+6+3+5+3+5+3+7+6);
     2875        PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off,
     2876                                                                 1+6+3+5+3+5+3+7+6 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
    28732877        //pCodeBuf[off++] = 0xcc;
    28742878        off = iemNativeEmitLoadGpr32ImmEx(pCodeBuf, off,                 idxTmpReg, XSAVE_C_YMM | XSAVE_C_SSE);
     
    28822886        off = iemNativeEmitXorGpr32ByImmEx(pCodeBuf, off,                idxTmpReg, ((XSAVE_C_YMM | XSAVE_C_SSE) << 2) | 2);
    28832887        /* -> idxTmpReg[0]=CR0.TS idxTmpReg[1]=~CR4.OSXSAVE; idxTmpReg[2]=0; idxTmpReg[3]=~SSE; idxTmpReg[4]=~YMM; */
    2884         off = iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, kIemNativeLabelType_RaiseAvxRelated, kIemNativeInstrCond_ne);
     2888        off = iemNativeEmitTbExitJccEx<kIemNativeLabelType_RaiseAvxRelated>(pReNative, pCodeBuf, off, kIemNativeInstrCond_ne);
    28852889
    28862890#elif defined(RT_ARCH_ARM64)
     
    28882892                  | ((cr0 >> X86_CR0_TS_BIT) & 1) ) { likely }
    28892893            else                                    { goto RaiseAvxRelated; } */
    2890         PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1+6);
     2894        PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off,
     2895                                                                 1+6 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
    28912896        //pCodeBuf[off++] = Armv8A64MkInstrBrk(0x1111);
    28922897        Assert(Armv8A64ConvertImmRImmS2Mask32(1, 32 - XSAVE_C_SSE_BIT) == (XSAVE_C_YMM | XSAVE_C_SSE));
     
    29002905        pCodeBuf[off++] = Armv8A64MkInstrBfxil(idxTmpReg, idxCr0Reg, X86_CR0_TS_BIT, 1, false /*f64Bit*/);
    29012906        /* -> idxTmpReg[0]=CR0.TS; idxTmpReg[1]=~CR4.OSXSAVE; idxTmpReg[2]=~SSE; idxTmpReg[3]=~YMM; (the rest is zero) */
    2902         off = iemNativeEmitTestIfGprIsNotZeroAndTbExitEx(pReNative, pCodeBuf, off, idxTmpReg, false /*f64Bit*/,
    2903                                                          kIemNativeLabelType_RaiseAvxRelated);
     2907        off = iemNativeEmitTbExitIfGprIsNotZeroEx<kIemNativeLabelType_RaiseAvxRelated>(pReNative, pCodeBuf, off,
     2908                                                                                       idxTmpReg, false /*f64Bit*/);
    29042909
    29052910#else
     
    29522957    /* Do the job we're here for. */
    29532958    uint8_t const idxVarReg = iemNativeVarRegisterAcquire(pReNative, idxVar, &off);
    2954     off = iemNativeEmitTestIfGprIsZeroAndTbExit(pReNative, off, idxVarReg, false /*f64Bit*/, kIemNativeLabelType_RaiseDe);
     2959    off = iemNativeEmitTbExitIfGprIsZero<kIemNativeLabelType_RaiseDe>(pReNative, off, idxVarReg, false /*f64Bit*/);
    29552960    iemNativeVarRegisterRelease(pReNative, idxVar);
    29562961
     
    29912996
    29922997    uint8_t const idxVarReg = iemNativeVarRegisterAcquire(pReNative, idxVarEffAddr, &off);
    2993     off = iemNativeEmitTestAnyBitsInGprAndTbExitIfAnySet(pReNative, off, idxVarReg, cbAlign - 1,
    2994                                                          kIemNativeLabelType_RaiseGp0);
     2998    off = iemNativeEmitTbExitIfAnyBitsSetInGpr<kIemNativeLabelType_RaiseGp0>(pReNative, off, idxVarReg, cbAlign - 1);
    29952999    iemNativeVarRegisterRelease(pReNative, idxVarEffAddr);
    29963000
     
    43354339     * Make the call and update the return code variable if we've got one.
    43364340     */
    4337     off = iemNativeEmitCallImm(pReNative, off, pfnAImpl);
     4341    off = iemNativeEmitCallImm<true /*a_fSkipEflChecks*/>(pReNative, off, pfnAImpl);
    43384342    if (idxVarRc != UINT8_MAX)
    43394343        iemNativeVarRegisterSet(pReNative, idxVarRc, IEMNATIVE_CALL_RET_GREG, off, false /*fAllocated*/);
     
    58655869# else
    58665870        PCIEMLIVENESSENTRY const pLivenessEntry       = &pReNative->paLivenessEntries[pReNative->idxCurCall];
    5867         IEMLIVENESSBIT const     LivenessClobbered    =
    5868         {
    5869               pLivenessEntry->aBits[IEMLIVENESS_BIT_WRITE].bm64
    5870             & ~(  pLivenessEntry->aBits[IEMLIVENESS_BIT_POTENTIAL_CALL].bm64
    5871                 | pLivenessEntry->aBits[IEMLIVENESS_BIT_READ].bm64
    5872                 | pLivenessEntry->aBits[IEMLIVENESS_BIT_CALL].bm64)
    5873         };
    5874         IEMLIVENESSBIT const     LivenessDelayable =
    5875         {
    5876               pLivenessEntry->aBits[IEMLIVENESS_BIT_POTENTIAL_CALL].bm64
    5877             & pLivenessEntry->aBits[IEMLIVENESS_BIT_WRITE].bm64
    5878             & ~(  pLivenessEntry->aBits[IEMLIVENESS_BIT_READ].bm64
    5879                 | pLivenessEntry->aBits[IEMLIVENESS_BIT_CALL].bm64)
    5880         };
     5871        IEMLIVENESSBIT const     LivenessClobbered    = { IEMLIVENESS_STATE_GET_WILL_BE_CLOBBERED_SET(pLivenessEntry) };
     5872        IEMLIVENESSBIT const     LivenessDelayable    = { IEMLIVENESS_STATE_GET_CAN_BE_POSTPONED_SET(pLivenessEntry)  };
    58815873#  define CHECK_FLAG_AND_UPDATE_STATS(a_fEfl, a_fLivenessMember, a_CoreStatName) \
    58825874            if (fEflOutput & (a_fEfl)) \
     
    59895981#define IEM_MC_COMMIT_EFLAGS_EX(a_EFlags, a_fEflInput, a_fEflOutput) \
    59905982    IEMNATIVE_EFLAGS_OPTIMIZATION_STATS(a_fEflInput, a_fEflOutput); \
    5991     off = iemNativeEmitCommitEFlags<true /*fUpdateSkipping*/, a_fEflOutput, \
     5983    off = iemNativeEmitCommitEFlags<true /*a_fUpdateSkippingAndPostponing*/, a_fEflOutput, \
    59925984                                    iemNativeEflagsToLivenessMask<a_fEflInput>(), \
    59935985                                    iemNativeEflagsToLivenessMask<a_fEflOutput>()>(pReNative, off, a_EFlags, a_fEflInput)
     
    59965988#define IEM_MC_COMMIT_EFLAGS_OPT_EX(a_EFlags, a_fEflInput, a_fEflOutput) \
    59975989    IEMNATIVE_EFLAGS_OPTIMIZATION_STATS(a_fEflInput, a_fEflOutput); \
    5998     off = iemNativeEmitCommitEFlags<false /*fUpdateSkipping*/, a_fEflOutput, \
     5990    off = iemNativeEmitCommitEFlags<false /*a_fUpdateSkippingAndPostponing*/, a_fEflOutput, \
    59995991                                    iemNativeEflagsToLivenessMask<a_fEflInput>(), \
    60005992                                    iemNativeEflagsToLivenessMask<a_fEflOutput>()>(pReNative, off, a_EFlags, a_fEflInput)
    60015993
    60025994/** Handles IEM_MC_COMMIT_EFLAGS_EX. */
    6003 template<bool const a_fUpdateSkipping, uint32_t const a_fEflOutput,
     5995template<bool const a_fUpdateSkippingAndPostponing, uint32_t const a_fEflOutput,
    60045996         uint64_t const a_fLivenessEflInputBits, uint64_t const a_fLivenessEflOutputBits>
    60055997DECL_INLINE_THROW(uint32_t)
     
    60526044
    60536045#ifdef IEMNATIVE_WITH_EFLAGS_SKIPPING
    6054     if RT_CONSTEXPR_IF(a_fUpdateSkipping)
     6046    if RT_CONSTEXPR_IF(a_fUpdateSkippingAndPostponing)
    60556047    {
    60566048        Assert(!(pReNative->fSkippingEFlags & fElfInput)); RT_NOREF(fElfInput);
     
    60666058                                                 RT_UOFFSETOF(VMCPU, iem.s.fSkippingEFlags));
    60676059# endif
     6060        IEMNATIVE_CLEAR_POSTPONED_EFLAGS(pReNative, a_fEflOutput);
    60686061    }
    60696062#endif
     
    62526245#define IEM_MC_REF_EFLAGS_EX(a_pEFlags, a_fEflInput, a_fEflOutput) \
    62536246    IEMNATIVE_EFLAGS_OPTIMIZATION_STATS(a_fEflInput, a_fEflOutput); \
    6254     off = iemNativeEmitRefEFlags(pReNative, off, a_pEFlags, a_fEflInput, a_fEflOutput)
     6247    off = iemNativeEmitRefEFlags<a_fEflOutput>(pReNative, off, a_pEFlags, a_fEflInput)
    62556248
    62566249/** Handles IEM_MC_REF_EFLAGS. */
    6257 DECL_INLINE_THROW(uint32_t)
    6258 iemNativeEmitRefEFlags(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t idxVarRef, uint32_t fEflInput, uint32_t fEflOutput)
     6250template<uint32_t const a_fEflOutput>
     6251DECL_INLINE_THROW(uint32_t)
     6252iemNativeEmitRefEFlags(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t idxVarRef, uint32_t fEflInput)
    62596253{
    62606254    iemNativeVarSetKindToGstRegRef(pReNative, idxVarRef, kIemNativeGstRegRef_EFlags, 0);
     
    62646258    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_AND_POSTPONING(pReNative,  fEflInput);
    62656259    IEMNATIVE_STRICT_EFLAGS_SKIPPING_EMIT_CHECK(pReNative, off, fEflInput);
    6266     pReNative->fSkippingEFlags &= ~fEflOutput;
     6260    pReNative->fSkippingEFlags &= ~a_fEflOutput;
    62676261# ifdef IEMNATIVE_STRICT_EFLAGS_SKIPPING
    62686262
    62696263    /* Updating the skipping according to the outputs is a little early, but
    62706264       we don't have any other hooks for references atm. */
    6271     if ((fEflOutput & X86_EFL_STATUS_BITS) == X86_EFL_STATUS_BITS)
     6265    if RT_CONSTEXPR((a_fEflOutput & X86_EFL_STATUS_BITS) == X86_EFL_STATUS_BITS)
    62726266        off = iemNativeEmitStoreImmToVCpuU32(pReNative, off, 0, RT_UOFFSETOF(VMCPU, iem.s.fSkippingEFlags));
    6273     else if (fEflOutput & X86_EFL_STATUS_BITS)
    6274         off = iemNativeEmitAndImmIntoVCpuU32(pReNative, off, ~(fEflOutput & X86_EFL_STATUS_BITS),
     6267    else if RT_CONSTEXPR((a_fEflOutput & X86_EFL_STATUS_BITS) != 0)
     6268        off = iemNativeEmitAndImmIntoVCpuU32(pReNative, off, ~(a_fEflOutput & X86_EFL_STATUS_BITS),
    62756269                                             RT_UOFFSETOF(VMCPU, iem.s.fSkippingEFlags));
    62766270# endif
    6277 #endif
    6278     RT_NOREF(fEflInput, fEflOutput);
     6271
     6272    /* This ASSUMES that EFLAGS references are not taken before use. */
     6273    IEMNATIVE_CLEAR_POSTPONED_EFLAGS(pReNative, a_fEflOutput);
     6274
     6275#endif
     6276    RT_NOREF(fEflInput);
    62796277
    62806278    /* If we've delayed writing back the register value, flush it now. */
     
    1105511053     * Make the call.
    1105611054     */
    11057     off = iemNativeEmitCallImm(pReNative, off, pfnAImpl);
     11055    off = iemNativeEmitCallImm<true /*a_fSkipEflChecks*/>(pReNative, off, pfnAImpl);
    1105811056
    1105911057    /*
     
    1109711095    /* tmp &= mxcsr */
    1109811096    off = iemNativeEmitAndGpr32ByGpr32(pReNative, off, idxRegTmp, idxRegTmp2);
    11099     off = iemNativeEmitTestAnyBitsInGprAndTbExitIfAnySet(pReNative, off, idxRegTmp, X86_MXCSR_XCPT_FLAGS,
    11100                                                          kIemNativeLabelType_RaiseSseAvxFpRelated);
     11097    off = iemNativeEmitTbExitIfAnyBitsSetInGpr<kIemNativeLabelType_RaiseSseAvxFpRelated>(pReNative, off, idxRegTmp,
     11098                                                                                         X86_MXCSR_XCPT_FLAGS);
    1110111099
    1110211100    iemNativeRegFreeTmp(pReNative, idxRegTmp2);
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp

    r106136 r106180  
    99 *      - Level 3  (Log3) : Disassemble native code after recompiling.
    1010 *      - Level 4  (Log4) : Delayed PC updating.
    11  *      - Level 5  (Log5) : ...
     11 *      - Level 5  (Log5) : Postponed and skipped EFLAGS calculations.
    1212 *      - Level 6  (Log6) : ...
    1313 *      - Level 7  (Log7) : ...
     
    7878#include "IEMN8veRecompilerTlbLookup.h"
    7979#include "IEMNativeFunctions.h"
     80#include "target-x86/IEMAllN8veEmit-x86.h"
    8081
    8182
     
    20702071#endif
    20712072#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
    2072     pReNative->fPostponingEFlags           = 0;
     2073    pReNative->PostponedEfl.fEFlags        = 0;
     2074    pReNative->PostponedEfl.enmOp          = kIemNativePostponedEflOp_Invalid;
     2075    pReNative->PostponedEfl.cOpBits        = 0;
     2076    pReNative->PostponedEfl.idxReg1        = UINT8_MAX;
     2077    pReNative->PostponedEfl.idxReg2        = UINT8_MAX;
    20732078#endif
    20742079
     
    64426447
    64436448    /* Jump to non-zero status return path. */
    6444     off = iemNativeEmitJnzTbExit(pReNative, off, kIemNativeLabelType_NonZeroRetOrPassUp);
     6449    off = iemNativeEmitTbExitJnz<kIemNativeLabelType_NonZeroRetOrPassUp>(pReNative, off);
    64456450
    64466451    /* done. */
     
    64506455     * ARM64: w0 = call status code.
    64516456     */
     6457    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1+3+3 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     6458
    64526459# ifdef IEMNATIVE_WITH_INSTRUCTION_COUNTING
    6453     off = iemNativeEmitLoadGprImm64(pReNative, off, ARMV8_A64_REG_X2, idxInstr);
     6460    AssertCompile(ARMV8_A64_REG_X2 == IEMNATIVE_CALL_ARG2_GREG);
     6461    off = iemNativeEmitLoadGprImmEx(pCodeBuf, off, ARMV8_A64_REG_X2, idxInstr);
    64546462# endif
    6455     off = iemNativeEmitLoadGprFromVCpuU32(pReNative, off, ARMV8_A64_REG_X3, RT_UOFFSETOF(VMCPUCC, iem.s.rcPassUp));
    6456 
    6457     uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3);
    6458 
    6459     pu32CodeBuf[off++] = Armv8A64MkInstrOrr(ARMV8_A64_REG_X4, ARMV8_A64_REG_X3, ARMV8_A64_REG_X0, false /*f64Bit*/);
    6460 
    6461     off = iemNativeEmitTestIfGprIsNotZeroAndTbExitEx(pReNative, pu32CodeBuf, off, ARMV8_A64_REG_X4, true /*f64Bit*/,
    6462                                                      kIemNativeLabelType_NonZeroRetOrPassUp);
     6463    off = iemNativeEmitLoadGprFromVCpuU32Ex(pCodeBuf, off, ARMV8_A64_REG_X3, RT_UOFFSETOF(VMCPUCC, iem.s.rcPassUp));
     6464
     6465    pCodeBuf[off++] = Armv8A64MkInstrOrr(ARMV8_A64_REG_X4, ARMV8_A64_REG_X3, ARMV8_A64_REG_X0, false /*f64Bit*/);
     6466
     6467    off = iemNativeEmitTbExitIfGprIsNotZeroEx<kIemNativeLabelType_NonZeroRetOrPassUp>(pReNative, pCodeBuf, off,
     6468                                                                                      ARMV8_A64_REG_X4, true /*f64Bit*/);
    64636469
    64646470#else
     
    99909996                    = szSegSel[X86_SREG_COUNT] = '\0';
    99919997
    9992                 char szEFlags[8];
    9993                 for (unsigned i = 0; i < 7; i++)
     9998                char szEFlags[IEMLIVENESSBIT_IDX_EFL_COUNT + 1];
     9999                for (unsigned i = 0; i < IEMLIVENESSBIT_IDX_EFL_COUNT; i++)
    999410000                    szEFlags[i] = s_achState[iemNativeLivenessGetStateByGstRegEx(pLivenessEntry, i + kIemNativeGstReg_EFlags)];
    999510001                szEFlags[7] = '\0';
    999610002
    9997                 Log2(("liveness: grp=%s segbase=%s segattr=%s seglim=%s segsel=%s efl=%s\n",
     10003                Log2(("liveness: gpr=%s segbase=%s segattr=%s seglim=%s segsel=%s efl=%s\n",
    999810004                      szGpr, szSegBase, szSegAttrib, szSegLimit, szSegSel, szEFlags));
    999910005            }
     
    1002710033         */
    1002810034        //off = iemNativeEmitBrk(pReNative, off, 0x1227);
    10029         off = iemNativeEmitTbExit(pReNative, off, kIemNativeLabelType_ReturnSuccess);
     10035        off = iemNativeEmitTbExit<kIemNativeLabelType_ReturnSuccess, true, false>(pReNative, off);
    1003010036
    1003110037        /*
     
    1003910045        if (fTailLabels)
    1004010046        {
     10047            PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, kIemNativeLabelType_LastTbExit + 1);
    1004110048            do
    1004210049            {
     
    1004710054                AssertContinue(idxLabel != UINT32_MAX);
    1004810055                iemNativeLabelDefine(pReNative, idxLabel, off);
    10049                 off = iemNativeEmitTbExit(pReNative, off, enmLabel);
     10056
     10057                iemNativeAddTbExitFixup(pReNative, off, enmLabel);
     10058# ifdef RT_ARCH_ARM64
     10059                pCodeBuf[off++] = Armv8A64MkInstrB(-1);
     10060# else
     10061#  error "port me"
     10062# endif
    1005010063            } while (fTailLabels);
     10064            IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    1005110065        }
    1005210066#else
  • trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllN8veEmit-x86.h

    r106123 r106180  
    195195#endif /* RT_ARCH_AMD64 */
    196196
     197
     198
     199/*********************************************************************************************************************************
     200*   EFLAGS                                                                                                                       *
     201*********************************************************************************************************************************/
     202
     203#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     204
     205/** @def IEMNATIVE_POSTPONING_REG_MASK
     206 * Register suitable for keeping the inputs or result for a postponed EFLAGS
     207 * calculation.
     208 *
     209 * We use non-volatile register here so we don't have to save & restore them
     210 * accross callouts (i.e. TLB loads).
     211 *
     212 * @note  On x86 we cannot use RDI and RSI because these are used by the
     213 *        opcode checking code.  The usual joy of the x86 instruction set.
     214 */
     215# ifdef RT_ARCH_AMD64
     216#  define IEMNATIVE_POSTPONING_REG_MASK \
     217    (IEMNATIVE_CALL_NONVOLATILE_GREG_MASK & ~(RT_BIT_32(X86_GREG_xDI) | RT_BIT_32(X86_GREG_xSI)))
     218# else
     219#  define IEMNATIVE_POSTPONING_REG_MASK     IEMNATIVE_CALL_NONVOLATILE_GREG_MASK
     220# endif
     221
     222/**
     223 * This is normally invoked via IEMNATIVE_CLEAR_POSTPONED_EFLAGS().
     224 */
     225template<uint32_t const a_fEflClobbered>
     226DECL_FORCE_INLINE(void) iemNativeClearPostponedEFlags(PIEMRECOMPILERSTATE pReNative)
     227{
     228    AssertCompile(!(a_fEflClobbered & ~X86_EFL_STATUS_BITS));
     229    uint32_t fEFlags = pReNative->PostponedEfl.fEFlags;
     230    if (fEFlags)
     231    {
     232        if RT_CONSTEXPR(a_fEflClobbered != X86_EFL_STATUS_BITS)
     233        {
     234            fEFlags &= ~a_fEflClobbered;
     235            if (!fEFlags)
     236            { /* likely */ }
     237            else
     238            {
     239                Log5(("iemNativeClearPostponedEFlags: Clobbering %#x: %#x -> %#x (op=%d bits=%u)\n", a_fEflClobbered,
     240                      pReNative->PostponedEfl.fEFlags, fEFlags, pReNative->PostponedEfl.enmOp, pReNative->PostponedEfl.cOpBits));
     241                pReNative->PostponedEfl.fEFlags = fEFlags;
     242                return;
     243            }
     244        }
     245
     246        /* Do cleanup.  */
     247        Log5(("iemNativeClearPostponedEFlags: Cleanup of op=%u bits=%u efl=%#x upon clobbering %#x\n",
     248              pReNative->PostponedEfl.enmOp, pReNative->PostponedEfl.cOpBits, pReNative->PostponedEfl.fEFlags, a_fEflClobbered));
     249        pReNative->PostponedEfl.fEFlags = 0;
     250        pReNative->PostponedEfl.enmOp   = kIemNativePostponedEflOp_Invalid;
     251        pReNative->PostponedEfl.cOpBits = 0;
     252        iemNativeRegFreeTmp(pReNative, pReNative->PostponedEfl.idxReg1);
     253        if (pReNative->PostponedEfl.idxReg2 != UINT8_MAX)
     254            iemNativeRegFreeTmp(pReNative, pReNative->PostponedEfl.idxReg2);
     255        pReNative->PostponedEfl.idxReg1 = UINT8_MAX;
     256        pReNative->PostponedEfl.idxReg2 = UINT8_MAX;
     257    }
     258}
     259
     260DECL_INLINE_THROW(uint32_t) iemNativeEmitPostponedEFlagsCalcLogical(PIEMNATIVEINSTR pCodeBuf, uint32_t off, uint8_t cOpBits,
     261                                                                    uint8_t idxRegResult, uint8_t idxRegEfl, uint8_t idxRegTmp)
     262{
     263#ifdef RT_ARCH_AMD64
     264    /*
     265     * Do an AND and collect flags and merge them with eflags.
     266     */
     267    /* Do TEST idxRegResult, idxRegResult to set flags. */
     268    off = iemNativeEmitAmd64OneByteModRmInstrRREx(pCodeBuf, off, 0x84, 0x85, cOpBits, idxRegResult, idxRegResult);
     269
     270    if (idxRegTmp == X86_GREG_xAX)
     271    {
     272        /* sahf ; AH = EFLAGS */
     273        pCodeBuf[off++] = 0x9e;
     274        if (idxRegEfl <= X86_GREG_xBX)
     275        {
     276            /* mov [CDB]L, AH */
     277            pCodeBuf[off++] = 0x88;
     278            pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4 /*AH*/, idxRegEfl);
     279        }
     280        else
     281        {
     282            /* mov   AL, AH */
     283            pCodeBuf[off++] = 0x88;
     284            pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4 /*AH*/, 0 /*AL*/);
     285            /* mov   xxL, AL */
     286            pCodeBuf[off++] = idxRegEfl >= 8 ? X86_OP_REX_B : X86_OP_REX;
     287            pCodeBuf[off++] = 0x88;
     288            pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 0 /*AL*/, idxRegEfl & 7);
     289        }
     290    }
     291    else if (idxRegEfl != X86_GREG_xAX)
     292    {
     293        /* pushf */
     294        pCodeBuf[off++] = 0x9c;
     295        /* pop  tmp */
     296        if (idxRegTmp >= 8)
     297            pCodeBuf[off++] = X86_OP_REX_B;
     298        pCodeBuf[off++] = 0x58 + (idxRegTmp & 7);
     299        /* mov   byte(efl), byte(tmp) */
     300        pCodeBuf[off++] = (idxRegEfl >= 8 ? X86_OP_REX_B : X86_OP_REX)
     301                        | (idxRegTmp >= 8 ? X86_OP_REX_R : 0);
     302        pCodeBuf[off++] = 0x88;
     303        pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxRegTmp & 7, idxRegEfl & 7);
     304    }
     305    else
     306    {
     307        /* xchg al, ah  */
     308        pCodeBuf[off++] = 0x86;
     309        pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4 /*AH*/, 0 /*AL*/);
     310        /* sahf ; AH = EFLAGS */
     311        pCodeBuf[off++] = 0x9e;
     312        /* xchg al, ah  */
     313        pCodeBuf[off++] = 0x86;
     314        pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4 /*AH*/, 0 /*AL*/);
     315    }
     316    /* BTC idxEfl, 11; Clear OF */
     317    if (idxRegEfl >= 8)
     318        pCodeBuf[off++] = X86_OP_REX_B;
     319    pCodeBuf[off++] = 0xf;
     320    pCodeBuf[off++] = 0xba;
     321    pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 7, idxRegEfl & 7);
     322    pCodeBuf[off++] = X86_EFL_OF_BIT;
     323
     324#elif defined(RT_ARCH_ARM64)
     325    /*
     326     * Calculate flags.
     327     */
     328    /* Clear the status bits. ~0x8D5 (or ~0x8FD) can't be AND immediate, so use idxRegTmp for constant. */
     329    off = iemNativeEmitLoadGpr32ImmExT<~X86_EFL_STATUS_BITS>(pCodeBuf, off, idxRegTmp);
     330    off = iemNativeEmitAndGpr32ByGpr32Ex(pCodeBuf, off, idxRegEfl, idxRegTmp);
     331
     332    /* N,Z -> SF,ZF */
     333    if (cOpBits < 32)
     334        pCodeBuf[off++] = Armv8A64MkInstrSetF8SetF16(idxRegResult, cOpBits > 8); /* sets NZ */
     335    else
     336        pCodeBuf[off++] = Armv8A64MkInstrAnds(ARMV8_A64_REG_XZR, idxRegResult, idxRegResult, cOpBits > 32 /*f64Bit*/);
     337    pCodeBuf[off++] = Armv8A64MkInstrMrs(idxRegTmp, ARMV8_AARCH64_SYSREG_NZCV); /* Bits: 31=N; 30=Z; 29=C; 28=V; */
     338    pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxRegTmp, idxRegTmp, 30);
     339    pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxRegTmp, X86_EFL_ZF_BIT, 2, false /*f64Bit*/);
     340    AssertCompile(X86_EFL_ZF_BIT + 1 == X86_EFL_SF_BIT);
     341
     342    /* Calculate 8-bit parity of the result. */
     343    pCodeBuf[off++] = Armv8A64MkInstrEor(idxRegTmp, idxRegResult, idxRegResult, false /*f64Bit*/,
     344                                         4 /*offShift6*/, kArmv8A64InstrShift_Lsr);
     345    pCodeBuf[off++] = Armv8A64MkInstrEor(idxRegTmp, idxRegTmp,    idxRegTmp,    false /*f64Bit*/,
     346                                         2 /*offShift6*/, kArmv8A64InstrShift_Lsr);
     347    pCodeBuf[off++] = Armv8A64MkInstrEor(idxRegTmp, idxRegTmp,    idxRegTmp,    false /*f64Bit*/,
     348                                         1 /*offShift6*/, kArmv8A64InstrShift_Lsr);
     349    Assert(Armv8A64ConvertImmRImmS2Mask32(0, 0) == 1);
     350    pCodeBuf[off++] = Armv8A64MkInstrEorImm(idxRegTmp, idxRegTmp, 0, 0, false /*f64Bit*/);
     351    pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxRegTmp, X86_EFL_PF_BIT, 1, false /*f64Bit*/);
     352
     353#else
     354# error "port me"
     355#endif
     356    return off;
     357}
     358
     359
     360template<uint32_t const a_bmInputRegs>
     361static uint32_t iemNativeDoPostponedEFlagsAtTbExitInternal(PIEMRECOMPILERSTATE pReNative, uint32_t off, PIEMNATIVEINSTR pCodeBuf)
     362{
     363    /*
     364     * We can't do regular register allocations here, but since we're in an exit
     365     * path where all pending writes has been flushed and we have a known set of
     366     * registers with input for the exit label, we do our own simple stuff here.
     367     *
     368     * Note! On x86 we prefer using RAX as the first TMP register, so we can
     369     *       make use of LAHF which is typically faster than PUSHF/POP.  This
     370     *       is why the idxRegTmp allocation is first when there is no EFLAG
     371     *       shadow, since RAX is represented by bit 0 in the mask.
     372     */
     373    uint32_t bmAvailableRegs = ~(a_bmInputRegs | IEMNATIVE_REG_FIXED_MASK) & IEMNATIVE_HST_GREG_MASK;
     374    if (pReNative->PostponedEfl.idxReg2 != UINT8_MAX)
     375        bmAvailableRegs &= ~(RT_BIT_32(pReNative->PostponedEfl.idxReg1) | RT_BIT_32(pReNative->PostponedEfl.idxReg2));
     376    else
     377        bmAvailableRegs &= ~RT_BIT_32(pReNative->PostponedEfl.idxReg1);
     378
     379    /* Use existing EFLAGS shadow if available. */
     380    uint8_t idxRegEfl, idxRegTmp;
     381    if (pReNative->Core.bmGstRegShadowDirty & RT_BIT_64(kIemNativeGstReg_EFlags))
     382    {
     383        idxRegEfl = pReNative->Core.aidxGstRegShadows[kIemNativeGstReg_EFlags];
     384        Assert(idxRegEfl < IEMNATIVE_HST_GREG_COUNT && (bmAvailableRegs & RT_BIT_32(idxRegEfl)));
     385        bmAvailableRegs &= ~RT_BIT_32(idxRegEfl);
     386#ifdef VBOX_STRICT
     387        /** @todo check shadow register content. */
     388#endif
     389
     390        idxRegTmp = ASMBitFirstSetU32(bmAvailableRegs) - 1;
     391        bmAvailableRegs &= ~RT_BIT_32(idxRegTmp);
     392    }
     393    else
     394    {
     395        idxRegTmp = ASMBitFirstSetU32(bmAvailableRegs) - 1; /* allocate the temp register first to prioritize EAX on x86. */
     396        bmAvailableRegs &= ~RT_BIT_32(idxRegTmp);
     397
     398        idxRegEfl = ASMBitFirstSetU32(bmAvailableRegs) - 1;
     399        bmAvailableRegs &= ~RT_BIT_32(idxRegTmp);
     400        off = iemNativeEmitLoadGprFromVCpuU32Ex(pCodeBuf, off, idxRegEfl, RT_UOFFSETOF(VMCPU, cpum.GstCtx.eflags));
     401    }
     402    Assert(bmAvailableRegs != 0);
     403
     404    /*
     405     * Do the actual EFLAGS calculation.
     406     */
     407    switch (pReNative->PostponedEfl.enmOp)
     408    {
     409        case kIemNativePostponedEflOp_Logical:
     410            Assert(pReNative->PostponedEfl.idxReg2 == UINT8_MAX);
     411            off = iemNativeEmitPostponedEFlagsCalcLogical(pCodeBuf, off, pReNative->PostponedEfl.cOpBits,
     412                                                          pReNative->PostponedEfl.idxReg1, idxRegEfl, idxRegTmp);
     413            break;
     414
     415        default:
     416            AssertFailedBreak();
     417    }
     418
     419    /*
     420     * Store EFLAGS.
     421     */
     422    off = iemNativeEmitStoreGprToVCpuU32Ex(pCodeBuf, off, idxRegEfl, RT_UOFFSETOF(VMCPU, cpum.GstCtx.eflags));
     423    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     424
     425    return off;
     426}
     427
     428
     429
     430template<uint32_t const a_bmInputRegs>
     431DECL_FORCE_INLINE_THROW(uint32_t)
     432iemNativeDoPostponedEFlagsAtTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off)
     433{
     434    if (pReNative->PostponedEfl.fEFlags)
     435    {
     436        PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     437        return iemNativeDoPostponedEFlagsAtTbExitInternal<a_bmInputRegs>(pReNative, off, pCodeBuf);
     438    }
     439    return off;
     440}
     441
     442
     443template<uint32_t const a_bmInputRegs>
     444DECL_FORCE_INLINE_THROW(uint32_t)
     445iemNativeDoPostponedEFlagsAtTbExitEx(PIEMRECOMPILERSTATE pReNative, uint32_t off, PIEMNATIVEINSTR pCodeBuf)
     446{
     447    if (pReNative->PostponedEfl.fEFlags)
     448        return iemNativeDoPostponedEFlagsAtTbExitInternal<a_bmInputRegs>(pReNative, off, pCodeBuf);
     449    return off;
     450}
     451
     452
     453#endif /* IEMNATIVE_WITH_EFLAGS_POSTPONING */
     454
     455
    197456/**
    198457 * This is an implementation of IEM_EFL_UPDATE_STATUS_BITS_FOR_LOGICAL.
     
    201460 */
    202461DECL_INLINE_THROW(uint32_t)
    203 iemNativeEmitEFlagsForLogical(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t idxVarEfl
     462iemNativeEmitEFlagsForLogical(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t idxVarEfl,
     463                              uint8_t cOpBits, uint8_t idxRegResult
    204464#ifndef RT_ARCH_AMD64
    205                               , uint8_t cOpBits, uint8_t idxRegResult, bool fNativeFlags = false
     465                              , bool fNativeFlags = false
    206466#endif
    207467                              )
    208468{
    209469    STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativeEflTotalLogical);
     470    IEMNATIVE_CLEAR_POSTPONED_EFLAGS(pReNative, X86_EFL_STATUS_BITS);
     471    RT_NOREF(cOpBits, idxRegResult);
    210472
    211473#ifdef IEMNATIVE_WITH_EFLAGS_SKIPPING
     
    214476     */
    215477    PCIEMLIVENESSENTRY const pLivenessEntry = &pReNative->paLivenessEntries[pReNative->idxCurCall];
    216     if (   IEMLIVENESS_STATE_ARE_STATUS_EFL_TO_BE_CLOBBERED(pLivenessEntry)
     478    uint64_t const           fEflClobbered  = IEMLIVENESS_STATE_GET_WILL_BE_CLOBBERED_SET(pLivenessEntry)
     479                                            & IEMLIVENESSBIT_STATUS_EFL_MASK;
     480# ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     481    uint64_t                 fEflPostponing;
     482# endif
     483    if (   fEflClobbered == IEMLIVENESSBIT_STATUS_EFL_MASK
    217484        && !(pReNative->fMc & IEM_MC_F_WITH_FLAGS))
    218485    {
     
    222489        off = iemNativeEmitOrImmIntoVCpuU32(pReNative, off, X86_EFL_STATUS_BITS, RT_UOFFSETOF(VMCPU, iem.s.fSkippingEFlags));
    223490# endif
    224     }
     491        Log5(("iemNativeEmitEFlagsForLogical: Skipping %#x\n", X86_EFL_STATUS_BITS));
     492    }
     493# ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     494    else if (      (  (fEflPostponing = IEMLIVENESS_STATE_GET_CAN_BE_POSTPONED_SET(pLivenessEntry) & IEMLIVENESSBIT_STATUS_EFL_MASK)
     495                    | fEflClobbered)
     496                == IEMLIVENESSBIT_STATUS_EFL_MASK
     497             && idxRegResult != UINT8_MAX)
     498    {
     499        STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativeEflPostponedLogical);
     500        pReNative->fSkippingEFlags       = 0;
     501        pReNative->PostponedEfl.fEFlags  = X86_EFL_STATUS_BITS;
     502        pReNative->PostponedEfl.enmOp    = kIemNativePostponedEflOp_Logical;
     503        pReNative->PostponedEfl.cOpBits  = cOpBits;
     504        pReNative->PostponedEfl.idxReg1  = iemNativeRegAllocTmpEx(pReNative, &off, IEMNATIVE_POSTPONING_REG_MASK, false);
     505        /** @todo it would normally be possible to use idxRegResult, iff it is
     506         *        already a non-volatile register and we can be user the caller
     507         *        doesn't modify it.  That'll save a register move and allocation. */
     508        off = iemNativeEmitLoadGprFromGpr(pReNative, off, pReNative->PostponedEfl.idxReg1, idxRegResult);
     509        Log5(("iemNativeEmitEFlagsForLogical: Postponing %#x op=%u bits=%u reg1=%u\n", X86_EFL_STATUS_BITS,
     510              kIemNativePostponedEflOp_Logical, cOpBits, pReNative->PostponedEfl.idxReg1));
     511    }
     512# endif
    225513    else
    226514#endif
     
    317605{
    318606    STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativeEflTotalArithmetic);
     607    IEMNATIVE_CLEAR_POSTPONED_EFLAGS(pReNative, X86_EFL_STATUS_BITS);
    319608
    320609#ifdef IEMNATIVE_WITH_EFLAGS_SKIPPING
     
    504793
    505794
     795
     796/*********************************************************************************************************************************
     797*   Bitwise Logical Operations                                                                                                   *
     798*********************************************************************************************************************************/
     799
    506800/**
    507801 * The AND instruction will clear OF, CF and AF (latter is undefined) and
     
    521815    iemNativeVarRegisterRelease(pReNative, idxVarSrc);
    522816
    523     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     817    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
    524818
    525819#elif defined(RT_ARCH_ARM64)
     
    553847    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    554848
    555     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     849    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
    556850
    557851#elif defined(RT_ARCH_ARM64)
     
    628922
    629923#ifdef RT_ARCH_AMD64
    630     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     924    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, UINT8_MAX);
    631925#else
    632926    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegResult, cOpBits >= 32 /*fNativeFlags*/);
     
    652946    iemNativeVarRegisterRelease(pReNative, idxVarDst);
    653947
    654     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     948    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, UINT8_MAX);
    655949
    656950#elif defined(RT_ARCH_ARM64)
     
    7121006    iemNativeVarRegisterRelease(pReNative, idxVarSrc);
    7131007
    714     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     1008    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
    7151009
    7161010#elif defined(RT_ARCH_ARM64)
     
    7451039    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    7461040
    747     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     1041    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
    7481042
    7491043#elif defined(RT_ARCH_ARM64)
     
    7951089    iemNativeVarRegisterRelease(pReNative, idxVarSrc);
    7961090
    797     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     1091    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
    7981092
    7991093#elif defined(RT_ARCH_ARM64)
     
    8281122    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    8291123
    830     off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl);
     1124    off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
    8311125
    8321126#elif defined(RT_ARCH_ARM64)
     
    27333027    /* tmp &= mxcsr */
    27343028    off = iemNativeEmitAndGpr32ByGpr32(pReNative, off, idxRegMxCsrXcptFlags, idxRegTmp);
    2735     off = iemNativeEmitTestAnyBitsInGprAndTbExitIfAnySet(pReNative, off, idxRegMxCsrXcptFlags, X86_MXCSR_XCPT_FLAGS,
    2736                                                          kIemNativeLabelType_RaiseSseAvxFpRelated);
     3029    off = iemNativeEmitTbExitIfAnyBitsSetInGpr<kIemNativeLabelType_RaiseSseAvxFpRelated>(pReNative, off, idxRegMxCsrXcptFlags,
     3030                                                                                         X86_MXCSR_XCPT_FLAGS);
    27373031
    27383032    uint8_t const idxSimdRegDst = iemNativeSimdRegAllocTmpForGuestSimdReg(pReNative, &off, IEMNATIVEGSTSIMDREG_SIMD(idxSimdGstRegDst),
  • trunk/src/VBox/VMM/VMMR3/IEMR3.cpp

    r106101 r106180  
    731731                        "/IEM/CPU%u/re/NativeRegFindFreeLivenessHelped", idCpu);
    732732
    733         STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedArithmetic,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    734                         "Skipped all status flag updating, arithmetic instructions",
    735                         "/IEM/CPU%u/re/NativeEFlags/ArithmeticSkipped", idCpu);
    736         STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotalArithmetic,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    737                         "Total number of arithmetic intructions with status flag updating",
    738                         "/IEM/CPU%u/re/NativeEFlags/ArithmeticTotal", idCpu);
    739         RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/ArithmeticTotal", idCpu);
    740         RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/ArithmeticSkipped", idCpu);
    741         STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
    742                                "Skipped all status flag updating, arithmetic instructions, percentage",
    743                                "/IEM/CPU%u/re/NativeEFlags/ArithmeticSkippedPct", idCpu);
    744 
    745         STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedLogical,         STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    746                         "Skipped all status flag updating, logical instructions",
    747                         "/IEM/CPU%u/re/NativeEFlags/LogicalSkipped", idCpu);
    748         STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotalLogical,           STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    749                         "Total number of logical intructions with status flag updating",
    750                         "/IEM/CPU%u/re/NativeEFlags/LogicalTotal", idCpu);
    751         RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/LogicalTotal", idCpu);
    752         RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/LogicalSkipped", idCpu);
    753         STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
    754                                "Skipped all status flag updating, logical instructions, percentage",
    755                                "/IEM/CPU%u/re/NativeEFlags/LogicalSkippedPct", idCpu);
    756 
    757         STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedShift,           STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    758                         "Skipped all status flag updating, shift instructions",
    759                         "/IEM/CPU%u/re/NativeEFlags/ShiftSkipped", idCpu);
    760         STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotalShift,             STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    761                         "Total number of shift intructions with status flag updating",
    762                         "/IEM/CPU%u/re/NativeEFlags/ShiftTotal", idCpu);
    763         RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/ShiftTotal", idCpu);
    764         RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/ShiftSkipped", idCpu);
    765         STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
    766                                "Skipped all status flag updating, shift instructions, percentage",
    767                                "/IEM/CPU%u/re/NativeEFlags/ShiftSkippedPct", idCpu);
     733#   define REG_NATIVE_EFL_GROUP(a_Lower, a_Camel) do { \
     734        STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflPostponed ## a_Camel, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, \
     735                        "Postponed all status flag updating, " #a_Lower " instructions", \
     736                        "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "Postponed", idCpu); \
     737        STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkipped ## a_Camel,   STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, \
     738                        "Skipped all status flag updating, " #a_Lower " instructions", \
     739                        "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "Skipped", idCpu); \
     740        STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotal ## a_Camel,     STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, \
     741                        "Total number of " #a_Lower " intructions with status flag updating", \
     742                        "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "Total", idCpu); \
     743        RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "Total", idCpu); \
     744        RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "Postponed", idCpu); \
     745        STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat, \
     746                               "Postponed all status flag updating, " #a_Lower " instructions, percentage", \
     747                               "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "PostponedPct", idCpu); \
     748        RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "Skipped", idCpu); \
     749        STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat, \
     750                               "Skipped all status flag updating, " #a_Lower " instructions, percentage", \
     751                               "/IEM/CPU%u/re/NativeEFlags/" #a_Camel "SkippedPct", idCpu); \
     752    } while (0)
     753        REG_NATIVE_EFL_GROUP(arithmetic, Arithmetic);
     754        REG_NATIVE_EFL_GROUP(logical,    Logical);
     755        REG_NATIVE_EFL_GROUP(shift,      Shift);
     756#   undef REG_NATIVE_EFL_GROUP
    768757
    769758        STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfSkippable,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.CF updating",       "/IEM/CPU%u/re/NativeLivenessEFlags/CfSkippable", idCpu);
  • trunk/src/VBox/VMM/include/IEMN8veRecompiler.h

    r106127 r106180  
    8080# if 0 || defined(DOXYGEN_RUNNING)
    8181#  define IEMNATIVE_WITH_EFLAGS_POSTPONING
     82# endif
     83#endif
     84#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     85# ifndef IEMNATIVE_WITH_EFLAGS_SKIPPING
     86#  error "IEMNATIVE_WITH_EFLAGS_POSTPONING requires IEMNATIVE_WITH_EFLAGS_SKIPPING at present"
    8287# endif
    8388#endif
     
    314319 * Mask of registers the callee will not save and may trash. */
    315320#ifdef RT_ARCH_AMD64
    316 # define IEMNATIVE_CALL_RET_GREG             X86_GREG_xAX
     321# define IEMNATIVE_CALL_RET_GREG            X86_GREG_xAX
    317322
    318323# ifdef RT_OS_WINDOWS
     
    435440# define IEMNATIVE_CALL_VOLATILE_NOTMP_GREG_MASK    IEMNATIVE_CALL_VOLATILE_GREG_MASK
    436441#endif
     442
     443/** @def IEMNATIVE_CALL_NONVOLATILE_GREG_MASK
     444 * The allocatable non-volatile general purpose register set.  */
     445#define IEMNATIVE_CALL_NONVOLATILE_GREG_MASK \
     446    (~IEMNATIVE_CALL_VOLATILE_GREG_MASK & ~IEMNATIVE_REG_FIXED_MASK & IEMNATIVE_HST_GREG_MASK)
    437447/** @} */
    438448
     
    480490{
    481491    kIemNativeLabelType_Invalid = 0,
    482     /*
    483      * Labels w/o data, only once instance per TB - aka exit reasons.
     492    /** @name Exit reasons - Labels w/o data, only once instance per TB.
    484493     *
    485      * Note! Jumps to these requires instructions that are capable of spanning
    486      *       the max TB length.
     494     * The labels requiring register inputs are documented.
     495     *
     496     * @note Jumps to these requires instructions that are capable of spanning the
     497     *       max TB length.
     498     * @{
    487499     */
    488500    /* Simple labels comes first for indexing reasons. RaiseXx is order by the exception's numerical value(s). */
     
    496508    kIemNativeLabelType_RaiseMf,                /**< Raise (throw) X86_XCPT_MF (10h). */
    497509    kIemNativeLabelType_RaiseXf,                /**< Raise (throw) X86_XCPT_XF (13h). */
    498     kIemNativeLabelType_ObsoleteTb,
    499     kIemNativeLabelType_NeedCsLimChecking,
    500     kIemNativeLabelType_CheckBranchMiss,
     510    kIemNativeLabelType_ObsoleteTb,             /**< Calls iemNativeHlpObsoleteTb (no inputs). */
     511    kIemNativeLabelType_NeedCsLimChecking,      /**< Calls iemNativeHlpNeedCsLimChecking (no inputs). */
     512    kIemNativeLabelType_CheckBranchMiss,        /**< Calls iemNativeHlpCheckBranchMiss (no inputs). */
    501513    kIemNativeLabelType_LastSimple = kIemNativeLabelType_CheckBranchMiss,
    502     /* Manually defined labels. */
     514
     515    /* Manually defined labels: */
     516    /**< Returns with VINF_SUCCESS, no inputs. */
     517    kIemNativeLabelType_ReturnSuccess,
     518    /** Returns with VINF_IEM_REEXEC_FINISH_WITH_FLAGS, no inputs. */
     519    kIemNativeLabelType_ReturnWithFlags,
     520    /** Returns with VINF_IEM_REEXEC_BREAK, no inputs. */
    503521    kIemNativeLabelType_ReturnBreak,
     522    /** Returns with VINF_IEM_REEXEC_BREAK_FF, no inputs. */
    504523    kIemNativeLabelType_ReturnBreakFF,
     524    /** The last TB exit label that doesn't have any input registers. */
     525    kIemNativeLabelType_LastTbExitWithoutInputs = kIemNativeLabelType_ReturnBreakFF,
     526
     527    /** Argument registers 1, 2 & 3 are set up.  */
    505528    kIemNativeLabelType_ReturnBreakViaLookup,
     529    /** Argument registers 1, 2 & 3 are set up.  */
    506530    kIemNativeLabelType_ReturnBreakViaLookupWithIrq,
     531    /** Argument registers 1 & 2 are set up.  */
    507532    kIemNativeLabelType_ReturnBreakViaLookupWithTlb,
     533    /** Argument registers 1 & 2 are set up.  */
    508534    kIemNativeLabelType_ReturnBreakViaLookupWithTlbAndIrq,
    509     kIemNativeLabelType_ReturnWithFlags,
     535    /** Return register holds the RC and the instruction number is in CL/RCX
     536     * on amd64 and the 2rd argument register elsewhere. */
    510537    kIemNativeLabelType_NonZeroRetOrPassUp,
    511     kIemNativeLabelType_ReturnSuccess,          /**< Sets eax/w0 to zero and returns. */
     538
    512539    /** The last fixup for branches that can span almost the whole TB length.
    513540     * @note Whether kIemNativeLabelType_Return needs to be one of these is
    514541     *       a bit questionable, since nobody jumps to it except other tail code. */
    515     kIemNativeLabelType_LastWholeTbBranch = kIemNativeLabelType_ReturnSuccess,
     542    kIemNativeLabelType_LastWholeTbBranch = kIemNativeLabelType_NonZeroRetOrPassUp,
    516543    /** The last fixup for branches that exits the TB. */
    517     kIemNativeLabelType_LastTbExit        = kIemNativeLabelType_ReturnSuccess,
     544    kIemNativeLabelType_LastTbExit        = kIemNativeLabelType_NonZeroRetOrPassUp,
     545    /** @} */
    518546
    519547    /** Loop-jump target. */
     
    538566#define IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmLabel) \
    539567    ((a_enmLabel) <= kIemNativeLabelType_LastTbExit && (a_enmLabel) > kIemNativeLabelType_Invalid)
     568
     569#define IEMNATIVELABELTYPE_IS_EXIT_WITHOUT_INPUTS(a_enmLabel) \
     570    ((a_enmLabel) <= kIemNativeLabelType_LastTbExitWithoutInputs && (a_enmLabel) > kIemNativeLabelType_Invalid)
     571
     572/**
     573 * Get the mask of input registers for an TB exit label.
     574 * This will return zero for any non-exit lable.
     575 */
     576#ifdef RT_ARCH_AMD64
     577# define IEMNATIVELABELTYPE_GET_INPUT_REG_MASK(a_enmLabel) \
     578    (     (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookup \
     579       || (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookupWithIrq \
     580     ? RT_BIT_32(IEMNATIVE_CALL_ARG1_GREG) | RT_BIT_32(IEMNATIVE_CALL_ARG2_GREG) | RT_BIT_32(IEMNATIVE_CALL_ARG3_GREG) \
     581     :    (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookupWithTlb \
     582       || (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookupWithTlbAndIrq \
     583     ? RT_BIT_32(IEMNATIVE_CALL_ARG1_GREG) | RT_BIT_32(IEMNATIVE_CALL_ARG2_GREG) \
     584     : (a_enmLabel) == kIemNativeLabelType_NonZeroRetOrPassUp \
     585     ? RT_BIT_32(IEMNATIVE_CALL_RET_GREG)  | RT_BIT_32(X86_GREG_xCX) /* <-- the difference */ \
     586     : 0)
     587# else
     588# define IEMNATIVELABELTYPE_GET_INPUT_REG_MASK(a_enmLabel) \
     589    (     (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookup \
     590       || (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookupWithIrq \
     591     ? RT_BIT_32(IEMNATIVE_CALL_ARG1_GREG) | RT_BIT_32(IEMNATIVE_CALL_ARG2_GREG) | RT_BIT_32(IEMNATIVE_CALL_ARG3_GREG) \
     592     :    (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookupWithTlb \
     593       || (a_enmLabel) == kIemNativeLabelType_ReturnBreakViaLookupWithTlbAndIrq \
     594     ? RT_BIT_32(IEMNATIVE_CALL_ARG1_GREG) | RT_BIT_32(IEMNATIVE_CALL_ARG2_GREG) \
     595     : (a_enmLabel) == kIemNativeLabelType_NonZeroRetOrPassUp \
     596     ? RT_BIT_32(IEMNATIVE_CALL_RET_GREG)  | RT_BIT_32(IEMNATIVE_CALL_ARG2_GREG) \
     597     : 0)
     598#endif
    540599
    541600
     
    660719#define IEMLIVENESSBIT_IDX_EFL_SF       ((unsigned)kIemNativeGstReg_EFlags + 5)
    661720#define IEMLIVENESSBIT_IDX_EFL_OF       ((unsigned)kIemNativeGstReg_EFlags + 6)
     721#define IEMLIVENESSBIT_IDX_EFL_COUNT    7
    662722
    663723
     
    819879# define IEMLIVENESS_STATE_ARE_STATUS_EFL_TO_BE_CLOBBERED(a_pCurEntry) \
    820880    ( (((a_pCurEntry)->Bit0.bm64 | (a_pCurEntry)->Bit1.bm64) & IEMLIVENESSBIT_STATUS_EFL_MASK) == 0 )
     881
     882/***
     883 * Construct a mask of what will be clobbered and never used.
     884 *
     885 * This is mainly used with IEMLIVENESSBIT_STATUS_EFL_MASK to avoid
     886 * unnecessary EFLAGS calculations.
     887 *
     888 * @param a_pCurEntry  The current liveness entry.
     889 * @note  Used by actual code.
     890 */
     891# define IEMLIVENESS_STATE_GET_WILL_BE_CLOBBERED_SET(a_pCurEntry) \
     892    ( ~((a_pCurEntry)->Bit0.bm64 | (a_pCurEntry)->Bit1.bm64) & IEMLIVENESSBIT_MASK )
    821893
    822894/** Construct a mask of the guest registers in the UNUSED and XCPT_OR_CALL
     
    864936 * @note  Used by actual code. */
    865937# define IEMLIVENESS_STATE_GET_CAN_BE_FREED_SET(a_pCurEntry) \
    866             (  ~(a_pCurEntry)->aBits[IEMLIVENESS_BIT_READ].bm64 \
    867              & ~(a_pCurEntry)->aBits[IEMLIVENESS_BIT_WRITE].bm64 \
    868              & IEMLIVENESSBIT_MASK )
    869 
     938    (  ~(a_pCurEntry)->aBits[IEMLIVENESS_BIT_READ].bm64 \
     939     & ~(a_pCurEntry)->aBits[IEMLIVENESS_BIT_WRITE].bm64 \
     940     & IEMLIVENESSBIT_MASK )
     941
     942/***
     943 * Construct a mask of what will be clobbered and never used.
     944 *
     945 * This is mainly used with IEMLIVENESSBIT_STATUS_EFL_MASK to avoid
     946 * unnecessary EFLAGS calculations.
     947 *
     948 * @param a_pCurEntry  The current liveness entry.
     949 * @note  Used by actual code.
     950 */
     951# define IEMLIVENESS_STATE_GET_WILL_BE_CLOBBERED_SET(a_pCurEntry) \
     952    (  (a_pCurEntry)->aBits[IEMLIVENESS_BIT_WRITE].bm64 \
     953     & ~(  (a_pCurEntry)->aBits[IEMLIVENESS_BIT_POTENTIAL_CALL].bm64 \
     954         | (a_pCurEntry)->aBits[IEMLIVENESS_BIT_READ].bm64 \
     955         | (a_pCurEntry)->aBits[IEMLIVENESS_BIT_CALL].bm64) )
     956
     957/**
     958 * Construct a mask of what (EFLAGS) which can be postponed.
     959 *
     960 * The postponement is for the avoiding EFLAGS status bits calculations in the
     961 * primary code stream whenever possible, and instead only do these in the TLB
     962 * load and TB exit code paths which shouldn't be traveled quite as often.
     963 * A requirement, though, is that the status bits will be clobbered later in the
     964 * TB.
     965 *
     966 * User need to apply IEMLIVENESSBIT_STATUS_EFL_MASK if appropriate/necessary.
     967 *
     968 * @param a_pCurEntry  The current liveness entry.
     969 * @note  Used by actual code.
     970 */
     971# define IEMLIVENESS_STATE_GET_CAN_BE_POSTPONED_SET(a_pCurEntry) \
     972    (  (a_pCurEntry)->aBits[IEMLIVENESS_BIT_POTENTIAL_CALL].bm64 \
     973     & (a_pCurEntry)->aBits[IEMLIVENESS_BIT_WRITE].bm64 \
     974     & ~(  (a_pCurEntry)->aBits[IEMLIVENESS_BIT_READ].bm64 \
     975         | (a_pCurEntry)->aBits[IEMLIVENESS_BIT_CALL].bm64) )
    870976
    871977#endif /* IEMLIVENESS_EXTENDED_LAYOUT */
     
    10391145#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
    10401146# define IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(a_pReNative, a_fEflNeeded) \
    1041     AssertMsg(!((a_pReNative)->fPostponingEFlags & (a_fEflNeeded)), \
    1042               ("%#x & %#x -> %#x\n", (a_pReNative)->fPostponingEFlags, \
    1043                a_fEflNeeded, (a_pReNative)->fPostponingEFlags & (a_fEflNeeded) ))
     1147    AssertMsg(!((a_pReNative)->PostponedEfl.fEFlags & (a_fEflNeeded)), \
     1148              ("%#x & %#x -> %#x\n", (a_pReNative)->PostponedEfl.fEFlags, \
     1149               a_fEflNeeded, (a_pReNative)->PostponedEfl.fEFlags & (a_fEflNeeded) ))
    10441150#else
    10451151# define IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(a_pReNative, a_fEflNeeded) ((void)0)
     
    10521158#if defined(IEMNATIVE_WITH_EFLAGS_SKIPPING) && defined(IEMNATIVE_WITH_EFLAGS_POSTPONING)
    10531159# define IEMNATIVE_ASSERT_EFLAGS_SKIPPING_AND_POSTPONING(a_pReNative, a_fEflNeeded) \
    1054     AssertMsg(!(((a_pReNative)->fSkippingEFlags | (a_pReNative)->fPostponingEFlags) & (a_fEflNeeded)), \
    1055               ("(%#x | %#x) & %#x -> %#x\n", (a_pReNative)->fSkippingEFlags, (a_pReNative)->fPostponingEFlags, \
    1056                a_fEflNeeded, ((a_pReNative)->fSkippingEFlags | (a_pReNative)->fPostponingEFlags) & (a_fEflNeeded) ))
     1160    AssertMsg(!(((a_pReNative)->fSkippingEFlags | (a_pReNative)->PostponedEfl.fEFlags) & (a_fEflNeeded)), \
     1161              ("(%#x | %#x) & %#x -> %#x\n", (a_pReNative)->fSkippingEFlags, (a_pReNative)->PostponedEfl.fEFlags, \
     1162               a_fEflNeeded, ((a_pReNative)->fSkippingEFlags | (a_pReNative)->PostponedEfl.fEFlags) & (a_fEflNeeded) ))
    10571163#elif defined(IEMNATIVE_WITH_EFLAGS_SKIPPING)
    10581164# define IEMNATIVE_ASSERT_EFLAGS_SKIPPING_AND_POSTPONING(a_pReNative, a_fEflNeeded) \
     
    10771183#else
    10781184# define IEMNATIVE_STRICT_EFLAGS_SKIPPING_EMIT_CHECK(a_pReNative, a_off, a_fEflNeeded) do { } while (0)
     1185#endif
     1186
     1187
     1188/** @def IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS
     1189 * Number of extra instructions to allocate for each TB exit to account for
     1190 * postponed EFLAGS calculations.
     1191 */
     1192#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     1193# ifdef RT_ARCH_AMD64
     1194#  define IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS   32
     1195# elif defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING)
     1196#  define IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS   32
     1197# else
     1198#  error "port me"
     1199# endif
     1200#else
     1201# define IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS    0
     1202#endif
     1203
     1204/** @def IEMNATIVE_CLEAR_POSTPONED_EFLAGS
     1205 * Helper macro function for calling iemNativeClearPostponedEFlags() when
     1206 * IEMNATIVE_WITH_EFLAGS_POSTPONING is enabled.
     1207 */
     1208#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     1209# define IEMNATIVE_CLEAR_POSTPONED_EFLAGS(a_pReNative, a_fEflClobbered) iemNativeClearPostponedEFlags<a_fEflClobbered>(a_pReNative)
     1210#else
     1211# define IEMNATIVE_CLEAR_POSTPONED_EFLAGS(a_pReNative, a_fEflClobbered) ((void)0)
    10791212#endif
    10801213
     
    15331666
    15341667
     1668#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     1669typedef enum IEMNATIVE_POSTPONED_EFL_OP_T : uint8_t
     1670{
     1671    kIemNativePostponedEflOp_Invalid = 0,
     1672    /** Logical operation.
     1673     * Operands: result register.
     1674     * @note This clears OF, CF and (undefined) AF, thus no need for inputs. */
     1675    kIemNativePostponedEflOp_Logical,
     1676    kIemNativePostponedEflOp_End
     1677} IEMNATIVE_POSTPONED_EFL_OP_T;
     1678#endif /* IEMNATIVE_WITH_EFLAGS_POSTPONING */
     1679
    15351680/**
    15361681 * Conditional stack entry.
     
    16701815#endif
    16711816#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
    1672     uint32_t                    fPostponingEFlags;
     1817    struct
     1818    {
     1819        /** EFLAGS status bits that we're currently postponing the calculcation of. */
     1820        uint32_t                        fEFlags;
     1821        /** The postponed EFLAGS status bits calculation operation. */
     1822        IEMNATIVE_POSTPONED_EFL_OP_T    enmOp;
     1823        /** The bit-width of the postponed EFLAGS calculation. */
     1824        uint8_t                         cOpBits;
     1825        /** Host register holding result or first source for the delayed operation,
     1826         *  UINT8_MAX if not in use. */
     1827        uint8_t                         idxReg1;
     1828        /** Host register holding second source for the delayed operation,
     1829         *  UINT8_MAX if not in use. */
     1830        uint8_t                         idxReg2;
     1831    } PostponedEfl;
    16731832#endif
    16741833
  • trunk/src/VBox/VMM/include/IEMN8veRecompilerEmit.h

    r106144 r106180  
    234234        pCodeBuf[off++] = Armv8A64MkInstrMovZ(iGpr, uImm32 & UINT32_C(0xffff), 0, false /*f64Bit*/);
    235235        pCodeBuf[off++] = Armv8A64MkInstrMovK(iGpr, uImm32 >> 16,              1, false /*f64Bit*/);
     236    }
     237
     238#else
     239# error "port me"
     240#endif
     241    return off;
     242}
     243
     244
     245/**
     246 * Variant of iemNativeEmitLoadGpr32Imm where the caller ensures sufficent
     247 * buffer space.
     248 *
     249 * Max buffer consumption:
     250 *      - AMD64: 6 instruction bytes.
     251 *      - ARM64: 2 instruction words (8 bytes).
     252 *
     253 * @note The top 32 bits will be cleared.
     254 */
     255template<uint32_t const a_uImm32>
     256DECL_FORCE_INLINE(uint32_t) iemNativeEmitLoadGpr32ImmExT(PIEMNATIVEINSTR pCodeBuf, uint32_t off, uint8_t iGpr)
     257{
     258#ifdef RT_ARCH_AMD64
     259    if (a_uImm32 == 0)
     260    {
     261        /* xor gpr, gpr */
     262        if (iGpr >= 8)
     263            pCodeBuf[off++] = X86_OP_REX_R | X86_OP_REX_B;
     264        pCodeBuf[off++] = 0x33;
     265        pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGpr & 7, iGpr & 7);
     266    }
     267    else
     268    {
     269        /* mov gpr, imm32 */
     270        if (iGpr >= 8)
     271            pCodeBuf[off++] = X86_OP_REX_B;
     272        pCodeBuf[off++] = 0xb8 + (iGpr & 7);
     273        pCodeBuf[off++] = RT_BYTE1(a_uImm32);
     274        pCodeBuf[off++] = RT_BYTE2(a_uImm32);
     275        pCodeBuf[off++] = RT_BYTE3(a_uImm32);
     276        pCodeBuf[off++] = RT_BYTE4(a_uImm32);
     277    }
     278
     279#elif defined(RT_ARCH_ARM64)
     280    if RT_CONSTEXPR((a_uImm32 >> 16) == 0)
     281        /* movz gpr, imm16 */
     282        pCodeBuf[off++] = Armv8A64MkInstrMovZ(iGpr, a_uImm32,                    0, false /*f64Bit*/);
     283    else if RT_CONSTEXPR((a_uImm32 & UINT32_C(0xffff)) == 0)
     284        /* movz gpr, imm16, lsl #16 */
     285        pCodeBuf[off++] = Armv8A64MkInstrMovZ(iGpr, a_uImm32 >> 16,              1, false /*f64Bit*/);
     286    else if RT_CONSTEXPR((a_uImm32 & UINT32_C(0xffff)) == UINT32_C(0xffff))
     287        /* movn gpr, imm16, lsl #16 */
     288        pCodeBuf[off++] = Armv8A64MkInstrMovN(iGpr, ~a_uImm32 >> 16,             1, false /*f64Bit*/);
     289    else if RT_CONSTEXPR((a_uImm32 >> 16) == UINT32_C(0xffff))
     290        /* movn gpr, imm16 */
     291        pCodeBuf[off++] = Armv8A64MkInstrMovN(iGpr, ~a_uImm32,                   0, false /*f64Bit*/);
     292    else
     293    {
     294        pCodeBuf[off++] = Armv8A64MkInstrMovZ(iGpr, a_uImm32 & UINT32_C(0xffff), 0, false /*f64Bit*/);
     295        pCodeBuf[off++] = Armv8A64MkInstrMovK(iGpr, a_uImm32 >> 16,              1, false /*f64Bit*/);
    236296    }
    237297
     
    81568216 * Emits a call to a 64-bit address.
    81578217 */
     8218template<bool const a_fSkipEflChecks = false>
    81588219DECL_INLINE_THROW(uint32_t) iemNativeEmitCallImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uintptr_t uPfn)
    81598220{
     8221    if RT_CONSTEXPR(!a_fSkipEflChecks)
     8222    {
     8223        IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS);
     8224        IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(  pReNative, X86_EFL_STATUS_BITS);
     8225    }
     8226
    81608227#ifdef RT_ARCH_AMD64
    81618228    off = iemNativeEmitLoadGprImm64(pReNative, off, X86_GREG_xAX, uPfn);
     
    82818348*********************************************************************************************************************************/
    82828349
     8350#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8351/* IEMAllN8veEmit-x86.h: */
     8352template<uint32_t const a_bmInputRegs>
     8353DECL_FORCE_INLINE_THROW(uint32_t)
     8354iemNativeDoPostponedEFlagsAtTbExitEx(PIEMRECOMPILERSTATE pReNative, uint32_t off, PIEMNATIVEINSTR pCodeBuf);
     8355
     8356template<uint32_t const a_bmInputRegs>
     8357DECL_FORCE_INLINE_THROW(uint32_t)
     8358iemNativeDoPostponedEFlagsAtTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off);
     8359#endif
     8360
     8361
    82838362/**
    82848363 * Helper for marking the current conditional branch as exiting the TB.
     
    82988377
    82998378/**
     8379 * Unconditionally exits the translation block via a branch instructions.
     8380 *
     8381 * @note In case a delayed EFLAGS calculation is pending, this may emit an
     8382 *       additional IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS instructions.
     8383 */
     8384template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fActuallyExitingTb = true, bool const a_fPostponedEfl = true>
     8385DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExitEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off)
     8386{
     8387    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
     8388    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
     8389
     8390    if RT_CONSTEXPR(a_fActuallyExitingTb)
     8391        iemNativeMarkCurCondBranchAsExiting(pReNative);
     8392
     8393#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8394    if RT_CONSTEXPR(a_fPostponedEfl)
     8395        off = iemNativeDoPostponedEFlagsAtTbExitEx<IEMNATIVELABELTYPE_GET_INPUT_REG_MASK(a_enmExitReason)>(pReNative, off,
     8396                                                                                                           pCodeBuf);
     8397#endif
     8398
     8399#ifdef RT_ARCH_AMD64
     8400    /* jmp rel32 */
     8401    pCodeBuf[off++] = 0xe9;
     8402    iemNativeAddTbExitFixup(pReNative, off, a_enmExitReason);
     8403    pCodeBuf[off++] = 0xfe;
     8404    pCodeBuf[off++] = 0xff;
     8405    pCodeBuf[off++] = 0xff;
     8406    pCodeBuf[off++] = 0xff;
     8407
     8408#elif defined(RT_ARCH_ARM64)
     8409    iemNativeAddTbExitFixup(pReNative, off, a_enmExitReason);
     8410    pCodeBuf[off++] = Armv8A64MkInstrB(-1);
     8411
     8412#else
     8413# error "Port me!"
     8414#endif
     8415    return off;
     8416}
     8417
     8418
     8419/**
     8420 * Unconditionally exits the translation block via a branch instructions.
     8421 *
     8422 * @note In case a delayed EFLAGS calculation is pending, this may emit an
     8423 *       additional IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS instructions.
     8424 */
     8425template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fActuallyExitingTb = true, bool const a_fPostponedEfl = true>
     8426DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off)
     8427{
     8428    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
     8429    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
     8430
     8431    if RT_CONSTEXPR(a_fActuallyExitingTb)
     8432        iemNativeMarkCurCondBranchAsExiting(pReNative);
     8433
     8434#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8435    if RT_CONSTEXPR(a_fPostponedEfl)
     8436        off = iemNativeDoPostponedEFlagsAtTbExit<IEMNATIVELABELTYPE_GET_INPUT_REG_MASK(a_enmExitReason)>(pReNative, off);
     8437#endif
     8438
     8439#ifdef RT_ARCH_AMD64
     8440    PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6);
     8441
     8442    /* jmp rel32 */
     8443    pCodeBuf[off++] = 0xe9;
     8444    iemNativeAddTbExitFixup(pReNative, off, a_enmExitReason);
     8445    pCodeBuf[off++] = 0xfe;
     8446    pCodeBuf[off++] = 0xff;
     8447    pCodeBuf[off++] = 0xff;
     8448    pCodeBuf[off++] = 0xff;
     8449
     8450#elif defined(RT_ARCH_ARM64)
     8451    PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
     8452    iemNativeAddTbExitFixup(pReNative, off, a_enmExitReason);
     8453    pCodeBuf[off++] = Armv8A64MkInstrB(-1);
     8454
     8455#else
     8456# error "Port me!"
     8457#endif
     8458    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8459    return off;
     8460}
     8461
     8462
     8463/**
    83008464 * Emits a Jcc rel32 / B.cc imm19 to the given label (ASSUMED requiring fixup).
    8301  */
     8465 *
     8466 * @note In case a delayed EFLAGS calculation is pending, this may emit an
     8467 *       additional IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS instructions.
     8468 */
     8469template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
    83028470DECL_FORCE_INLINE_THROW(uint32_t)
    8303 iemNativeEmitJccTbExitEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off,
    8304                          IEMNATIVELABELTYPE enmExitReason, IEMNATIVEINSTRCOND enmCond)
     8471iemNativeEmitTbExitJccEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off, IEMNATIVEINSTRCOND enmCond)
    83058472{
    83068473    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8307     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8308     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
     8474    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
     8475
     8476#ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8477    if RT_CONSTEXPR(a_fPostponedEfl)
     8478        if (pReNative->PostponedEfl.fEFlags)
     8479        {
     8480            /* Jcc l_NonPrimaryCodeStreamTarget */
     8481            uint32_t const offFixup1 = off;
     8482            off = iemNativeEmitJccToFixedEx(pCodeBuf, off, off + 1, enmCond);
     8483
     8484            /* JMP l_PrimaryCodeStreamResume */
     8485            uint32_t const offFixup2 = off;
     8486            off = iemNativeEmitJmpToFixedEx(pCodeBuf, off, off + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     8487
     8488            /* l_NonPrimaryCodeStreamTarget: */
     8489            iemNativeFixupFixedJump(pReNative, offFixup1, off);
     8490            off = iemNativeEmitTbExitEx<a_enmExitReason, false /*a_fActuallyExitingTb*/, true>(pReNative, pCodeBuf, off);
     8491
     8492            /* l_PrimaryCodeStreamResume: */
     8493            iemNativeFixupFixedJump(pReNative, offFixup2, off);
     8494            IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8495            return off;
     8496        }
     8497#endif
    83098498
    83108499#if defined(RT_ARCH_AMD64)
     
    83128501    pCodeBuf[off++] = 0x0f;
    83138502    pCodeBuf[off++] = (uint8_t)enmCond | 0x80;
    8314     iemNativeAddTbExitFixup(pReNative, off, enmExitReason);
     8503    iemNativeAddTbExitFixup(pReNative, off, a_enmExitReason);
    83158504    pCodeBuf[off++] = 0x00;
    83168505    pCodeBuf[off++] = 0x00;
     
    83218510    /* ARM64 doesn't have the necessary jump range, so we jump via local label
    83228511       just like when we keep everything local. */
    8323     uint32_t const idxLabel = iemNativeLabelCreate(pReNative, enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
     8512    uint32_t const idxLabel = iemNativeLabelCreate(pReNative, a_enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
    83248513    off = iemNativeEmitJccToLabelEx(pReNative, pCodeBuf, off, idxLabel, enmCond);
    83258514#endif
     
    83318520 * Emits a Jcc rel32 / B.cc imm19 to the epilog.
    83328521 */
    8333 DECL_INLINE_THROW(uint32_t)
    8334 iemNativeEmitJccTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVELABELTYPE enmExitReason, IEMNATIVEINSTRCOND enmCond)
     8522template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8523DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExitJcc(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVEINSTRCOND enmCond)
    83358524{
    83368525    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8337     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8338     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
    8339 
    8340 #ifdef RT_ARCH_AMD64
    8341     off = iemNativeEmitJccTbExitEx(pReNative, iemNativeInstrBufEnsure(pReNative, off, 6), off, enmExitReason, enmCond);
    8342 #elif defined(RT_ARCH_ARM64)
    8343     off = iemNativeEmitJccTbExitEx(pReNative, iemNativeInstrBufEnsure(pReNative, off, 2), off, enmExitReason, enmCond);
     8526    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
     8527
     8528#ifdef RT_ARCH_AMD64
     8529    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS + 5);
     8530#elif defined(RT_ARCH_ARM64)
     8531    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 2 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS + 1);
    83448532#else
    83458533# error "Port me!"
    83468534#endif
     8535    off = iemNativeEmitTbExitJccEx<a_enmExitReason, a_fPostponedEfl>(pReNative, pCodeBuf, off, enmCond);
    83478536    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    83488537    return off;
     
    83538542 * Emits a JNZ/JNE rel32 / B.NE imm19 to the TB exit routine with the given reason.
    83548543 */
    8355 DECL_INLINE_THROW(uint32_t) iemNativeEmitJnzTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVELABELTYPE enmExitReason)
    8356 {
    8357 #ifdef RT_ARCH_AMD64
    8358     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kIemNativeInstrCond_ne);
    8359 #elif defined(RT_ARCH_ARM64)
    8360     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kArmv8InstrCond_Ne);
     8544template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8545DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExitJnz(PIEMRECOMPILERSTATE pReNative, uint32_t off)
     8546{
     8547#ifdef RT_ARCH_AMD64
     8548    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kIemNativeInstrCond_ne);
     8549#elif defined(RT_ARCH_ARM64)
     8550    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kArmv8InstrCond_Ne);
    83618551#else
    83628552# error "Port me!"
     
    83688558 * Emits a JZ/JE rel32 / B.EQ imm19 to the TB exit routine with the given reason.
    83698559 */
    8370 DECL_INLINE_THROW(uint32_t) iemNativeEmitJzTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVELABELTYPE enmExitReason)
    8371 {
    8372 #ifdef RT_ARCH_AMD64
    8373     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kIemNativeInstrCond_e);
    8374 #elif defined(RT_ARCH_ARM64)
    8375     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kArmv8InstrCond_Eq);
     8560template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8561DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExitJz(PIEMRECOMPILERSTATE pReNative, uint32_t off)
     8562{
     8563#ifdef RT_ARCH_AMD64
     8564    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kIemNativeInstrCond_e);
     8565#elif defined(RT_ARCH_ARM64)
     8566    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kArmv8InstrCond_Eq);
    83768567#else
    83778568# error "Port me!"
     
    83838574 * Emits a JA/JNBE rel32 / B.HI imm19 to the TB exit.
    83848575 */
    8385 DECL_INLINE_THROW(uint32_t) iemNativeEmitJaTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVELABELTYPE enmExitReason)
    8386 {
    8387 #ifdef RT_ARCH_AMD64
    8388     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kIemNativeInstrCond_nbe);
    8389 #elif defined(RT_ARCH_ARM64)
    8390     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kArmv8InstrCond_Hi);
     8576template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8577DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExitJa(PIEMRECOMPILERSTATE pReNative, uint32_t off)
     8578{
     8579#ifdef RT_ARCH_AMD64
     8580    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kIemNativeInstrCond_nbe);
     8581#elif defined(RT_ARCH_ARM64)
     8582    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kArmv8InstrCond_Hi);
    83918583#else
    83928584# error "Port me!"
     
    83988590 * Emits a JL/JNGE rel32 / B.LT imm19 to the TB exit with the given reason.
    83998591 */
    8400 DECL_INLINE_THROW(uint32_t) iemNativeEmitJlTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVELABELTYPE enmExitReason)
    8401 {
    8402 #ifdef RT_ARCH_AMD64
    8403     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kIemNativeInstrCond_l);
    8404 #elif defined(RT_ARCH_ARM64)
    8405     return iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kArmv8InstrCond_Lt);
     8592template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8593DECL_INLINE_THROW(uint32_t) iemNativeEmitTbExitJl(PIEMRECOMPILERSTATE pReNative, uint32_t off)
     8594{
     8595#ifdef RT_ARCH_AMD64
     8596    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kIemNativeInstrCond_l);
     8597#elif defined(RT_ARCH_ARM64)
     8598    return iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kArmv8InstrCond_Lt);
    84068599#else
    84078600# error "Port me!"
     
    84108603
    84118604
    8412 DECL_INLINE_THROW(uint32_t)
    8413 iemNativeEmitTbExitEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off, IEMNATIVELABELTYPE enmExitReason)
    8414 {
    8415     IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8416     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here. */
    8417     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
    8418 
    8419     iemNativeMarkCurCondBranchAsExiting(pReNative);
    8420 
    8421 #ifdef RT_ARCH_AMD64
    8422     /* jmp rel32 */
    8423     pCodeBuf[off++] = 0xe9;
    8424     iemNativeAddTbExitFixup(pReNative, off, enmExitReason);
    8425     pCodeBuf[off++] = 0xfe;
    8426     pCodeBuf[off++] = 0xff;
    8427     pCodeBuf[off++] = 0xff;
    8428     pCodeBuf[off++] = 0xff;
    8429 
    8430 #elif defined(RT_ARCH_ARM64)
    8431     iemNativeAddTbExitFixup(pReNative, off, enmExitReason);
    8432     pCodeBuf[off++] = Armv8A64MkInstrB(-1);
    8433 
    8434 #else
    8435 # error "Port me!"
    8436 #endif
    8437     return off;
    8438 }
    8439 
    8440 
    8441 DECL_INLINE_THROW(uint32_t)
    8442 iemNativeEmitTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off, IEMNATIVELABELTYPE enmExitReason,
    8443                     bool fActuallyExitingTb = true)
    8444 {
    8445     IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8446     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here. */
    8447     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
    8448 
    8449     if (fActuallyExitingTb)
    8450         iemNativeMarkCurCondBranchAsExiting(pReNative);
    8451 
    8452 #ifdef RT_ARCH_AMD64
    8453     PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6);
    8454 
    8455     /* jmp rel32 */
    8456     pCodeBuf[off++] = 0xe9;
    8457     iemNativeAddTbExitFixup(pReNative, off, enmExitReason);
    8458     pCodeBuf[off++] = 0xfe;
    8459     pCodeBuf[off++] = 0xff;
    8460     pCodeBuf[off++] = 0xff;
    8461     pCodeBuf[off++] = 0xff;
    8462 
    8463 #elif defined(RT_ARCH_ARM64)
    8464     PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
    8465     iemNativeAddTbExitFixup(pReNative, off, enmExitReason);
    8466     pCodeBuf[off++] = Armv8A64MkInstrB(-1);
    8467 
    8468 #else
    8469 # error "Port me!"
    8470 #endif
    8471     IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    8472     return off;
    8473 }
    8474 
    8475 
    8476 /**
    8477  * Emits a jump to the TB exit with @a enmExitReason on the condition _any_ of the bits in @a fBits
    8478  * are set in @a iGprSrc.
    8479  */
    8480 DECL_INLINE_THROW(uint32_t)
    8481 iemNativeEmitTestAnyBitsInGprAndTbExitIfAnySet(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8482                                                uint8_t iGprSrc, uint64_t fBits, IEMNATIVELABELTYPE enmExitReason)
     8605/**
     8606 * Emits a jump to the TB exit with @a a_enmExitReason on the condition _any_ of
     8607 * the bits in @a fBits are set in @a iGprSrc.
     8608 */
     8609template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8610DECL_INLINE_THROW(uint32_t)
     8611iemNativeEmitTbExitIfAnyBitsSetInGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, uint64_t fBits)
    84838612{
    84848613    Assert(fBits); Assert(!RT_IS_POWER_OF_TWO(fBits));
    84858614
    84868615    off = iemNativeEmitTestAnyBitsInGpr(pReNative, off, iGprSrc, fBits);
    8487     return iemNativeEmitJnzTbExit(pReNative, off, enmExitReason);
    8488 }
    8489 
    8490 
     8616    return iemNativeEmitTbExitJnz<a_enmExitReason, a_fPostponedEfl>(pReNative, off);
     8617}
     8618
     8619
     8620#if 0 /* unused */
    84918621/**
    84928622 * Emits a jump to @a idxLabel on the condition _none_ of the bits in @a fBits
    84938623 * are set in @a iGprSrc.
    84948624 */
    8495 DECL_INLINE_THROW(uint32_t)
    8496 iemNativeEmitTestAnyBitsInGprAndTbExitIfNoneSet(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8497                                                 uint8_t iGprSrc, uint64_t fBits, IEMNATIVELABELTYPE enmExitReason)
     8625template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8626DECL_INLINE_THROW(uint32_t)
     8627iemNativeEmitTbExitIfNoBitsSetInGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, uint64_t fBits)
    84988628{
    84998629    Assert(fBits); Assert(!RT_IS_POWER_OF_TWO(fBits));
    85008630
    85018631    off = iemNativeEmitTestAnyBitsInGpr(pReNative, off, iGprSrc, fBits);
    8502     return iemNativeEmitJzTbExit(pReNative, off, enmExitReason);
    8503 }
    8504 
    8505 
     8632    return iemNativeEmitJzTbExit<a_enmExitReason, a_fPostponedEfl>(pReNative, off);
     8633}
     8634#endif
     8635
     8636
     8637#if 0 /* unused */
    85068638/**
    85078639 * Emits code that exits the TB with the given reason if @a iGprLeft and @a iGprRight
    85088640 * differs.
    85098641 */
    8510 DECL_INLINE_THROW(uint32_t)
    8511 iemNativeEmitTestIfGprNotEqualGprAndTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8512                                            uint8_t iGprLeft, uint8_t iGprRight, IEMNATIVELABELTYPE enmExitReason)
     8642template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8643DECL_INLINE_THROW(uint32_t)
     8644iemNativeEmitTbExitIfGprNotEqualGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprLeft, uint8_t iGprRight)
    85138645{
    85148646    off = iemNativeEmitCmpGprWithGpr(pReNative, off, iGprLeft, iGprRight);
    8515     off = iemNativeEmitJnzTbExit(pReNative, off, enmExitReason);
    8516     return off;
    8517 }
     8647    off = iemNativeEmitJnzTbExit<a_enmExitReason, a_fPostponedEfl>(pReNative, off);
     8648    return off;
     8649}
     8650#endif
    85188651
    85198652
     
    85228655 * @a uImm.
    85238656 */
    8524 DECL_INLINE_THROW(uint32_t)
    8525 iemNativeEmitTestIfGpr32NotEqualImmAndTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8526                                              uint8_t iGprSrc, uint32_t uImm, IEMNATIVELABELTYPE enmExitReason)
     8657template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8658DECL_INLINE_THROW(uint32_t)
     8659iemNativeEmitTbExitIfGpr32NotEqualImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, uint32_t uImm)
    85278660{
    85288661    off = iemNativeEmitCmpGpr32WithImm(pReNative, off, iGprSrc, uImm);
    8529     off = iemNativeEmitJnzTbExit(pReNative, off, enmExitReason);
     8662    off = iemNativeEmitTbExitJnz<a_enmExitReason, a_fPostponedEfl>(pReNative, off);
    85308663    return off;
    85318664}
     
    85358668 * Emits code that exits the current TB if @a iGprSrc differs from @a uImm.
    85368669 */
    8537 DECL_INLINE_THROW(uint32_t)
    8538 iemNativeEmitTestIfGprNotEqualImmAndTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8539                                            uint8_t iGprSrc, uint64_t uImm, IEMNATIVELABELTYPE enmExitReason)
     8670template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8671DECL_INLINE_THROW(uint32_t)
     8672iemNativeEmitTbExitIfGprNotEqualImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, uint64_t uImm)
    85408673{
    85418674    off = iemNativeEmitCmpGprWithImm(pReNative, off, iGprSrc, uImm);
    8542     off = iemNativeEmitJnzTbExit(pReNative, off, enmExitReason);
     8675    off = iemNativeEmitTbExitJnz<a_enmExitReason, a_fPostponedEfl>(pReNative, off);
    85438676    return off;
    85448677}
     
    85488681 * Emits code that exits the current TB with the given reason if 32-bit @a iGprSrc equals @a uImm.
    85498682 */
    8550 DECL_INLINE_THROW(uint32_t)
    8551 iemNativeEmitTestIfGpr32EqualsImmAndTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8552                                            uint8_t iGprSrc, uint32_t uImm, IEMNATIVELABELTYPE enmExitReason)
     8683template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8684DECL_INLINE_THROW(uint32_t)
     8685iemNativeEmitTbExitIfGpr32EqualsImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, uint32_t uImm)
    85538686{
    85548687    off = iemNativeEmitCmpGpr32WithImm(pReNative, off, iGprSrc, uImm);
    8555     off = iemNativeEmitJzTbExit(pReNative, off, enmExitReason);
    8556     return off;
    8557 }
    8558 
    8559 
    8560 /**
    8561  * Emits code to exit the current TB with the reason @a enmExitReason on the condition that bit @a iBitNo _is_ _set_ in
    8562  * @a iGprSrc.
     8688    off = iemNativeEmitTbExitJz<a_enmExitReason, a_fPostponedEfl>(pReNative, off);
     8689    return off;
     8690}
     8691
     8692
     8693/**
     8694 * Emits code to exit the current TB with the reason @a a_enmExitReason on the
     8695 * condition that bit @a iBitNo _is_ _set_ in @a iGprSrc.
    85638696 *
    85648697 * @note On ARM64 the range is only +/-8191 instructions.
    85658698 */
    8566 DECL_INLINE_THROW(uint32_t)
    8567 iemNativeEmitTestBitInGprAndTbExitIfSet(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8568                                         uint8_t iGprSrc, uint8_t iBitNo, IEMNATIVELABELTYPE enmExitReason)
    8569 {
    8570     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
     8699template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8700DECL_INLINE_THROW(uint32_t)
     8701iemNativeEmitTbExitIfBitSetInGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, uint8_t iBitNo)
     8702{
     8703    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
    85718704
    85728705#if defined(RT_ARCH_AMD64)
     
    85818714        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 0, iGprSrc & 7);
    85828715        pbCodeBuf[off++] = (uint8_t)1 << iBitNo;
    8583         off = iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kIemNativeInstrCond_ne);
     8716        IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8717        off = iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kIemNativeInstrCond_ne);
    85848718    }
    85858719    else
     
    85948728        pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprSrc & 7);
    85958729        pbCodeBuf[off++] = iBitNo;
    8596         off = iemNativeEmitJccTbExit(pReNative, off, enmExitReason, kIemNativeInstrCond_c);
    8597     }
    8598     IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    8599     return off;
    8600 
    8601 #else
    8602     /* ARM64 doesn't have the necessary jump range, so we jump via local label
    8603        just like when we keep everything local. */
     8730        IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8731        off = iemNativeEmitTbExitJcc<a_enmExitReason, a_fPostponedEfl>(pReNative, off, kIemNativeInstrCond_c);
     8732    }
     8733    return off;
     8734
     8735#elif defined(RT_ARCH_ARM64)
    86048736    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8605     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8606     uint32_t const idxLabel = iemNativeLabelCreate(pReNative, enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
     8737    /** @todo Perhaps we should always apply the PostponedEfl code pattern here,
     8738     *        it's the same number of instructions as the TST + B.CC stuff? */
     8739# ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8740    if RT_CONSTEXPR(a_fPostponedEfl)
     8741        if (pReNative->PostponedEfl.fEFlags)
     8742        {
     8743            PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off,
     8744                                                                     3 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     8745            pCodeBuf[off++] = Armv8A64MkInstrTbnz(1 /*l_NonPrimaryCodeStreamTarget*/, iGprSrc, iBitNo);
     8746            uint32_t const offFixup = off;
     8747            pCodeBuf[off++] = Armv8A64MkInstrB(0 /*l_PrimaryCodeStreamResume*/);
     8748            /* l_NonPrimaryCodeStreamTarget: */
     8749            off = iemNativeEmitTbExitEx<a_enmExitReason, false /*a_fActuallyExitingTb*/, true>(pReNative, pCodeBuf, off);
     8750            /* l_PrimaryCodeStreamResume: */
     8751            iemNativeFixupFixedJump(pReNative, offFixup, off);
     8752            IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8753            return off;
     8754        }
     8755# endif
     8756    /* ARM64 doesn't have the necessary range to reach the per-chunk code, so
     8757       we go via a local trampoline. */
     8758    uint32_t const idxLabel = iemNativeLabelCreate(pReNative, a_enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
    86078759    return iemNativeEmitTestBitInGprAndJmpToLabelIfCc(pReNative, off, iGprSrc, iBitNo, idxLabel, true /*fJmpIfSet*/);
    8608 #endif
    8609 }
    8610 
    8611 
    8612 /**
    8613  * Emits code that exits the current TB with @a enmExitReason if @a iGprSrc is not zero.
     8760#else
     8761# error "port me"
     8762#endif
     8763}
     8764
     8765
     8766/**
     8767 * Emits code that exits the current TB with @a a_enmExitReason if @a iGprSrc is
     8768 * not zero.
    86148769 *
    86158770 * The operand size is given by @a f64Bit.
    86168771 */
     8772template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
    86178773DECL_FORCE_INLINE_THROW(uint32_t)
    8618 iemNativeEmitTestIfGprIsNotZeroAndTbExitEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off,
    8619                                            uint8_t iGprSrc, bool f64Bit, IEMNATIVELABELTYPE enmExitReason)
    8620 {
    8621     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
     8774iemNativeEmitTbExitIfGprIsNotZeroEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off,
     8775                                    uint8_t iGprSrc, bool f64Bit)
     8776{
     8777    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
    86228778
    86238779#if defined(RT_ARCH_AMD64)
     
    86318787
    86328788    /* jnz idxLabel  */
    8633     return iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, enmExitReason, kIemNativeInstrCond_ne);
    8634 
    8635 #else
    8636     /* ARM64 doesn't have the necessary jump range, so we jump via local label
    8637        just like when we keep everything local. */
     8789    return iemNativeEmitTbExitJccEx<a_enmExitReason, a_fPostponedEfl>(pReNative, pCodeBuf, off, kIemNativeInstrCond_ne);
     8790
     8791#elif defined(RT_ARCH_ARM64)
    86388792    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8639     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8640     uint32_t const idxLabel = iemNativeLabelCreate(pReNative, enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
     8793# ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8794    if RT_CONSTEXPR(a_fPostponedEfl)
     8795        if (pReNative->PostponedEfl.fEFlags)
     8796        {
     8797            pCodeBuf[off++] = Armv8A64MkInstrCbnz(1 /*l_NonPrimaryCodeStreamTarget*/, iGprSrc, f64Bit);
     8798            uint32_t const offFixup = off;
     8799            pCodeBuf[off++] = Armv8A64MkInstrB(0 /*l_PrimaryCodeStreamResume*/);
     8800            /* l_NonPrimaryCodeStreamTarget: */
     8801            off = iemNativeEmitTbExitEx<a_enmExitReason, false /*a_fActuallyExitingTb*/, true>(pReNative, pCodeBuf, off);
     8802            /* l_PrimaryCodeStreamResume: */
     8803            iemNativeFixupFixedJump(pReNative, offFixup, off);
     8804            IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8805            return off;
     8806        }
     8807# endif
     8808    /* ARM64 doesn't have the necessary range to reach the per-chunk code, so
     8809       we go via a local trampoline. */
     8810    uint32_t const idxLabel = iemNativeLabelCreate(pReNative, a_enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
    86418811    return iemNativeEmitTestIfGprIsZeroOrNotZeroAndJmpToLabelEx(pReNative, pCodeBuf, off, iGprSrc,
    86428812                                                                f64Bit, true /*fJmpIfNotZero*/, idxLabel);
    8643 #endif
    8644 }
    8645 
    8646 
    8647 /**
    8648  * Emits code to exit the current TB with the given reason @a enmExitReason if @a iGprSrc is not zero.
     8813#else
     8814# error "port me"
     8815#endif
     8816}
     8817
     8818
     8819/**
     8820 * Emits code to exit the current TB with the given reason @a a_enmExitReason if
     8821 * @a iGprSrc is not zero.
    86498822 *
    86508823 * The operand size is given by @a f64Bit.
    86518824 */
    8652 DECL_INLINE_THROW(uint32_t)
    8653 iemNativeEmitTestIfGprIsNotZeroAndTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8654                                          uint8_t iGprSrc, bool f64Bit, IEMNATIVELABELTYPE enmExitReason)
     8825template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8826DECL_INLINE_THROW(uint32_t)
     8827iemNativeEmitTbExitIfGprIsNotZero(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, bool f64Bit)
    86558828{
    86568829#if defined(RT_ARCH_AMD64)
    8657     off = iemNativeEmitTestIfGprIsNotZeroAndTbExitEx(pReNative, iemNativeInstrBufEnsure(pReNative, off, 3 + 6),
    8658                                                      off, iGprSrc, f64Bit, enmExitReason);
    8659     IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    8660     return off;
    8661 #else
    8662     IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8663     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8664     uint32_t const idxLabel = iemNativeLabelCreate(pReNative, enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
    8665     return iemNativeEmitTestIfGprIsZeroOrNotZeroAndJmpToLabel(pReNative, off, iGprSrc, f64Bit, true /*fJmpIfNotZero*/, idxLabel);
    8666 #endif
    8667 }
    8668 
    8669 
    8670 /**
    8671  * Emits code that exits the current TB with @a enmExitReason if @a iGprSrc is zero.
     8830    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3 + 6 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     8831
     8832#else
     8833    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     8834#endif
     8835    off = iemNativeEmitTbExitIfGprIsNotZeroEx<a_enmExitReason, a_fPostponedEfl>(pReNative, pCodeBuf, off, iGprSrc, f64Bit);
     8836    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8837    return off;
     8838}
     8839
     8840
     8841/**
     8842 * Emits code that exits the current TB with @a a_enmExitReason if @a iGprSrc is
     8843 * zero.
    86728844 *
    86738845 * The operand size is given by @a f64Bit.
    86748846 */
     8847template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
    86758848DECL_FORCE_INLINE_THROW(uint32_t)
    8676 iemNativeEmitTestIfGprIsZeroAndTbExitEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off,
    8677                                         uint8_t iGprSrc, bool f64Bit, IEMNATIVELABELTYPE enmExitReason)
    8678 {
    8679     Assert(IEMNATIVELABELTYPE_IS_EXIT_REASON(enmExitReason));
     8849iemNativeEmitTbExitIfGprIsZeroEx(PIEMRECOMPILERSTATE pReNative, PIEMNATIVEINSTR pCodeBuf, uint32_t off,
     8850                                 uint8_t iGprSrc, bool f64Bit)
     8851{
     8852    AssertCompile(IEMNATIVELABELTYPE_IS_EXIT_REASON(a_enmExitReason));
     8853
    86808854#if defined(RT_ARCH_AMD64)
    86818855    /* test reg32,reg32  / test reg64,reg64 */
     
    86888862
    86898863    /* jnz idxLabel  */
    8690     return iemNativeEmitJccTbExitEx(pReNative, pCodeBuf, off, enmExitReason, kIemNativeInstrCond_e);
    8691 
    8692 #else
    8693     /* ARM64 doesn't have the necessary jump range, so we jump via local label
    8694        just like when we keep everything local. */
     8864    return iemNativeEmitTbExitJccEx<a_enmExitReason, a_fPostponedEfl>(pReNative, pCodeBuf, off, kIemNativeInstrCond_e);
     8865
     8866#elif defined(RT_ARCH_ARM64)
    86958867    IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8696     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8697     uint32_t const idxLabel = iemNativeLabelCreate(pReNative, enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
     8868# ifdef IEMNATIVE_WITH_EFLAGS_POSTPONING
     8869    if RT_CONSTEXPR(a_fPostponedEfl)
     8870        if (pReNative->PostponedEfl.fEFlags)
     8871        {
     8872            pCodeBuf[off++] = Armv8A64MkInstrCbz(1 /*l_NonPrimaryCodeStreamTarget*/, iGprSrc, f64Bit);
     8873            uint32_t const offFixup = off;
     8874            pCodeBuf[off++] = Armv8A64MkInstrB(0 /*l_PrimaryCodeStreamResume*/);
     8875            /* l_NonPrimaryCodeStreamTarget: */
     8876            off = iemNativeEmitTbExitEx<a_enmExitReason, false /*a_fActuallyExitingTb*/, true>(pReNative, pCodeBuf, off);
     8877            /* l_PrimaryCodeStreamResume: */
     8878            iemNativeFixupFixedJump(pReNative, offFixup, off);
     8879            IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8880            return off;
     8881        }
     8882# endif
     8883    /* ARM64 doesn't have the necessary range to reach the per-chunk code, so
     8884       we go via a local trampoline. */
     8885    uint32_t const idxLabel = iemNativeLabelCreate(pReNative, a_enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
    86988886    return iemNativeEmitTestIfGprIsZeroOrNotZeroAndJmpToLabelEx(pReNative, pCodeBuf, off, iGprSrc,
    86998887                                                                f64Bit, false /*fJmpIfNotZero*/, idxLabel);
    8700 #endif
    8701 }
    8702 
    8703 
    8704 /**
    8705  * Emits code to exit the current TB with the given reason @a enmExitReason if @a iGprSrc is zero.
     8888#else
     8889# error "port me"
     8890#endif
     8891}
     8892
     8893
     8894/**
     8895 * Emits code to exit the current TB with the given reason @a a_enmExitReason if @a iGprSrc is zero.
    87068896 *
    87078897 * The operand size is given by @a f64Bit.
    87088898 */
    8709 DECL_INLINE_THROW(uint32_t)
    8710 iemNativeEmitTestIfGprIsZeroAndTbExit(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    8711                                       uint8_t iGprSrc, bool f64Bit, IEMNATIVELABELTYPE enmExitReason)
     8899template<IEMNATIVELABELTYPE const a_enmExitReason, bool const a_fPostponedEfl = true>
     8900DECL_INLINE_THROW(uint32_t)
     8901iemNativeEmitTbExitIfGprIsZero(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprSrc, bool f64Bit)
    87128902{
    87138903#if defined(RT_ARCH_AMD64)
    8714     off = iemNativeEmitTestIfGprIsZeroAndTbExitEx(pReNative, iemNativeInstrBufEnsure(pReNative, off, 3 + 6),
    8715                                                   off, iGprSrc, f64Bit, enmExitReason);
    8716     IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
    8717     return off;
    8718 #else
    8719     IEMNATIVE_ASSERT_EFLAGS_SKIPPING_ONLY(pReNative, X86_EFL_STATUS_BITS);
    8720     IEMNATIVE_ASSERT_EFLAGS_POSTPONING_ONLY(pReNative, X86_EFL_STATUS_BITS); /** @todo emit postponed stuff here and invert the condition. */
    8721     uint32_t const idxLabel = iemNativeLabelCreate(pReNative, enmExitReason, UINT32_MAX /*offWhere*/, 0 /*uData*/);
    8722     return iemNativeEmitTestIfGprIsZeroOrNotZeroAndJmpToLabel(pReNative, off, iGprSrc, f64Bit, false /*fJmpIfNotZero*/, idxLabel);
    8723 #endif
     8904    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3 + 6 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     8905
     8906#else
     8907    PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3 + IEMNATIVE_MAX_POSTPONED_EFLAGS_INSTRUCTIONS);
     8908#endif
     8909    off = iemNativeEmitTbExitIfGprIsZeroEx<a_enmExitReason, a_fPostponedEfl>(pReNative, pCodeBuf, off, iGprSrc, f64Bit);
     8910    IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
     8911    return off;
    87248912}
    87258913
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