- Timestamp:
- Oct 28, 2023 1:01:28 AM (16 months ago)
- svn:sync-xref-src-repo-rev:
- 159729
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp
r101626 r101640 1588 1588 pReNative->cCondDepth = 0; 1589 1589 pReNative->uCondSeqNo = 0; 1590 pReNative->uCheckIrqSeqNo = 0; 1590 1591 1591 1592 pReNative->Core.bmHstRegs = IEMNATIVE_REG_FIXED_MASK … … 1994 1995 * Debug Info: Record info about a threaded call. 1995 1996 */ 1996 static bool iemNativeDbgInfoAddThreadedCall(PIEMRECOMPILERSTATE pReNative, IEMTHREADEDFUNCS enmCall ) RT_NOEXCEPT1997 static bool iemNativeDbgInfoAddThreadedCall(PIEMRECOMPILERSTATE pReNative, IEMTHREADEDFUNCS enmCall, bool fRecompiled) RT_NOEXCEPT 1997 1998 { 1998 1999 PIEMTBDBGENTRY const pEntry = iemNativeDbgInfoAddNewEntry(pReNative, pReNative->pDbgInfo); 1999 2000 AssertReturn(pEntry, false); 2000 2001 2001 pEntry->ThreadedCall.uType = kIemTbDbgEntryType_ThreadedCall; 2002 pEntry->ThreadedCall.uUnused = 0; 2003 pEntry->ThreadedCall.enmCall = (uint16_t)enmCall; 2002 pEntry->ThreadedCall.uType = kIemTbDbgEntryType_ThreadedCall; 2003 pEntry->ThreadedCall.fRecompiled = fRecompiled; 2004 pEntry->ThreadedCall.uUnused = 0; 2005 pEntry->ThreadedCall.enmCall = (uint16_t)enmCall; 2004 2006 2005 2007 return true; … … 2526 2528 2527 2529 2528 2529 /** 2530 * Intended use statement for iemNativeRegAllocTmpForGuestReg(). 2531 */ 2532 typedef enum IEMNATIVEGSTREGUSE 2533 { 2534 /** The usage is read-only, the register holding the guest register 2535 * shadow copy will not be modified by the caller. */ 2536 kIemNativeGstRegUse_ReadOnly = 0, 2537 /** The caller will update the guest register (think: PC += cbInstr). 2538 * The guest shadow copy will follow the returned register. */ 2539 kIemNativeGstRegUse_ForUpdate, 2540 /** The caller will use the guest register value as input in a calculation 2541 * and the host register will be modified. 2542 * This means that the returned host register will not be marked as a shadow 2543 * copy of the guest register. */ 2544 kIemNativeGstRegUse_Calculation 2545 } IEMNATIVEGSTREGUSE; 2546 2547 /** 2548 * Allocates a temporary host general purpose register for updating a guest 2530 /** 2531 * Allocates a temporary host general purpose register for keeping a guest 2549 2532 * register value. 2550 2533 * … … 2561 2544 * @param enmGstReg The guest register that will is to be updated. 2562 2545 * @param enmIntendedUse How the caller will be using the host register. 2546 * @sa iemNativeRegAllocTmpForGuestRegIfAlreadyPresent 2563 2547 */ 2564 2548 DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuestReg(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, … … 2678 2662 2679 2663 return idxRegNew; 2664 } 2665 2666 2667 /** 2668 * Allocates a temporary host general purpose register that already holds the 2669 * given guest register value. 2670 * 2671 * The use case for this function is places where the shadowing state cannot be 2672 * modified due to branching and such. This will fail if the we don't have a 2673 * current shadow copy handy or if it's incompatible. The only code that will 2674 * be emitted here is value checking code in strict builds. 2675 * 2676 * The intended use can only be readonly! 2677 * 2678 * @returns The host register number, UINT8_MAX on failure. 2679 * @param pReNative The native recompile state. 2680 * @param poff Pointer to the instruction buffer offset. 2681 * Will be updated in strict builds if a register is 2682 * found. 2683 * @param enmGstReg The guest register that will is to be updated. 2684 * @sa iemNativeRegAllocTmpForGuestReg 2685 */ 2686 DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuestRegIfAlreadyPresent(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, 2687 IEMNATIVEGSTREG enmGstReg) RT_NOEXCEPT 2688 { 2689 Assert(enmGstReg < kIemNativeGstReg_End && g_aGstShadowInfo[enmGstReg].cb != 0); 2690 2691 /* 2692 * First check if the guest register value is already in a host register. 2693 */ 2694 if (pReNative->Core.bmGstRegShadows & RT_BIT_64(enmGstReg)) 2695 { 2696 uint8_t idxReg = pReNative->Core.aidxGstRegShadows[enmGstReg]; 2697 Assert(idxReg < RT_ELEMENTS(pReNative->Core.aHstRegs)); 2698 Assert(pReNative->Core.aHstRegs[idxReg].fGstRegShadows & RT_BIT_64(enmGstReg)); 2699 Assert(pReNative->Core.bmHstRegsWithGstShadow & RT_BIT_32(idxReg)); 2700 2701 if (!(pReNative->Core.bmHstRegs & RT_BIT_32(idxReg))) 2702 { 2703 /* 2704 * We only do readonly use here, so easy compared to the other 2705 * variant of this code. 2706 */ 2707 pReNative->Core.bmHstRegs |= RT_BIT_32(idxReg); 2708 pReNative->Core.aHstRegs[idxReg].enmWhat = kIemNativeWhat_Tmp; 2709 pReNative->Core.aHstRegs[idxReg].idxVar = UINT8_MAX; 2710 Log12(("iemNativeRegAllocTmpForGuestRegIfAlreadyPresent: Reusing %s for guest %s readonly\n", 2711 g_apszIemNativeHstRegNames[idxReg], g_aGstShadowInfo[enmGstReg].pszName)); 2712 2713 #ifdef VBOX_STRICT 2714 /* Strict builds: Check that the value is correct. */ 2715 uint32_t off = *poff; 2716 *poff = off = iemNativeEmitGuestRegValueCheck(pReNative, off, idxReg, enmGstReg); 2717 AssertReturn(off != UINT32_MAX, UINT8_MAX); 2718 #else 2719 RT_NOREF(poff); 2720 #endif 2721 return idxReg; 2722 } 2723 } 2724 2725 return UINT8_MAX; 2680 2726 } 2681 2727 … … 4883 4929 4884 4930 /** 4931 * Built-in function that checks for pending interrupts that can be delivered or 4932 * forced action flags. 4933 * 4934 * This triggers after the completion of an instruction, so EIP is already at 4935 * the next instruction. If an IRQ or important FF is pending, this will return 4936 * a non-zero status that stops TB execution. 4937 */ 4938 static IEM_DECL_IEMNATIVERECOMPFUNC_DEF(iemNativeRecompFunc_BltIn_CheckIrq) 4939 { 4940 RT_NOREF(pCallEntry); 4941 //pReNative->pInstrBuf[off++] = 0xcc; 4942 4943 /* It's too convenient to use iemNativeEmitTestBitInGprAndJmpToLabelIfNotSet below 4944 and I'm too lazy to create a 'Fixed' version of that one. */ 4945 uint32_t const idxLabelVmCheck = iemNativeLabelCreate(pReNative, kIemNativeLabelType_CheckIrq, 4946 UINT32_MAX, pReNative->uCheckIrqSeqNo++); 4947 AssertReturn(idxLabelVmCheck != UINT32_MAX, UINT32_MAX); 4948 4949 uint32_t const idxLabelReturnBreak = iemNativeLabelCreate(pReNative, kIemNativeLabelType_ReturnBreak); 4950 AssertReturn(idxLabelReturnBreak != UINT32_MAX, UINT32_MAX); 4951 4952 /* Again, we need to load the extended EFLAGS before we actually need them 4953 in case we jump. We couldn't use iemNativeRegAllocTmpForGuestReg if we 4954 loaded them inside the check, as the shadow state would not be correct 4955 when the code branches before the load. Ditto PC. */ 4956 uint8_t const idxEflReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_EFlags, 4957 kIemNativeGstRegUse_ReadOnly); 4958 AssertReturn(idxEflReg != UINT8_MAX, UINT32_MAX); 4959 4960 uint8_t const idxPcReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_Pc, 4961 kIemNativeGstRegUse_ReadOnly); 4962 AssertReturn(idxPcReg != UINT8_MAX, UINT32_MAX); 4963 4964 uint8_t idxTmpReg = iemNativeRegAllocTmp(pReNative, &off); 4965 AssertReturn(idxTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX); 4966 4967 /* 4968 * Start by checking the local forced actions of the EMT we're on for IRQs 4969 * and other FFs that needs servicing. 4970 */ 4971 /** @todo this isn't even close to the NMI and interrupt conditions in EM! */ 4972 /* Load FFs in to idxTmpReg and AND with all relevant flags. */ 4973 off = iemNativeEmitLoadGprFromVCpuU64(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, fLocalForcedActions)); 4974 off = iemNativeEmitAndGprByImm(pReNative, off, idxTmpReg, 4975 VMCPU_FF_ALL_MASK & ~( VMCPU_FF_PGM_SYNC_CR3 4976 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL 4977 | VMCPU_FF_TLB_FLUSH 4978 | VMCPU_FF_UNHALT ), 4979 true /*fSetFlags*/); 4980 /* If we end up with ZERO in idxTmpReg there is nothing to do.*/ 4981 uint32_t const offFixupJumpToVmCheck1 = off; 4982 off = iemNativeEmitJzToFixed(pReNative, off, 0); 4983 4984 /* Some relevant FFs are set, but if's only APIC or/and PIC being set, 4985 these may be supressed by EFLAGS.IF or CPUMIsInInterruptShadow. */ 4986 off = iemNativeEmitAndGprByImm(pReNative, off, idxTmpReg, 4987 ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC), true /*fSetFlags*/); 4988 /* Return VINF_IEM_REEXEC_BREAK if other FFs are set. */ 4989 off = iemNativeEmitJnzToLabel(pReNative, off, idxLabelReturnBreak); 4990 4991 /* So, it's only interrupt releated FFs and we need to see if IRQs are being 4992 suppressed by the CPU or not. */ 4993 off = iemNativeEmitTestBitInGprAndJmpToLabelIfNotSet(pReNative, off, idxEflReg, X86_EFL_IF_BIT, idxLabelVmCheck); 4994 off = iemNativeEmitTestAnyBitsInGprAndJmpToLabelIfNoneSet(pReNative, off, idxEflReg, CPUMCTX_INHIBIT_SHADOW, 4995 idxLabelReturnBreak); 4996 4997 /* We've got shadow flags set, so we must check that the PC they are valid 4998 for matches our current PC value. */ 4999 /** @todo AMD64 can do this more efficiently w/o loading uRipInhibitInt into 5000 * a register. */ 5001 off = iemNativeEmitLoadGprFromVCpuU64(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, cpum.GstCtx.uRipInhibitInt)); 5002 off = iemNativeEmitTestIfGprNotEqualGprAndJmpToLabel(pReNative, off, idxTmpReg, idxPcReg, idxLabelReturnBreak); 5003 5004 /* 5005 * Now check the force flags of the VM. 5006 */ 5007 iemNativeLabelDefine(pReNative, idxLabelVmCheck, off); 5008 iemNativeFixupFixedJump(pReNative, offFixupJumpToVmCheck1, off); 5009 off = iemNativeEmitLoadGprFromVCpuU64(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, CTX_SUFF(pVM))); /* idxTmpReg = pVM */ 5010 off = iemNativeEmitLoadGpr32ByGpr(pReNative, off, idxTmpReg, idxTmpReg, RT_UOFFSETOF(VMCC, fGlobalForcedActions)); 5011 off = iemNativeEmitAndGpr32ByImm(pReNative, off, idxTmpReg, VM_FF_ALL_MASK, true /*fSetFlags*/); 5012 off = iemNativeEmitJnzToLabel(pReNative, off, idxLabelReturnBreak); 5013 5014 /** @todo STAM_REL_COUNTER_INC(&pVCpu->iem.s.StatCheckIrqBreaks); */ 5015 5016 /* 5017 * We're good, no IRQs or FFs pending. 5018 */ 5019 iemNativeRegFreeTmp(pReNative, idxTmpReg); 5020 iemNativeRegFreeTmp(pReNative, idxEflReg); 5021 iemNativeRegFreeTmp(pReNative, idxPcReg); 5022 5023 return off; 5024 } 5025 5026 5027 /** 4885 5028 * Built-in function checks if IEMCPU::fExec has the expected value. 4886 5029 */ … … 4888 5031 { 4889 5032 uint32_t const fExpectedExec = (uint32_t)pCallEntry->auParams[0]; 4890 4891 5033 uint8_t idxTmpReg = iemNativeRegAllocTmp(pReNative, &off); 5034 4892 5035 AssertReturn(idxTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX); 4893 5036 off = iemNativeEmitLoadGprFromVCpuU32(pReNative, off, idxTmpReg, RT_UOFFSETOF(VMCPUCC, iem.s.fExec)); … … 5167 5310 case kIemTbDbgEntryType_ThreadedCall: 5168 5311 pHlp->pfnPrintf(pHlp, 5169 " Call #%u to %s (%u args) \n",5312 " Call #%u to %s (%u args)%s\n", 5170 5313 idxThreadedCall, 5171 5314 g_apszIemThreadedFunctions[pDbgInfo->aEntries[iDbgEntry].ThreadedCall.enmCall], 5172 g_acIemThreadedFunctionUsedArgs[pDbgInfo->aEntries[iDbgEntry].ThreadedCall.enmCall]); 5315 g_acIemThreadedFunctionUsedArgs[pDbgInfo->aEntries[iDbgEntry].ThreadedCall.enmCall], 5316 pDbgInfo->aEntries[iDbgEntry].ThreadedCall.fRecompiled ? " - recompiled" : ""); 5173 5317 idxThreadedCall++; 5174 5318 continue; … … 5204 5348 pszName = "ReturnBreak"; 5205 5349 break; 5350 case kIemNativeLabelType_NonZeroRetOrPassUp: 5351 pszName = "NonZeroRetOrPassUp"; 5352 break; 5353 case kIemNativeLabelType_RaiseGp0: 5354 pszName = "RaiseGp0"; 5355 break; 5206 5356 case kIemNativeLabelType_If: 5207 5357 pszName = "If"; … … 5217 5367 fNumbered = true; 5218 5368 break; 5219 case kIemNativeLabelType_NonZeroRetOrPassUp: 5220 pszName = "NonZeroRetOrPassUp"; 5221 break; 5222 case kIemNativeLabelType_RaiseGp0: 5223 pszName = "RaiseGp0"; 5369 case kIemNativeLabelType_CheckIrq: 5370 pszName = "CheckIrq_CheckVM"; 5371 fNumbered = true; 5224 5372 break; 5225 5373 case kIemNativeLabelType_Invalid: … … 5259 5407 uint32_t const uInfo = *(uint32_t const *)&Dis.Instr.ab[3]; 5260 5408 if (RT_HIWORD(uInfo) < kIemThreadedFunc_End) 5261 pHlp->pfnPrintf(pHlp, " %p: nop ; marker: call #%u to %s (%u args)\n", 5262 &paNative[offNative], RT_LOWORD(uInfo), g_apszIemThreadedFunctions[RT_HIWORD(uInfo)], 5263 g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)]); 5409 pHlp->pfnPrintf(pHlp, " %p: nop ; marker: call #%u to %s (%u args)%s\n", 5410 &paNative[offNative], uInfo & 0x7fff, g_apszIemThreadedFunctions[RT_HIWORD(uInfo)], 5411 g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)], 5412 uInfo & 0x8000 ? " - recompiled" : ""); 5264 5413 else 5265 5414 pHlp->pfnPrintf(pHlp, " %p: nop ; unknown marker: %#x (%d)\n", &paNative[offNative], uInfo, uInfo); … … 5346 5495 uint32_t const uInfo = *(uint32_t const *)&Dis.Instr.ab[3]; 5347 5496 if (RT_HIWORD(uInfo) < kIemThreadedFunc_End) 5348 pHlp->pfnPrintf(pHlp, "\n %p: nop ; marker: call #%u to %s (%u args)\n", 5349 &paNative[offNative], RT_LOWORD(uInfo), g_apszIemThreadedFunctions[RT_HIWORD(uInfo)], 5350 g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)]); 5497 pHlp->pfnPrintf(pHlp, "\n %p: nop ; marker: call #%u to %s (%u args)%s\n", 5498 &paNative[offNative], uInfo & 0x7fff, g_apszIemThreadedFunctions[RT_HIWORD(uInfo)], 5499 g_acIemThreadedFunctionUsedArgs[RT_HIWORD(uInfo)], 5500 uInfo & 0x8000 ? " - recompiled" : ""); 5351 5501 else 5352 5502 pHlp->pfnPrintf(pHlp, " %p: nop ; unknown marker: %#x (%d)\n", &paNative[offNative], uInfo, uInfo); … … 5426 5576 while (cCallsLeft-- > 0) 5427 5577 { 5578 PFNIEMNATIVERECOMPFUNC const pfnRecom = g_apfnIemNativeRecompileFunctions[pCallEntry->enmFunction]; 5579 5428 5580 /* 5429 5581 * Debug info and assembly markup. … … 5441 5593 iGstInstr = pCallEntry->idxInstr; 5442 5594 } 5443 iemNativeDbgInfoAddThreadedCall(pReNative, (IEMTHREADEDFUNCS)pCallEntry->enmFunction );5595 iemNativeDbgInfoAddThreadedCall(pReNative, (IEMTHREADEDFUNCS)pCallEntry->enmFunction, pfnRecom != NULL); 5444 5596 #endif 5445 5597 5446 5598 #ifdef VBOX_STRICT 5447 off = iemNativeEmitMarker(pReNative, off, RT_MAKE_U32(pTb->Thrd.cCalls - cCallsLeft - 1, pCallEntry->enmFunction)); 5599 off = iemNativeEmitMarker(pReNative, off, 5600 RT_MAKE_U32((pTb->Thrd.cCalls - cCallsLeft - 1) | (pfnRecom ? 0x8000 : 0), 5601 pCallEntry->enmFunction)); 5448 5602 AssertReturn(off != UINT32_MAX, pTb); 5449 5603 #endif 5604 5450 5605 /* 5451 5606 * Actual work. 5452 5607 */ 5453 PFNIEMNATIVERECOMPFUNC const pfnRecom = g_apfnIemNativeRecompileFunctions[pCallEntry->enmFunction];5454 5608 if (pfnRecom) /** @todo stats on this. */ 5455 5609 { -
trunk/src/VBox/VMM/VMMAll/IEMAllThrdFuncsBltIn.cpp
r101182 r101640 128 128 return VINF_IEM_REEXEC_BREAK; 129 129 } 130 131 130 132 131 -
trunk/src/VBox/VMM/VMMAll/IEMAllThrdPython.py
r101626 r101640 1877 1877 katBltIns = ( 1878 1878 ( 'DeferToCImpl0', 2, True ), 1879 ( 'CheckIrq', 0, False),1879 ( 'CheckIrq', 0, True ), 1880 1880 ( 'CheckMode', 1, True ), 1881 1881 ( 'CheckHwInstrBps', 0, False ), -
trunk/src/VBox/VMM/include/IEMInternal.h
r101547 r101640 929 929 { 930 930 /* kIemTbDbgEntryType_ThreadedCall. */ 931 uint32_t uType : 4; 932 uint32_t uUnused : 12; 931 uint32_t uType : 4; 932 /** Set if the call was recompiled to native code, clear if just calling 933 * threaded function. */ 934 uint32_t fRecompiled : 1; 935 uint32_t uUnused : 11; 933 936 /** The threaded call number (IEMTHREADEDFUNCS). */ 934 uint32_t enmCall : 16;937 uint32_t enmCall : 16; 935 938 } ThreadedCall; 936 939 -
trunk/src/VBox/VMM/include/IEMN8veRecompiler.h
r101626 r101640 263 263 { 264 264 kIemNativeLabelType_Invalid = 0, 265 /* Labels w/o data, only once instance per TB: */ 265 266 kIemNativeLabelType_Return, 266 267 kIemNativeLabelType_ReturnBreak, 268 kIemNativeLabelType_NonZeroRetOrPassUp, 269 kIemNativeLabelType_RaiseGp0, 270 /* Labels with data, potentially multiple instances per TB: */ 267 271 kIemNativeLabelType_If, 268 272 kIemNativeLabelType_Else, 269 273 kIemNativeLabelType_Endif, 270 kIemNativeLabelType_NonZeroRetOrPassUp, 271 kIemNativeLabelType_RaiseGp0, 274 kIemNativeLabelType_CheckIrq, 272 275 kIemNativeLabelType_End 273 276 } IEMNATIVELABELTYPE; … … 338 341 kIemNativeGstReg_End 339 342 } IEMNATIVEGSTREG; 343 344 /** 345 * Intended use statement for iemNativeRegAllocTmpForGuestReg(). 346 */ 347 typedef enum IEMNATIVEGSTREGUSE 348 { 349 /** The usage is read-only, the register holding the guest register 350 * shadow copy will not be modified by the caller. */ 351 kIemNativeGstRegUse_ReadOnly = 0, 352 /** The caller will update the guest register (think: PC += cbInstr). 353 * The guest shadow copy will follow the returned register. */ 354 kIemNativeGstRegUse_ForUpdate, 355 /** The caller will use the guest register value as input in a calculation 356 * and the host register will be modified. 357 * This means that the returned host register will not be marked as a shadow 358 * copy of the guest register. */ 359 kIemNativeGstRegUse_Calculation 360 } IEMNATIVEGSTREGUSE; 340 361 341 362 /** … … 591 612 /** Condition sequence number (for generating unique labels). */ 592 613 uint16_t uCondSeqNo; 593 uint32_t uPadding3; 614 /** Check IRQ seqeunce number (for generating unique lables). */ 615 uint16_t uCheckIrqSeqNo; 616 uint16_t uPadding3; 594 617 595 618 /** Core state requiring care with branches. */ … … 624 647 #define IEM_DECL_IEMNATIVERECOMPFUNC_PROTO(a_Name) FNIEMNATIVERECOMPFUNC a_Name 625 648 626 627 649 DECLHIDDEN(uint32_t) iemNativeLabelCreate(PIEMRECOMPILERSTATE pReNative, IEMNATIVELABELTYPE enmType, 628 650 uint32_t offWhere = UINT32_MAX, uint16_t uData = 0) RT_NOEXCEPT; … … 637 659 DECLHIDDEN(uint8_t) iemNativeRegAllocTmpImm(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, uint64_t uImm, 638 660 bool fPreferVolatile = true) RT_NOEXCEPT; 639 DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuest(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, 640 IEMNATIVEGSTREG enmGstReg) RT_NOEXCEPT; 661 DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuestReg(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, 662 IEMNATIVEGSTREG enmGstReg, 663 IEMNATIVEGSTREGUSE enmIntendedUse) RT_NOEXCEPT; 664 DECLHIDDEN(uint8_t) iemNativeRegAllocTmpForGuestRegIfAlreadyPresent(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, 665 IEMNATIVEGSTREG enmGstReg) RT_NOEXCEPT; 666 641 667 DECLHIDDEN(uint8_t) iemNativeRegAllocVar(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, uint8_t idxVar) RT_NOEXCEPT; 642 668 DECLHIDDEN(uint32_t) iemNativeRegAllocArgs(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t cArgs) RT_NOEXCEPT; … … 970 996 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R; 971 997 pbCodeBuf[off++] = 0x8b; 972 off = iemNativeEmitGprByVCpuDisp(pbCodeBuf, off,iGpr, offVCpu);998 off = iemNativeEmitGprByVCpuDisp(pbCodeBuf, off,iGpr, offVCpu); 973 999 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 974 1000 … … 1263 1289 * Emits a load effective address to a GRP with an BP relative source address. 1264 1290 */ 1265 DECLINLINE(uint32_t) iemNativeEmitLeaG rpByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)1291 DECLINLINE(uint32_t) iemNativeEmitLeaGprByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp) 1266 1292 { 1267 1293 /* lea gprdst, [rbp + offDisp] */ … … 1374 1400 1375 1401 1402 #ifdef RT_ARCH_AMD64 1403 /** 1404 * Common bit of iemNativeEmitLoadGprByGpr and friends. 1405 */ 1406 DECL_FORCE_INLINE(uint32_t) iemNativeEmitGprByGprDisp(uint8_t *pbCodeBuf, uint32_t off, 1407 uint8_t iGprReg, uint8_t iGprBase, int32_t offDisp) 1408 { 1409 if (offDisp == 0 && (iGprBase & 7) != X86_GREG_xBP) /* Can use encoding w/o displacement field. */ 1410 { 1411 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM0, iGprReg & 7, iGprBase & 7); 1412 if ((iGprBase & 7) == X86_GREG_xSP) /* for RSP/R12 relative addressing we have to use a SIB byte. */ 1413 pbCodeBuf[off++] = X86_SIB_MAKE(X86_GREG_xSP, X86_GREG_xSP, 0); /* -> [RSP/R12] */ 1414 } 1415 else if (offDisp == (int8_t)offDisp) 1416 { 1417 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGprReg & 7, iGprBase & 7); 1418 if ((iGprBase & 7) == X86_GREG_xSP) /* for RSP/R12 relative addressing we have to use a SIB byte. */ 1419 pbCodeBuf[off++] = X86_SIB_MAKE(X86_GREG_xSP, X86_GREG_xSP, 0); /* -> [RSP/R12] */ 1420 pbCodeBuf[off++] = (uint8_t)offDisp; 1421 } 1422 else 1423 { 1424 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGprReg & 7, iGprBase & 7); 1425 if ((iGprBase & 7) == X86_GREG_xSP) /* for RSP/R12 relative addressing we have to use a SIB byte. */ 1426 pbCodeBuf[off++] = X86_SIB_MAKE(X86_GREG_xSP, X86_GREG_xSP, 0); /* -> [RSP/R12] */ 1427 pbCodeBuf[off++] = RT_BYTE1((uint32_t)offDisp); 1428 pbCodeBuf[off++] = RT_BYTE2((uint32_t)offDisp); 1429 pbCodeBuf[off++] = RT_BYTE3((uint32_t)offDisp); 1430 pbCodeBuf[off++] = RT_BYTE4((uint32_t)offDisp); 1431 } 1432 return off; 1433 } 1434 #elif RT_ARCH_ARM64 1435 /** 1436 * Common bit of iemNativeEmitLoadGprFromVCpuU64 and friends. 1437 */ 1438 DECL_FORCE_INLINE(uint32_t) iemNativeEmitGprByGprLdSt(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprReg, 1439 uint8_t iGprBase, int32_t offDisp, 1440 ARMV8A64INSTRLDSTTYPE enmOperation, unsigned cbData) 1441 { 1442 /* 1443 * There are a couple of ldr variants that takes an immediate offset, so 1444 * try use those if we can, otherwise we have to use the temporary register 1445 * help with the addressing. 1446 */ 1447 if ((uint32_t)offDisp < _4K * cbData && !((uint32_t)offDisp & (cbData - 1))) 1448 { 1449 /* Use the unsigned variant of ldr Wt, [<Xn|SP>, #off]. */ 1450 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 1451 AssertReturn(pu32CodeBuf, UINT32_MAX); 1452 pu32CodeBuf[off++] = Armv8A64MkInstrStLdRUOff(enmOperation, iGprReg, iGprBase, (uint32_t)offDisp / cbData); 1453 } 1454 else 1455 { 1456 /* The offset is too large, so we must load it into a register and use 1457 ldr Wt, [<Xn|SP>, (<Wm>|<Xm>)]. */ 1458 /** @todo reduce by offVCpu by >> 3 or >> 2? if it saves instructions? */ 1459 uint8_t const idxTmpReg = iemNativeRegAllocTmpImm(pReNative, off, (uint64)offDisp); 1460 AssertReturn(idxTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX); 1461 1462 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 1463 AssertReturn(pu32CodeBuf, UINT32_MAX); 1464 pu32CodeBuf[off++] = Armv8A64MkInstrStLdRegIdx(enmOperation, iGprReg, iGprBase, idxTmpReg); 1465 1466 iemNativeRegFreeTmpImm(pReNative, idxTmpReg); 1467 } 1468 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 1469 return off; 1470 } 1471 #endif 1472 1473 1474 /** 1475 * Emits a 64-bit GPR load via a GPR base address with a displacement. 1476 */ 1477 DECLINLINE(uint32_t) iemNativeEmitLoadGprByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, 1478 uint8_t iGprDst, uint8_t iGprBase, int32_t offDisp) 1479 { 1480 #ifdef RT_ARCH_AMD64 1481 /* mov reg64, mem64 */ 1482 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 8); 1483 AssertReturn(pbCodeBuf, UINT32_MAX); 1484 pbCodeBuf[off++] = X86_OP_REX_W | (iGprDst < 8 ? 0 : X86_OP_REX_R) | (iGprBase < 8 ? 0 : X86_OP_REX_B); 1485 pbCodeBuf[off++] = 0x8b; 1486 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, iGprDst, iGprBase, offDisp); 1487 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 1488 1489 #elif RT_ARCH_ARM64 1490 off = iemNativeEmitGprByGprLdSt(pReNative, off, iGprDst, offDisp, kArmv8A64InstrLdStType_Ld_Dword, sizeof(uint64_t)); 1491 1492 #else 1493 # error "port me" 1494 #endif 1495 return off; 1496 } 1497 1498 1499 /** 1500 * Emits a 32-bit GPR load via a GPR base address with a displacement. 1501 * @note Bits 63 thru 32 in @a iGprDst will be cleared. 1502 */ 1503 DECLINLINE(uint32_t) iemNativeEmitLoadGpr32ByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, 1504 uint8_t iGprDst, uint8_t iGprBase, int32_t offDisp) 1505 { 1506 #ifdef RT_ARCH_AMD64 1507 /* mov reg32, mem32 */ 1508 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 8); 1509 AssertReturn(pbCodeBuf, UINT32_MAX); 1510 if (iGprDst >= 8 || iGprBase >= 8) 1511 pbCodeBuf[off++] = (iGprDst < 8 ? 0 : X86_OP_REX_R) | (iGprBase < 8 ? 0 : X86_OP_REX_B); 1512 pbCodeBuf[off++] = 0x8b; 1513 off = iemNativeEmitGprByGprDisp(pbCodeBuf, off, iGprDst, iGprBase, offDisp); 1514 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 1515 1516 #elif RT_ARCH_ARM64 1517 off = iemNativeEmitGprByGprLdSt(pReNative, off, iGprDst, offDisp, kArmv8A64InstrLdStType_Ld_Word, sizeof(uint32_t)); 1518 1519 #else 1520 # error "port me" 1521 #endif 1522 return off; 1523 } 1524 1525 1376 1526 /********************************************************************************************************************************* 1377 1527 * Subtraction and Additions * … … 1683 1833 /** 1684 1834 * Emits code for AND'ing two 64-bit GPRs. 1685 */ 1686 DECLINLINE(uint32_t ) iemNativeEmitAndGprByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint8_t iGprSrc) 1835 * 1836 * @note When fSetFlags=true, JZ/JNZ jumps can be used afterwards on both AMD64 1837 * and ARM64 hosts. 1838 */ 1839 DECLINLINE(uint32_t ) iemNativeEmitAndGprByGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint8_t iGprSrc, 1840 bool fSetFlags = false) 1687 1841 { 1688 1842 #if defined(RT_ARCH_AMD64) … … 1693 1847 pbCodeBuf[off++] = 0x23; 1694 1848 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGprDst & 7, iGprSrc & 7); 1849 RT_NOREF(fSetFlags); 1695 1850 1696 1851 #elif defined(RT_ARCH_ARM64) 1697 1852 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 1698 1853 AssertReturn(pu32CodeBuf, UINT32_MAX); 1699 pu32CodeBuf[off++] = Armv8A64MkInstrAnd(iGprDst, iGprDst, iGprSrc); 1854 if (!fSetFlags) 1855 pu32CodeBuf[off++] = Armv8A64MkInstrAnd(iGprDst, iGprDst, iGprSrc); 1856 else 1857 pu32CodeBuf[off++] = Armv8A64MkInstrAnds(iGprDst, iGprDst, iGprSrc); 1700 1858 1701 1859 #else … … 1735 1893 1736 1894 /** 1737 * Emits code for AND'ing an 32-bit GPRs with a constant. 1738 */ 1739 DECLINLINE(uint32_t ) iemNativeEmitAndGpr32ByImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint32_t uImm) 1895 * Emits code for AND'ing a 64-bit GPRs with a constant. 1896 * 1897 * @note When fSetFlags=true, JZ/JNZ jumps can be used afterwards on both AMD64 1898 * and ARM64 hosts. 1899 */ 1900 DECLINLINE(uint32_t ) iemNativeEmitAndGprByImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint64_t uImm, 1901 bool fSetFlags = false) 1740 1902 { 1741 1903 #if defined(RT_ARCH_AMD64) 1742 /* and Ev, imm */ 1743 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7); 1744 AssertReturn(pbCodeBuf, UINT32_MAX); 1745 if (iGprDst >= 8) 1746 pbCodeBuf[off++] = X86_OP_REX_R; 1747 if (uImm < 128) 1748 { 1904 if ((int64_t)uImm == (int8_t)uImm) 1905 { 1906 /* and Ev, imm8 */ 1907 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 4); 1908 AssertReturn(pbCodeBuf, UINT32_MAX); 1909 pbCodeBuf[off++] = X86_OP_REX_W | (iGprDst < 8 ? 0 : X86_OP_REX_R); 1749 1910 pbCodeBuf[off++] = 0x83; 1750 1911 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7); 1751 1912 pbCodeBuf[off++] = (uint8_t)uImm; 1752 1913 } 1753 else 1754 { 1914 else if ((int64_t)uImm == (int32_t)uImm) 1915 { 1916 /* and Ev, imm32 */ 1917 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7); 1918 AssertReturn(pbCodeBuf, UINT32_MAX); 1919 pbCodeBuf[off++] = X86_OP_REX_W | (iGprDst < 8 ? 0 : X86_OP_REX_R); 1755 1920 pbCodeBuf[off++] = 0x81; 1756 1921 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7); … … 1760 1925 pbCodeBuf[off++] = RT_BYTE4(uImm); 1761 1926 } 1927 else 1928 { 1929 /* Use temporary register for the 64-bit immediate. */ 1930 uint8_t iTmpReg = iemNativeRegAllocTmpImm(pReNative, &off, uImm); 1931 AssertReturn(iTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX); 1932 off = iemNativeEmitAndGprByGpr(pReNative, off, iGprDst, iTmpReg); 1933 iemNativeRegFreeTmpImm(pReNative, iTmpReg); 1934 } 1935 RT_NOREF(fSetFlags); 1762 1936 1763 1937 #elif defined(RT_ARCH_ARM64) … … 1768 1942 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 1769 1943 AssertReturn(pu32CodeBuf, UINT32_MAX); 1770 pu32CodeBuf[off++] = Armv8A64MkInstrAndImm(iGprDst, iGprDst, uImmNandS, uImmR, false /*f64Bit*/); 1771 } 1772 else 1773 { 1774 /* Use temporary register for the immediate. */ 1944 if (!fSetFlags) 1945 pu32CodeBuf[off++] = Armv8A64MkInstrAndImm(iGprDst, iGprDst, uImmNandS, uImmR); 1946 else 1947 pu32CodeBuf[off++] = Armv8A64MkInstrAndsImm(iGprDst, iGprDst, uImmNandS, uImmR); 1948 } 1949 else 1950 { 1951 /* Use temporary register for the 64-bit immediate. */ 1775 1952 uint8_t iTmpReg = iemNativeRegAllocTmpImm(pReNative, &off, uImm); 1776 1953 AssertReturn(iTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX); 1777 1778 /* and gprdst, gprdst, tmpreg */ 1954 off = iemNativeEmitAndGprByGpr(pReNative, off, iGprDst, iTmpReg, fSetFlags); 1955 iemNativeRegFreeTmpImm(pReNative, iTmpReg); 1956 } 1957 1958 #else 1959 # error "Port me" 1960 #endif 1961 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 1962 return off; 1963 } 1964 1965 1966 /** 1967 * Emits code for AND'ing an 32-bit GPRs with a constant. 1968 */ 1969 DECLINLINE(uint32_t ) iemNativeEmitAndGpr32ByImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint32_t uImm, 1970 bool fSetFlags = false) 1971 { 1972 #if defined(RT_ARCH_AMD64) 1973 /* and Ev, imm */ 1974 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7); 1975 AssertReturn(pbCodeBuf, UINT32_MAX); 1976 if (iGprDst >= 8) 1977 pbCodeBuf[off++] = X86_OP_REX_R; 1978 if ((int32_t)uImm == (int8_t)uImm) 1979 { 1980 pbCodeBuf[off++] = 0x83; 1981 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7); 1982 pbCodeBuf[off++] = (uint8_t)uImm; 1983 } 1984 else 1985 { 1986 pbCodeBuf[off++] = 0x81; 1987 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 4, iGprDst & 7); 1988 pbCodeBuf[off++] = RT_BYTE1(uImm); 1989 pbCodeBuf[off++] = RT_BYTE2(uImm); 1990 pbCodeBuf[off++] = RT_BYTE3(uImm); 1991 pbCodeBuf[off++] = RT_BYTE4(uImm); 1992 } 1993 RT_NOREF(fSetFlags); 1994 1995 #elif defined(RT_ARCH_ARM64) 1996 uint32_t uImmR = 0; 1997 uint32_t uImmNandS = 0; 1998 if (Armv8A64ConvertMaskToImmRImmS(uImm, &uImmNandS, &uImmR)) 1999 { 1779 2000 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 1780 2001 AssertReturn(pu32CodeBuf, UINT32_MAX); 1781 pu32CodeBuf[off++] = Armv8A64MkInstrAnd(iGprDst, iGprDst, iTmpReg, false /*f64Bit*/); 1782 2002 if (!fSetFlags) 2003 pu32CodeBuf[off++] = Armv8A64MkInstrAndImm(iGprDst, iGprDst, uImmNandS, uImmR, false /*f64Bit*/); 2004 else 2005 pu32CodeBuf[off++] = Armv8A64MkInstrAndsImm(iGprDst, iGprDst, uImmNandS, uImmR, false /*f64Bit*/); 2006 } 2007 else 2008 { 2009 /* Use temporary register for the 64-bit immediate. */ 2010 uint8_t iTmpReg = iemNativeRegAllocTmpImm(pReNative, &off, uImm); 2011 AssertReturn(iTmpReg < RT_ELEMENTS(pReNative->Core.aHstRegs), UINT32_MAX); 2012 if (!fSetFlags) 2013 off = iemNativeEmitAndGpr32ByGpr32(pReNative, off, iGprDst, iTmpReg); 2014 else 2015 off = iemNativeEmitAndsGpr32ByGpr32(pReNative, off, iGprDst, iTmpReg); 1783 2016 iemNativeRegFreeTmpImm(pReNative, iTmpReg); 1784 2017 } … … 2724 2957 iemNativeRegFreeTmpImm(pReNative, iTmpReg); 2725 2958 } 2726 else 2959 else if (fBits <= UINT32_MAX) 2727 2960 { 2728 2961 /* test Eb, imm8 or test Ev, imm32 */ … … 2747 2980 } 2748 2981 } 2982 /** @todo implement me. */ 2983 else 2984 AssertFailedReturn(UINT32_MAX); 2749 2985 2750 2986 #elif defined(RT_ARCH_ARM64)
Note:
See TracChangeset
for help on using the changeset viewer.