VirtualBox

Changeset 106180 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Sep 30, 2024 1:51:48 PM (7 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/VMMAll
Files:
6 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),
Note: See TracChangeset for help on using the changeset viewer.

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