VirtualBox

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


Ignore:
Timestamp:
Nov 12, 2023 1:36:45 AM (17 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
160181
Message:

VMM/IEM: Native translation of IEM_MC_CLEAR_HIGH_GREG_U64. Had to extend IEMAllN8veRecompiler.py to insert IEM_MC_FREE_LOCAL (and IEM_MC_FREE_ARG) into ELSE branches to simplify state consolidation on IEM_MC_ENDIF (had trouble with cmovxx). bugref:10371

Location:
trunk/src/VBox/VMM/VMMAll
Files:
4 edited

Legend:

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

    r102069 r102070  
    19911991    ## @}
    19921992
    1993     def __init__(self, sSrcFile, iBeginLine, offBeginLine, oFunction, iInFunction, cchIndent = None):
     1993    def __init__(self, sSrcFile, iBeginLine, offBeginLine, oFunction, iInFunction, cchIndent = None, fDeferToCImpl = False):
     1994        ## Set if IEM_MC_DEFER_TO_CIMPL_0_RET and friends, clear if IEM_MC_BEGIN/END block.
     1995        self.fDeferToCImpl = fDeferToCImpl;
    19941996        ## The source file containing the block.
    19951997        self.sSrcFile     = sSrcFile;
     
    27932795    'IEM_MC_CLEAR_EFL_BIT':                                      (McBlock.parseMcGeneric,           True,  False, ),
    27942796    'IEM_MC_CLEAR_FSW_EX':                                       (McBlock.parseMcGeneric,           True,  False, ),
    2795     'IEM_MC_CLEAR_HIGH_GREG_U64':                                (McBlock.parseMcGeneric,           True,  False, ),
     2797    'IEM_MC_CLEAR_HIGH_GREG_U64':                                (McBlock.parseMcGeneric,           True,  True, ),
    27962798    'IEM_MC_CLEAR_XREG_U32_MASK':                                (McBlock.parseMcGeneric,           True,  False, ),
    27972799    'IEM_MC_CLEAR_YREG_128_UP':                                  (McBlock.parseMcGeneric,           True,  False, ),
     
    52015203        # Start a new block.
    52025204        oMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine,
    5203                            self.oCurFunction, self.iMcBlockInFunc, cchIndent);
     5205                           self.oCurFunction, self.iMcBlockInFunc, cchIndent, fDeferToCImpl = True);
    52045206
    52055207        # Parse the statment.
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8vePython.py

    r102012 r102070  
    198198        return True;
    199199
    200     def renderCode(self, cchIndent):
    201         """
    202         Returns the native recompiler function body for this threaded variant.
    203         """
    204         # Take the threaded function statement list and add detected
    205         # IEM_CIMPL_F_XXX flags to the IEM_MC_BEGIN statement.  Also add
    206         # IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags checking
    207         # and clearing while there are such variations for this function (this
    208         # sounds a bit backwards, but has to be done this way for the use we
    209         # make of the flags in CIMPL calls).
    210         aoStmts = list(self.oVariation.aoStmtsForThreadedFunction) # type: list(McStmt)
     200    def raiseProblem(self, sMessage):
     201        """ Raises a problem. """
     202        raise Exception('%s:%s: error: %s'
     203                        % (self.oVariation.oParent.oMcBlock.sSrcFile, self.oVariation.oParent.oMcBlock.iBeginLine, sMessage,));
     204
     205    def __analyzeVariableLiveness(self, aoStmts, dVars, iDepth = 0):
     206        """
     207        Performs liveness analysis of the given statement list, inserting new
     208        statements to signal to the native recompiler that a variable is no
     209        longer used and can be freed.
     210
     211        Returns list of freed variables.
     212        """
     213
     214        class VarInfo(object):
     215            """ Variable info """
     216            def __init__(self, oStmt):
     217                self.oStmt         = oStmt;
     218                self.fIsArg        = isinstance(oStmt, iai.McStmtArg);
     219                self.oReferences   = None       # type: VarInfo
     220                self.oReferencedBy = None       # type: VarInfo
     221
     222            def isArg(self):
     223                return self.fIsArg;
     224
     225            def makeReference(self, oLocal, oParent):
     226                if not self.isArg():
     227                    oParent.raiseProblem('Attempt to make a reference out of an local variable: %s = &%s'
     228                                         % (self.oStmt.sVarName, oLocal.oStmt.sVarName,));
     229                if self.oReferences:
     230                    oParent.raiseProblem('Can only make a variable a reference once: %s = &%s; now = &%s'
     231                                         % (self.oStmt.sVarName, self.oReferences.oStmt.sVarName, oLocal.oStmt.sVarName,));
     232                if oLocal.isArg():
     233                    oParent.raiseProblem('Attempt to make a reference to an argument: %s = &%s'
     234                                         % (self.oStmt.sVarName, oLocal.oStmt.sVarName,));
     235                if oLocal.oReferencedBy:
     236                    oParent.raiseProblem('%s is already referenced by %s, so cannot make %s reference it as well'
     237                                         % (oLocal.oStmt.sVarName, oLocal.oReferencedBy.oStmt.sVarName, self.oStmt.sVarName,));
     238                oInfo.oReferences = oLocal;
     239                oInfo.oReferences.oReferencedBy = self;
     240                return True;
     241
     242        #
     243        # Gather variable declarations and add them to dVars.
     244        # Also keep a local list of them for scoping when iDepth > 0.
     245        #
     246        asVarsInScope = [];
     247        for oStmt in aoStmts:
     248            if isinstance(oStmt, iai.McStmtVar):
     249                if oStmt.sVarName in dVars:
     250                    raise Exception('Duplicate variable: %s' % (oStmt.sVarName, ));
     251
     252                oInfo = VarInfo(oStmt);
     253                if oInfo.isArg() and oStmt.sRefType == 'local':
     254                    oInfo.makeReference(dVars[oStmt.sRef], self);
     255
     256                dVars[oStmt.sVarName] = oInfo;
     257                asVarsInScope.append(oStmt.sVarName);
     258
     259            elif oStmt.sName == 'IEM_MC_REF_LOCAL':
     260                dVars[oStmt.asParam[0]].makeReference(dVars[oStmt.asParam[1]], self);
     261
     262        #
     263        # Now work the statements backwards and look for the last reference to
     264        # each of the variables in dVars.  We remove the variables from the
     265        # collections as we go along.
     266        #
     267        def freeVariable(aoStmts, iStmt, oVarInfo, dFreedVars, dVars, fIncludeReferences = True):
     268            sVarName = oVarInfo.oStmt.sVarName;
     269            if not oVarInfo.isArg():
     270                aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sVarName,]));
     271                assert not oVarInfo.oReferences;
     272            else:
     273                aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_ARG', [sVarName,]));
     274                if fIncludeReferences and oVarInfo.sReference:
     275                    sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
     276                    if sRefVarName in dVars:
     277                        dFreedVars[sRefVarName] = dVars[sRefVarName];
     278                        del dVars[sRefVarName];
     279                        aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
     280            dFreedVars[sVarName] = oVarInfo;
     281            if dVars is not None:
     282                del dVars[sVarName];
     283
     284        dFreedVars = {};
     285        for iStmt in range(len(aoStmts) - 1, -1, -1):
     286            oStmt = aoStmts[iStmt];
     287            if isinstance(oStmt, iai.McStmtCond):
     288                #
     289                # Conditionals requires a bit more work...
     290                #
     291
     292                # Start by replacing the conditional statement by a shallow copy.
     293                oStmt = copy.copy(oStmt);
     294                oStmt.aoIfBranch   = list(oStmt.aoIfBranch);
     295                oStmt.aoElseBranch = list(oStmt.aoElseBranch);
     296                aoStmts[iStmt] = oStmt;
     297
     298                # Check the two branches for final references. Both branches must
     299                # start processing with the same dVars set, fortunately as shallow
     300                # copy suffices.
     301                dFreedInIfBranch   = self.__analyzeVariableLiveness(oStmt.aoIfBranch, dict(dVars), iDepth + 1);
     302                dFreedInElseBranch = self.__analyzeVariableLiveness(oStmt.aoElseBranch, dVars, iDepth + 1);
     303
     304                # Add free statements to the start of the IF-branch for variables use
     305                # for the last time in the else branch.
     306                for sVarName, oVarInfo in dFreedInElseBranch.items():
     307                    if sVarName not in dFreedInIfBranch:
     308                        freeVariable(oStmt.aoIfBranch, -1, oVarInfo, dFreedVars, None, False);
     309                    else:
     310                        dFreedVars[sVarName] = oVarInfo;
     311
     312                # And vice versa.
     313                for sVarName, oVarInfo in dFreedInIfBranch.items():
     314                    if sVarName not in dFreedInElseBranch:
     315                        freeVariable(oStmt.aoElseBranch, -1, oVarInfo, dFreedVars, dVars, False);
     316
     317                #
     318                # Now check if any remaining variables are used for the last time
     319                # in the conditional statement ifself, in which case we need to insert
     320                # free statements to both branches.
     321                #
     322                if not oStmt.isCppStmt():
     323                    aoFreeStmts = [];
     324                    for sParam in oStmt.asParams:
     325                        if sParam in dVars:
     326                            freeVariable(aoFreeStmts, -1, dVars[sParam], dFreedVars, dVars);
     327                    for oFreeStmt in aoFreeStmts:
     328                        oStmt.aoIfBranch.insert(0, oFreeStmt);
     329                        oStmt.aoElseBranch.insert(0, oFreeStmt);
     330
     331            elif not oStmt.isCppStmt():
     332                if isinstance(oStmt, iai.McStmtCall):
     333                    #
     334                    # Call statements will make use of all argument variables and
     335                    # will implicitly free them.  So, iterate the variable and
     336                    # move them from dVars and onto dFreedVars.
     337                    #
     338                    # We explictly free any referenced variable that is still in
     339                    # dVar at this point (since only arguments can hold variable
     340                    # references).
     341                    #
     342                    for sParam in oStmt.asParams[oStmt.idxParams:]:
     343                        oVarInfo = dVars.get(sParam);
     344                        if oVarInfo:
     345                            if not oVarInfo.isArg():
     346                                self.raiseProblem('Argument %s in %s is not an argument!' % (sParam, oStmt.sName,));
     347                            if oVarInfo.oReferences:
     348                                sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
     349                                if sRefVarName in dVars:
     350                                    dFreedVars[sRefVarName] = dVars[sRefVarName];
     351                                    del dVars[sRefVarName];
     352                                    aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
     353                            dFreedVars[sParam] = oVarInfo;
     354                            del dVars[sParam];
     355                        elif sParam in dFreedVars:
     356                            self.raiseProblem('Argument %s in %s was used after the call!' % (sParam, oStmt.sName,));
     357                        else:
     358                            self.raiseProblem('Argument %s in %s is not known to us' % (sParam, oStmt.sName,));
     359
     360                    # Check for stray argument variables.
     361                    for oVarInfo in dVars.values():
     362                        if oVarInfo.isArg():
     363                            self.raiseProblem('Unused argument variable: %s' % (oVarInfo.oStmt.sVarName,));
     364                else:
     365                    #
     366                    # Scan all the parameters of generic statements.
     367                    #
     368                    for sParam in oStmt.asParams:
     369                        if sParam in dVars:
     370                            freeVariable(aoStmts, iStmt, dVars[sParam], dFreedVars, dVars);
     371
     372        #
     373        # Free anything left from asVarsInScope that's now going out of scope.
     374        #
     375        if iDepth > 0:
     376            for sVarName in asVarsInScope:
     377                if sVarName in dVars:
     378                    freeVariable(aoStmts, len(aoStmts) - 1, dVars[sVarName], dFreedVars, dVars);
     379        return dFreedVars;
     380
     381    def __morphStatements(self, aoStmts):
     382        """
     383        Morphs the given statement list into something more suitable for
     384        native recompilation.
     385
     386        The following is currently done here:
     387            - Amend IEM_MC_BEGIN with all the IEM_CIMPL_F_XXX and IEM_MC_F_XXX
     388              flags found and derived, including IEM_MC_F_WITHOUT_FLAGS which
     389              we determine here.
     390            - Insert IEM_MC_FREE_LOCAL when after the last statment a local
     391              variable is last used.
     392
     393        Returns a new list of statements.
     394        """
     395
     396        #
     397        # We can skip IEM_MC_DEFER_TO_CIMPL_x_RET stuff.
     398        #
     399        if self.oVariation.oParent.oMcBlock.fDeferToCImpl:
     400            return aoStmts;
     401
     402        #
     403        # We make a shallow copy of the list, and only make deep copies of the
     404        # statements we modify.
     405        #
     406        aoStmts = list(aoStmts) # type: list(iai.McStmt)
     407
     408        #
     409        # First, amend the IEM_MC_BEGIN statment, adding all the flags found
     410        # to it so the native recompiler can correctly process ARG and CALL
     411        # statements (among other things).
     412        #
     413        # Also add IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags
     414        # checking and clearing while there are such variations for this
     415        # function (this sounds a bit backwards, but has to be done this way
     416        # for the use we make of the flags in CIMPL calls).
     417        #
    211418        for iStmt, oStmt in enumerate(aoStmts):
    212419            if oStmt.sName == 'IEM_MC_BEGIN':
     
    221428                        oNewStmt.asParams[3] = ' | '.join(sorted(self.oVariation.oParent.dsCImplFlags.keys()));
    222429                    aoStmts[iStmt] = oNewStmt;
    223 
    224         return iai.McStmt.renderCodeForList(aoStmts, cchIndent);
     430                break;
     431
     432        #
     433        # Do a simple liveness analysis of the variable and insert
     434        # IEM_MC_FREE_LOCAL statements after the last statements using each
     435        # variable.  We do this recursively to best handle conditionals and
     436        # scoping related to those.
     437        #
     438        self.__analyzeVariableLiveness(aoStmts, {});
     439
     440        return aoStmts;
     441
     442
     443    def renderCode(self, cchIndent):
     444        """
     445        Returns the native recompiler function body for this threaded variant.
     446        """
     447        return iai.McStmt.renderCodeForList(self.__morphStatements(self.oVariation.aoStmtsForThreadedFunction), cchIndent);
    225448
    226449    @staticmethod
     
    307530                g_dUnsupportedMcStmtLastOneVarStats[sStmt] = [oVariation,];
    308531
    309 
    310 
    311532    return None;
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp

    r102069 r102070  
    55785578
    55795579
     5580#define IEM_MC_FREE_LOCAL(a_Name)   iemNativeVarFreeLocal(pReNative, a_Name)
     5581
     5582/**
     5583 * This is called by IEM_MC_FREE_LOCAL.
     5584 */
     5585DECLINLINE(void) iemNativeVarFreeLocal(PIEMRECOMPILERSTATE pReNative, uint8_t idxVar)
     5586{
     5587    IEMNATIVE_ASSERT_VAR_IDX(pReNative, idxVar);
     5588    Assert(pReNative->Core.aVars[idxVar].uArgNo == UINT8_MAX);
     5589    iemNativeVarFreeOneWorker(pReNative, idxVar);
     5590}
     5591
     5592
     5593#define IEM_MC_FREE_ARG(a_Name)     iemNativeVarFreeArg(pReNative, a_Name)
     5594
     5595/**
     5596 * This is called by IEM_MC_FREE_ARG.
     5597 */
     5598DECLINLINE(void) iemNativeVarFreeArg(PIEMRECOMPILERSTATE pReNative, uint8_t idxVar)
     5599{
     5600    IEMNATIVE_ASSERT_VAR_IDX(pReNative, idxVar);
     5601    Assert(pReNative->Core.aVars[idxVar].uArgNo < RT_ELEMENTS(pReNative->Core.aidxArgVars));
     5602    iemNativeVarFreeOneWorker(pReNative, idxVar);
     5603}
     5604
     5605
     5606
    55805607/*********************************************************************************************************************************
    55815608*   Emitters for IEM_MC_CALL_CIMPL_XXX                                                                                           *
     
    63866413    off = iemNativeEmitTop32BitsClearCheck(pReNative, off, idxVarReg);
    63876414#endif
     6415    return off;
     6416}
     6417
     6418
     6419
     6420#define IEM_MC_CLEAR_HIGH_GREG_U64(a_iGReg) \
     6421    off = iemNativeEmitClearHighGregU64(pReNative, off, a_iGReg)
     6422
     6423/** Emits code for IEM_MC_CLEAR_HIGH_GREG_U64. */
     6424DECL_INLINE_THROW(uint32_t)
     6425iemNativeEmitClearHighGregU64(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGReg)
     6426{
     6427    Assert(iGReg < 16);
     6428    uint8_t const idxGstTmpReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, IEMNATIVEGSTREG_GPR(iGReg),
     6429                                                                 kIemNativeGstRegUse_ForUpdate);
     6430    off = iemNativeEmitLoadGprFromGpr32(pReNative, off, idxGstTmpReg, idxGstTmpReg);
     6431    off = iemNativeEmitStoreGprToVCpuU64(pReNative, off, idxGstTmpReg, RT_UOFFSETOF_DYN(VMCPU, cpum.GstCtx.aGRegs[iGReg]));
     6432    iemNativeRegFreeTmp(pReNative, idxGstTmpReg);
    63886433    return off;
    63896434}
  • trunk/src/VBox/VMM/VMMAll/IEMAllThrdPython.py

    r102012 r102070  
    850850                # ... and IEM_MC_CALL_CIMPL_[0-5] and IEM_MC_DEFER_TO_CIMPL_[0-5]_RET into *_THREADED ...
    851851                elif oNewStmt.sName.startswith('IEM_MC_CALL_CIMPL_') or oNewStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_'):
    852                     oNewStmt.sName += '_THREADED';
     852                    oNewStmt.sName     += '_THREADED';
     853                    oNewStmt.idxFn     += 1;
     854                    oNewStmt.idxParams += 1;
    853855                    oNewStmt.asParams.insert(0, self.dParamRefs['cbInstr'][0].sNewName);
    854856
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