VirtualBox

Ignore:
Timestamp:
Mar 7, 2024 12:11:33 PM (13 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
162096
Message:

VMM/IEM: Initial implementation of a SIMD register allocator and associated code in order to be able to recompile SSE/AVX instructions (disabled by default and only working on ARM64 right now), bugref:10614

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/include/IEMN8veRecompiler.h

    r103671 r103728  
    157157 * Mask GPRs with fixes assignments, either by us or dictated by the CPU/OS
    158158 * architecture. */
     159#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     160/** @def IEMNATIVE_SIMD_REG_FIXED_TMP0
     161 * Mask SIMD registers with fixes assignments, either by us or dictated by the CPU/OS
     162 * architecture. */
     163/** @def IEMNATIVE_SIMD_REG_FIXED_TMP0
     164 * Dedicated temporary SIMD register. */
     165#endif
    159166#if defined(RT_ARCH_AMD64) && !defined(DOXYGEN_RUNNING)
    160167# define IEMNATIVE_REG_FIXED_PVMCPU         X86_GREG_xBX
     
    164171                                            | RT_BIT_32(X86_GREG_xSP) \
    165172                                            | RT_BIT_32(X86_GREG_xBP) )
     173
     174# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     175#  if defined(IEMNATIVE_WITH_SIMD_REG_ACCESS_ALL_REGISTERS) || !defined(_MSC_VER)
     176#   define IEMNATIVE_SIMD_REG_FIXED_MASK   0
     177#  else
     178/** On Windows xmm6 through xmm15 are marked as callee saved. */
     179#   define IEMNATIVE_SIMD_REG_FIXED_MASK   (UINT32_C(0xffc0))
     180#  endif
     181# endif
    166182
    167183#elif defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING)
     
    186202                                             | IEMNATIVE_REG_FIXED_MASK_ADD)
    187203
     204# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     205# define IEMNATIVE_SIMD_REG_FIXED_TMP0     ARMV8_A64_REG_Q30
     206#  if defined(IEMNATIVE_WITH_SIMD_REG_ACCESS_ALL_REGISTERS)
     207#   define IEMNATIVE_SIMD_REG_FIXED_MASK   RT_BIT_32(ARMV8_A64_REG_Q30)
     208#  else
     209/** arm64 declares the low 64-bit of v8-v15 as callee saved. */
     210#   define IEMNATIVE_SIMD_REG_FIXED_MASK   (  UINT32_C(0xff00) \
     211                                            | RT_BIT_32(ARMV8_A64_REG_Q30))
     212#  endif
     213# endif
     214
    188215#else
    189216# error "port me"
     
    227254                                             | RT_BIT_32(X86_GREG_x10) \
    228255                                             | RT_BIT_32(X86_GREG_x11) )
     256#  ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     257/* xmm0 - xmm5 are marked as volatile. */
     258#   define IEMNATIVE_CALL_VOLATILE_SIMD_REG_MASK (UINT32_C(0x3f))
     259#  endif
     260
    229261# else
    230262#  define IEMNATIVE_CALL_ARG_GREG_COUNT     6
     
    250282                                             | RT_BIT_32(X86_GREG_x10) \
    251283                                             | RT_BIT_32(X86_GREG_x11) )
     284#  ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     285/* xmm0 - xmm15 are marked as volatile. */
     286#   define IEMNATIVE_CALL_VOLATILE_SIMD_REG_MASK (UINT32_C(0xffff))
     287#  endif
    252288# endif
    253289
     
    289325                                             | RT_BIT_32(ARMV8_A64_REG_X16) \
    290326                                             | RT_BIT_32(ARMV8_A64_REG_X17) )
     327# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     328/* The low 64 bits of v8 - v15 marked as callee saved but the rest is volatile,
     329 * so to simplify our life a bit we just mark everything as volatile. */
     330#  define IEMNATIVE_CALL_VOLATILE_SIMD_REG_MASK (UINT32_C(0xffffffff))
     331# endif
    291332
    292333#endif
     
    306347 * Mask corresponding to IEMNATIVE_HST_GREG_COUNT that can be applied to
    307348 * inverted register masks and such to get down to a correct set of regs. */
     349#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     350/** @def IEMNATIVE_HST_SIMD_REG_COUNT
     351 * Number of host SIMD registers we track. */
     352/** @def IEMNATIVE_HST_SIMD_REG_MASK
     353 * Mask corresponding to IEMNATIVE_HST_SIMD_REG_COUNT that can be applied to
     354 * inverted register masks and such to get down to a correct set of regs. */
     355#endif
    308356#ifdef RT_ARCH_AMD64
    309357# define IEMNATIVE_HST_GREG_COUNT           16
    310358# define IEMNATIVE_HST_GREG_MASK            UINT32_C(0xffff)
    311359
     360# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     361#  define IEMNATIVE_HST_SIMD_REG_COUNT      16
     362#  define IEMNATIVE_HST_SIMD_REG_MASK       UINT32_C(0xffff)
     363# endif
     364
    312365#elif defined(RT_ARCH_ARM64)
    313366# define IEMNATIVE_HST_GREG_COUNT           32
    314367# define IEMNATIVE_HST_GREG_MASK            UINT32_MAX
     368
     369# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     370#  define IEMNATIVE_HST_SIMD_REG_COUNT      32
     371#  define IEMNATIVE_HST_SIMD_REG_MASK       UINT32_MAX
     372# endif
     373
    315374#else
    316375# error "Port me!"
     
    735794/** @} */
    736795
     796
     797#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     798/**
     799 * Guest registers that can be shadowed in host SIMD registers.
     800 *
     801 * @todo r=aeichner Liveness tracking
     802 * @todo r=aeichner Given that we can only track xmm/ymm here does this actually make sense?
     803 */
     804typedef enum IEMNATIVEGSTSIMDREG : uint8_t
     805{
     806    kIemNativeGstSimdReg_SimdRegFirst  = 0,
     807    kIemNativeGstSimdReg_SimdRegLast   = kIemNativeGstSimdReg_SimdRegFirst + 15,
     808    kIemNativeGstSimdReg_End
     809} IEMNATIVEGSTSIMDREG;
     810
     811/** @name Helpers for converting register numbers to IEMNATIVEGSTSIMDREG values.
     812 * @{  */
     813#define IEMNATIVEGSTSIMDREG_SIMD(a_iSimdReg)   ((IEMNATIVEGSTSIMDREG)(kIemNativeGstSimdReg_SimdRegFirst + (a_iSimdReg)))
     814/** @} */
     815
     816/**
     817 * The Load/store size for a SIMD guest register.
     818 */
     819typedef enum IEMNATIVEGSTSIMDREGLDSTSZ : uint8_t
     820{
     821    /** Invalid size. */
     822    kIemNativeGstSimdRegLdStSz_Invalid = 0,
     823    /** Loads the low 128-bit of a guest SIMD register. */
     824    kIemNativeGstSimdRegLdStSz_Low128,
     825    /** Loads the high 128-bit of a guest SIMD register. */
     826    kIemNativeGstSimdRegLdStSz_High128,
     827    /** Loads the whole 256-bits of a guest SIMD register. */
     828    kIemNativeGstSimdRegLdStSz_256,
     829    /** End value. */
     830    kIemNativeGstSimdRegLdStSz_End
     831} IEMNATIVEGSTSIMDREGLDSTSZ;
     832#endif
     833
     834
    737835/**
    738836 * Intended use statement for iemNativeRegAllocTmpForGuestReg().
     
    9121010
    9131011
     1012#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     1013/**
     1014 * Host SIMD register entry - this tracks a virtual 256-bit register split into two 128-bit
     1015 * halves, on architectures where there is no 256-bit register available this entry will track
     1016 * two adjacent 128-bit host registers.
     1017 *
     1018 * The actual allocation status is kept in IEMRECOMPILERSTATE::bmHstSimdRegs.
     1019 */
     1020typedef struct IEMNATIVEHSTSIMDREG
     1021{
     1022    /** Set of guest registers this one shadows.
     1023     *
     1024     * Using a bitmap here so we can designate the same host register as a copy
     1025     * for more than one guest register.  This is expected to be useful in
     1026     * situations where one value is copied to several registers in a sequence.
     1027     * If the mapping is 1:1, then we'd have to pick which side of a 'MOV SRC,DST'
     1028     * sequence we'd want to let this register follow to be a copy of and there
     1029     * will always be places where we'd be picking the wrong one.
     1030     */
     1031    uint64_t                  fGstRegShadows;
     1032    /** What is being kept in this register. */
     1033    IEMNATIVEWHAT             enmWhat;
     1034    /** Flag what is currently loaded, low 128-bits, high 128-bits or complete 256-bits. */
     1035    IEMNATIVEGSTSIMDREGLDSTSZ enmLoaded;
     1036    /** Alignment padding. */
     1037    uint8_t                   abAlign[6];
     1038} IEMNATIVEHSTSIMDREG;
     1039#endif
     1040
     1041
    9141042/**
    9151043 * Core state for the native recompiler, that is, things that needs careful
     
    9351063    uint64_t                    bmGstRegShadows;
    9361064
     1065#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     1066    /** Allocation bitmap for aHstSimdRegs. */
     1067    uint32_t                    bmHstSimdRegs;
     1068
     1069    /** Bitmap marking which host SIMD register contains guest SIMD register shadow copies.
     1070     * This is used during register allocation to try preserve copies.  */
     1071    uint32_t                    bmHstSimdRegsWithGstShadow;
     1072    /** Bitmap marking valid entries in aidxSimdGstRegShadows. */
     1073    uint64_t                    bmGstSimdRegShadows;
     1074    /** Bitmap marking whether the low 128-bit of the shadowed guest register are dirty and need writeback. */
     1075    uint64_t                    bmGstSimdRegShadowDirtyLo128;
     1076    /** Bitmap marking whether the high 128-bit of the shadowed guest register are dirty and need writeback. */
     1077    uint64_t                    bmGstSimdRegShadowDirtyHi128;
     1078#endif
     1079
    9371080    union
    9381081    {
     
    9531096     * there are no duplicate copies or ambiguities like that). */
    9541097    uint8_t                     aidxGstRegShadows[kIemNativeGstReg_End];
     1098#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     1099    /** Maps a guest SIMD register to a host SIMD register (index by IEMNATIVEGSTSIMDREG).
     1100     * Entries are only valid if the corresponding bit in bmGstSimdRegShadows is set.
     1101     * (A shadow copy of a guest register can only be held in a one host register,
     1102     * there are no duplicate copies or ambiguities like that). */
     1103    uint8_t                     aidxGstSimdRegShadows[kIemNativeGstSimdReg_End];
     1104#endif
    9551105
    9561106    /** Host register allocation tracking. */
    9571107    IEMNATIVEHSTREG             aHstRegs[IEMNATIVE_HST_GREG_COUNT];
     1108#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     1109    /** Host SIMD register allocation tracking. */
     1110    IEMNATIVEHSTSIMDREG         aHstSimdRegs[IEMNATIVE_HST_SIMD_REG_COUNT];
     1111#endif
    9581112
    9591113    /** Variables and arguments. */
     
    9821136# define IEMNATIVE_VAR_IDX_UNPACK(a_idxVar) (a_idxVar)
    9831137# define IEMNATIVE_VAR_IDX_PACK(a_idxVar)   (a_idxVar)
     1138#endif
     1139
     1140
     1141#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     1142/** Clear the dirty state of the given guest SIMD register. */
     1143# define IEMNATIVE_SIMD_REG_STATE_CLR_DIRTY(a_pReNative, a_iSimdReg) \
     1144    do { \
     1145        (a_pReNative)->Core.bmGstSimdRegShadowDirtyLo128 &= ~RT_BIT_64(a_iSimdReg); \
     1146        (a_pReNative)->Core.bmGstSimdRegShadowDirtyHi128 &= ~RT_BIT_64(a_iSimdReg); \
     1147    } while (0)
     1148
     1149/** Returns whether the low 128-bits of the given guest SIMD register are dirty. */
     1150# define IEMNATIVE_SIMD_REG_STATE_IS_DIRTY_LO_U128(a_pReNative, a_iSimdReg) \
     1151    RT_BOOL((a_pReNative)->Core.bmGstSimdRegShadowDirtyLo128 & RT_BIT_64(a_iSimdReg))
     1152/** Returns whether the high 128-bits of the given guest SIMD register are dirty. */
     1153# define IEMNATIVE_SIMD_REG_STATE_IS_DIRTY_HI_U128(a_pReNative, a_iSimdReg) \
     1154    RT_BOOL((a_pReNative)->Core.bmGstSimdRegShadowDirtyHi128 & RT_BIT_64(a_iSimdReg))
     1155/** Returns whether the given guest SIMD register is dirty. */
     1156# define IEMNATIVE_SIMD_REG_STATE_IS_DIRTY_U256(a_pReNative, a_iSimdReg) \
     1157    RT_BOOL(((a_pReNative)->Core.bmGstSimdRegShadowDirtyLo128 | (a_pReNative)->Core.bmGstSimdRegShadowDirtyHi128) & RT_BIT_64(a_iSimdReg))
     1158
     1159/** Set the low 128-bits of the given guest SIMD register to the dirty state. */
     1160# define IEMNATIVE_SIMD_REG_STATE_SET_DIRTY_LO_U128(a_pReNative, a_iSimdReg) \
     1161    ((a_pReNative)->Core.bmGstSimdRegShadowDirtyLo128 |= RT_BIT_64(a_iSimdReg))
     1162/** Set the high 128-bits of the given guest SIMD register to the dirty state. */
     1163# define IEMNATIVE_SIMD_REG_STATE_SET_DIRTY_HI_U128(a_pReNative, a_iSimdReg) \
     1164    ((a_pReNative)->Core.bmGstSimdRegShadowDirtyHi128 |= RT_BIT_64(a_iSimdReg))
    9841165#endif
    9851166
     
    12381419DECLHIDDEN(void)            iemNativeRegFreeVar(PIEMRECOMPILERSTATE pReNative, uint8_t idxHstReg, bool fFlushShadows) RT_NOEXCEPT;
    12391420DECLHIDDEN(void)            iemNativeRegFreeAndFlushMask(PIEMRECOMPILERSTATE pReNative, uint32_t fHstRegMask) RT_NOEXCEPT;
    1240 DECL_HIDDEN_THROW(uint32_t) iemNativeRegFlushPendingWrites(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint64_t fGstShwExept = 0);
     1421DECL_HIDDEN_THROW(uint32_t) iemNativeRegFlushPendingWrites(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint64_t fGstShwExept = 0, bool fFlushShadows = true);
    12411422DECL_HIDDEN_THROW(uint32_t) iemNativeRegMoveAndFreeAndFlushAtCall(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t cArgs,
    12421423                                                                  uint32_t fKeepVars = 0);
     
    12641445DECL_HIDDEN_THROW(uint32_t) iemNativeEmitThreadedCall(PIEMRECOMPILERSTATE pReNative, uint32_t off,
    12651446                                                      PCIEMTHRDEDCALLENTRY pCallEntry);
     1447
     1448#ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
     1449DECL_HIDDEN_THROW(uint8_t) iemNativeSimdRegAllocTmp(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, bool fPreferVolatile = true);
     1450DECL_HIDDEN_THROW(uint8_t) iemNativeSimdRegAllocTmpEx(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, uint32_t fRegMask,
     1451                                                      bool fPreferVolatile = true);
     1452DECL_HIDDEN_THROW(uint8_t) iemNativeSimdRegAllocTmpForGuestSimdReg(PIEMRECOMPILERSTATE pReNative, uint32_t *poff, IEMNATIVEGSTSIMDREG enmGstSimdReg,
     1453                                                                   IEMNATIVEGSTSIMDREGLDSTSZ enmLoadSz, IEMNATIVEGSTREGUSE enmIntendedUse = kIemNativeGstRegUse_ReadOnly,
     1454                                                                   bool fNoVolatileRegs = false);
     1455DECL_HIDDEN_THROW(uint32_t) iemNativeEmitLoadSimdRegWithGstShadowSimdReg(PIEMRECOMPILERSTATE pReNative, uint32_t off,
     1456                                                                         uint8_t idxHstSimdReg, IEMNATIVEGSTSIMDREG enmGstSimdReg,
     1457                                                                         IEMNATIVEGSTSIMDREGLDSTSZ enmLoadSz);
     1458#endif
    12661459
    12671460extern DECL_HIDDEN_DATA(const char * const) g_apszIemNativeHstRegNames[];
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