diff options
Diffstat (limited to 'src/jit/regset.cpp')
-rw-r--r-- | src/jit/regset.cpp | 2760 |
1 files changed, 9 insertions, 2751 deletions
diff --git a/src/jit/regset.cpp b/src/jit/regset.cpp index f37c422646..3bef88aea9 100644 --- a/src/jit/regset.cpp +++ b/src/jit/regset.cpp @@ -36,13 +36,6 @@ const regMaskSmall regMasks[] = { }; #endif -#ifdef _TARGET_X86_ -const regMaskSmall regFPMasks[] = { -#define REGDEF(name, rnum, mask, sname) mask, -#include "registerfp.h" -}; -#endif // _TARGET_X86_ - /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -54,9 +47,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void RegSet::rsClearRegsModified() { -#ifndef LEGACY_BACKEND assert(m_rsCompiler->lvaDoneFrameLayout < Compiler::FINAL_FRAME_LAYOUT); -#endif // !LEGACY_BACKEND #ifdef DEBUG if (m_rsCompiler->verbose) @@ -74,7 +65,6 @@ void RegSet::rsSetRegsModified(regMaskTP mask DEBUGARG(bool suppressDump)) assert(mask != RBM_NONE); assert(rsModifiedRegsMaskInitialized); -#ifndef LEGACY_BACKEND // We can't update the modified registers set after final frame layout (that is, during code // generation and after). Ignore prolog and epilog generation: they call register tracking to // modify rbp, for example, even in functions that use rbp as a frame pointer. Make sure normal @@ -84,7 +74,6 @@ void RegSet::rsSetRegsModified(regMaskTP mask DEBUGARG(bool suppressDump)) assert((m_rsCompiler->lvaDoneFrameLayout < Compiler::FINAL_FRAME_LAYOUT) || m_rsCompiler->compGeneratingProlog || m_rsCompiler->compGeneratingEpilog || (((rsModifiedRegsMask | mask) & RBM_CALLEE_SAVED) == (rsModifiedRegsMask & RBM_CALLEE_SAVED))); -#endif // !LEGACY_BACKEND #ifdef DEBUG if (m_rsCompiler->verbose && !suppressDump) @@ -110,12 +99,10 @@ void RegSet::rsRemoveRegsModified(regMaskTP mask) assert(mask != RBM_NONE); assert(rsModifiedRegsMaskInitialized); -#ifndef LEGACY_BACKEND // See comment in rsSetRegsModified(). assert((m_rsCompiler->lvaDoneFrameLayout < Compiler::FINAL_FRAME_LAYOUT) || m_rsCompiler->compGeneratingProlog || m_rsCompiler->compGeneratingEpilog || (((rsModifiedRegsMask & ~mask) & RBM_CALLEE_SAVED) == (rsModifiedRegsMask & RBM_CALLEE_SAVED))); -#endif // !LEGACY_BACKEND #ifdef DEBUG if (m_rsCompiler->verbose) @@ -166,262 +153,6 @@ void RegSet::SetMaskVars(regMaskTP newMaskVars) _rsMaskVars = newMaskVars; } -#ifdef DEBUG - -RegSet::rsStressRegsType RegSet::rsStressRegs() -{ -#ifndef LEGACY_BACKEND - return RS_STRESS_NONE; -#else // LEGACY_BACKEND - rsStressRegsType val = (rsStressRegsType)JitConfig.JitStressRegs(); - if (val == RS_STRESS_NONE && m_rsCompiler->compStressCompile(Compiler::STRESS_REGS, 15)) - val = RS_PICK_BAD_REG; - return val; -#endif // LEGACY_BACKEND -} -#endif // DEBUG - -#ifdef LEGACY_BACKEND -/***************************************************************************** - * Includes 'includeHint' if 'regs' is empty - */ - -regMaskTP RegSet::rsUseIfZero(regMaskTP regs, regMaskTP includeHint) -{ - return regs ? regs : includeHint; -} - -/***************************************************************************** - * Excludes 'excludeHint' if it results in a non-empty mask - */ - -regMaskTP RegSet::rsExcludeHint(regMaskTP regs, regMaskTP excludeHint) -{ - regMaskTP OKmask = regs & ~excludeHint; - return OKmask ? OKmask : regs; -} - -/***************************************************************************** - * Narrows choice by 'narrowHint' if it results in a non-empty mask - */ - -regMaskTP RegSet::rsNarrowHint(regMaskTP regs, regMaskTP narrowHint) -{ - regMaskTP narrowed = regs & narrowHint; - return narrowed ? narrowed : regs; -} - -/***************************************************************************** - * Excludes 'exclude' from regs if non-zero, or from RBM_ALLINT - */ - -regMaskTP RegSet::rsMustExclude(regMaskTP regs, regMaskTP exclude) -{ - // Try to exclude from current set - regMaskTP OKmask = regs & ~exclude; - - // If current set wont work, exclude from RBM_ALLINT - if (OKmask == RBM_NONE) - OKmask = (RBM_ALLINT & ~exclude); - - assert(OKmask); - - return OKmask; -} - -/***************************************************************************** - * - * The following returns a mask that yields all free registers. - */ - -// inline -regMaskTP RegSet::rsRegMaskFree() -{ - /* Any register that is locked must also be marked as 'used' */ - - assert((rsMaskUsed & rsMaskLock) == rsMaskLock); - - /* Any register that isn't used and doesn't hold a variable is free */ - - return RBM_ALLINT & ~(rsMaskUsed | rsMaskVars | rsMaskResvd); -} - -/***************************************************************************** - * - * The following returns a mask of registers that may be grabbed. - */ - -// inline -regMaskTP RegSet::rsRegMaskCanGrab() -{ - /* Any register that is locked must also be marked as 'used' */ - - assert((rsMaskUsed & rsMaskLock) == rsMaskLock); - - /* Any register that isn't locked and doesn't hold a var can be grabbed */ - - regMaskTP result = (RBM_ALLINT & ~(rsMaskLock | rsMaskVars)); - -#ifdef _TARGET_ARM_ - - // On the ARM when we pass structs in registers we set the rsUsedTree[] - // to be the full TYP_STRUCT tree, which doesn't allow us to spill/unspill - // these argument registers. To fix JitStress issues that can occur - // when rsPickReg tries to spill one of these registers we just remove them - // from the set of registers that we can grab - // - regMaskTP structArgMask = RBM_NONE; - // Load all the variable arguments in registers back to their registers. - for (regNumber reg = REG_ARG_FIRST; reg <= REG_ARG_LAST; reg = REG_NEXT(reg)) - { - GenTree* regHolds = rsUsedTree[reg]; - if ((regHolds != NULL) && (regHolds->TypeGet() == TYP_STRUCT)) - { - structArgMask |= genRegMask(reg); - } - } - result &= ~structArgMask; -#endif - - return result; -} - -/***************************************************************************** - * - * Pick a free register. It is guaranteed that a register is available. - * Note that rsPickReg() can spill a register, whereas rsPickFreeReg() will not. - */ - -// inline -regNumber RegSet::rsPickFreeReg(regMaskTP regMaskHint) -{ - regMaskTP freeRegs = rsRegMaskFree(); - assert(freeRegs != RBM_NONE); - - regMaskTP regs = rsNarrowHint(freeRegs, regMaskHint); - - return rsGrabReg(regs); -} - -/***************************************************************************** - * - * Mark the given set of registers as used and locked. - */ - -// inline -void RegSet::rsLockReg(regMaskTP regMask) -{ - /* Must not be already marked as either used or locked */ - - assert((rsMaskUsed & regMask) == 0); - rsMaskUsed |= regMask; - assert((rsMaskLock & regMask) == 0); - rsMaskLock |= regMask; -} - -/***************************************************************************** - * - * Mark an already used set of registers as locked. - */ - -// inline -void RegSet::rsLockUsedReg(regMaskTP regMask) -{ - /* Must not be already marked as locked. Must be already marked as used. */ - - assert((rsMaskLock & regMask) == 0); - assert((rsMaskUsed & regMask) == regMask); - - rsMaskLock |= regMask; -} - -/***************************************************************************** - * - * Mark the given set of registers as no longer used/locked. - */ - -// inline -void RegSet::rsUnlockReg(regMaskTP regMask) -{ - /* Must be currently marked as both used and locked */ - - assert((rsMaskUsed & regMask) == regMask); - rsMaskUsed -= regMask; - assert((rsMaskLock & regMask) == regMask); - rsMaskLock -= regMask; -} - -/***************************************************************************** - * - * Mark the given set of registers as no longer locked. - */ - -// inline -void RegSet::rsUnlockUsedReg(regMaskTP regMask) -{ - /* Must be currently marked as both used and locked */ - - assert((rsMaskUsed & regMask) == regMask); - assert((rsMaskLock & regMask) == regMask); - rsMaskLock -= regMask; -} - -/***************************************************************************** - * - * Mark the given set of registers as used and locked. It may already have - * been marked as used. - */ - -// inline -void RegSet::rsLockReg(regMaskTP regMask, regMaskTP* usedMask) -{ - /* Is it already marked as used? */ - - regMaskTP used = (rsMaskUsed & regMask); - regMaskTP unused = (regMask & ~used); - - if (used) - rsLockUsedReg(used); - - if (unused) - rsLockReg(unused); - - *usedMask = used; -} - -/***************************************************************************** - * - * Mark the given set of registers as no longer - */ - -// inline -void RegSet::rsUnlockReg(regMaskTP regMask, regMaskTP usedMask) -{ - regMaskTP unused = (regMask & ~usedMask); - - if (usedMask) - rsUnlockUsedReg(usedMask); - - if (unused) - rsUnlockReg(unused); -} -#endif // LEGACY_BACKEND - -#ifdef LEGACY_BACKEND -/***************************************************************************** - * - * Assume all registers contain garbage (called at start of codegen and when - * we encounter a code label). - */ - -// inline -void RegTracker::rsTrackRegClr() -{ - assert(RV_TRASH == 0); - memset(rsRegValues, 0, sizeof(rsRegValues)); -} -#endif // LEGACY_BACKEND - /***************************************************************************** * * Trash the rsRegValues associated with a register @@ -433,39 +164,7 @@ void RegTracker::rsTrackRegTrash(regNumber reg) /* Keep track of which registers we ever touch */ regSet->rsSetRegsModified(genRegMask(reg)); - -#ifdef LEGACY_BACKEND - /* Record the new value for the register */ - - rsRegValues[reg].rvdKind = RV_TRASH; -#endif // LEGACY_BACKEND -} - -#ifdef LEGACY_BACKEND -/***************************************************************************** - * - * calls rsTrackRegTrash on the set of registers in regmask - */ - -// inline -void RegTracker::rsTrackRegMaskTrash(regMaskTP regMask) -{ - regMaskTP regBit = 1; - - for (regNumber regNum = REG_FIRST; regNum < REG_COUNT; regNum = REG_NEXT(regNum), regBit <<= 1) - { - if (regBit > regMask) - { - break; - } - - if (regBit & regMask) - { - rsTrackRegTrash(regNum); - } - } } -#endif // LEGACY_BACKEND /*****************************************************************************/ @@ -477,325 +176,8 @@ void RegTracker::rsTrackRegIntCns(regNumber reg, ssize_t val) /* Keep track of which registers we ever touch */ regSet->rsSetRegsModified(genRegMask(reg)); - -#ifdef LEGACY_BACKEND - /* Record the new value for the register */ - - rsRegValues[reg].rvdKind = RV_INT_CNS; - rsRegValues[reg].rvdIntCnsVal = val; -#endif -} - -#ifdef LEGACY_BACKEND -/*****************************************************************************/ - -// inline -void RegTracker::rsTrackRegLclVarLng(regNumber reg, unsigned var, bool low) -{ - assert(genIsValidIntReg(reg)); - - if (compiler->lvaTable[var].lvAddrExposed) - { - return; - } - - /* Keep track of which registers we ever touch */ - - regSet->rsSetRegsModified(genRegMask(reg)); - - /* Record the new value for the register */ - - rsRegValues[reg].rvdKind = (low ? RV_LCL_VAR_LNG_LO : RV_LCL_VAR_LNG_HI); - rsRegValues[reg].rvdLclVarNum = var; -} - -/*****************************************************************************/ - -// inline -bool RegTracker::rsTrackIsLclVarLng(regValKind rvKind) -{ - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return false; - } - - if (rvKind == RV_LCL_VAR_LNG_LO || rvKind == RV_LCL_VAR_LNG_HI) - { - return true; - } - else - { - return false; - } -} - -/*****************************************************************************/ - -// inline -void RegTracker::rsTrackRegClsVar(regNumber reg, GenTree* clsVar) -{ - rsTrackRegTrash(reg); -} - -/*****************************************************************************/ - -// inline -void RegTracker::rsTrackRegAssign(GenTree* op1, GenTree* op2) -{ - /* Constant/bitvalue has precedence over local */ - switch (rsRegValues[op2->gtRegNum].rvdKind) - { - case RV_INT_CNS: - break; - - default: - - /* Mark RHS register as containing the value */ - - switch (op1->gtOper) - { - case GT_LCL_VAR: - rsTrackRegLclVar(op2->gtRegNum, op1->gtLclVarCommon.gtLclNum); - break; - case GT_CLS_VAR: - rsTrackRegClsVar(op2->gtRegNum, op1); - break; - default: - break; - } - } -} - -/***************************************************************************** - * - * Given a regmask, find the best regPairNo that can be formed - * or return REG_PAIR_NONE if no register pair can be formed - */ - -regPairNo RegSet::rsFindRegPairNo(regMaskTP regAllowedMask) -{ - regPairNo regPair; - - // Remove any special purpose registers such as SP, EBP, etc... - regMaskTP specialUseMask = (rsMaskResvd | RBM_SPBASE); -#if ETW_EBP_FRAMED - specialUseMask |= RBM_FPBASE; -#else - if (m_rsCompiler->codeGen->isFramePointerUsed()) - specialUseMask |= RBM_FPBASE; -#endif - - regAllowedMask &= ~specialUseMask; - - /* Check if regAllowedMask has zero or one bits set */ - if ((regAllowedMask & (regAllowedMask - 1)) == 0) - { - /* If so we won't be able to find a reg pair */ - return REG_PAIR_NONE; - } - -#ifdef _TARGET_X86_ - if (regAllowedMask & RBM_EAX) - { - /* EAX is available, see if we can pair it with another reg */ - - if (regAllowedMask & RBM_EDX) - { - regPair = REG_PAIR_EAXEDX; - goto RET; - } - if (regAllowedMask & RBM_ECX) - { - regPair = REG_PAIR_EAXECX; - goto RET; - } - if (regAllowedMask & RBM_EBX) - { - regPair = REG_PAIR_EAXEBX; - goto RET; - } - if (regAllowedMask & RBM_ESI) - { - regPair = REG_PAIR_EAXESI; - goto RET; - } - if (regAllowedMask & RBM_EDI) - { - regPair = REG_PAIR_EAXEDI; - goto RET; - } - if (regAllowedMask & RBM_EBP) - { - regPair = REG_PAIR_EAXEBP; - goto RET; - } - } - - if (regAllowedMask & RBM_ECX) - { - /* ECX is available, see if we can pair it with another reg */ - - if (regAllowedMask & RBM_EDX) - { - regPair = REG_PAIR_ECXEDX; - goto RET; - } - if (regAllowedMask & RBM_EBX) - { - regPair = REG_PAIR_ECXEBX; - goto RET; - } - if (regAllowedMask & RBM_ESI) - { - regPair = REG_PAIR_ECXESI; - goto RET; - } - if (regAllowedMask & RBM_EDI) - { - regPair = REG_PAIR_ECXEDI; - goto RET; - } - if (regAllowedMask & RBM_EBP) - { - regPair = REG_PAIR_ECXEBP; - goto RET; - } - } - - if (regAllowedMask & RBM_EDX) - { - /* EDX is available, see if we can pair it with another reg */ - - if (regAllowedMask & RBM_EBX) - { - regPair = REG_PAIR_EDXEBX; - goto RET; - } - if (regAllowedMask & RBM_ESI) - { - regPair = REG_PAIR_EDXESI; - goto RET; - } - if (regAllowedMask & RBM_EDI) - { - regPair = REG_PAIR_EDXEDI; - goto RET; - } - if (regAllowedMask & RBM_EBP) - { - regPair = REG_PAIR_EDXEBP; - goto RET; - } - } - - if (regAllowedMask & RBM_EBX) - { - /* EBX is available, see if we can pair it with another reg */ - - if (regAllowedMask & RBM_ESI) - { - regPair = REG_PAIR_EBXESI; - goto RET; - } - if (regAllowedMask & RBM_EDI) - { - regPair = REG_PAIR_EBXEDI; - goto RET; - } - if (regAllowedMask & RBM_EBP) - { - regPair = REG_PAIR_EBXEBP; - goto RET; - } - } - - if (regAllowedMask & RBM_ESI) - { - /* ESI is available, see if we can pair it with another reg */ - - if (regAllowedMask & RBM_EDI) - { - regPair = REG_PAIR_ESIEDI; - goto RET; - } - if (regAllowedMask & RBM_EBP) - { - regPair = REG_PAIR_EBPESI; - goto RET; - } - } - - if (regAllowedMask & RBM_EDI) - { - /* EDI is available, see if we can pair it with another reg */ - - if (regAllowedMask & RBM_EBP) - { - regPair = REG_PAIR_EBPEDI; - goto RET; - } - } -#endif - -#ifdef _TARGET_ARM_ - // ARM is symmetric, so don't bother to prefer some pairs to others - // - // Iterate the registers in the order specified by rpRegTmpOrder/raRegTmpOrder - - for (unsigned index1 = 0; index1 < REG_TMP_ORDER_COUNT; index1++) - { - regNumber reg1; - if (m_rsCompiler->rpRegAllocDone) - reg1 = raRegTmpOrder[index1]; - else - reg1 = rpRegTmpOrder[index1]; - - regMaskTP reg1Mask = genRegMask(reg1); - - if ((regAllowedMask & reg1Mask) == 0) - continue; - - for (unsigned index2 = index1 + 1; index2 < REG_TMP_ORDER_COUNT; index2++) - { - regNumber reg2; - if (m_rsCompiler->rpRegAllocDone) - reg2 = raRegTmpOrder[index2]; - else - reg2 = rpRegTmpOrder[index2]; - - regMaskTP reg2Mask = genRegMask(reg2); - - if ((regAllowedMask & reg2Mask) == 0) - continue; - - regMaskTP pairMask = genRegMask(reg1) | genRegMask(reg2); - - // if reg1 is larger than reg2 then swap the registers - if (reg1 > reg2) - { - regNumber regT = reg1; - reg1 = reg2; - reg2 = regT; - } - - regPair = gen2regs2pair(reg1, reg2); - return regPair; - } - } -#endif - - assert(!"Unreachable code"); - regPair = REG_PAIR_NONE; - -#ifdef _TARGET_X86_ -RET: -#endif - - return regPair; } -#endif // LEGACY_BACKEND - /*****************************************************************************/ RegSet::RegSet(Compiler* compiler, GCInfo& gcInfo) : m_rsCompiler(compiler), m_rsGCInfo(gcInfo) @@ -812,12 +194,6 @@ RegSet::RegSet(Compiler* compiler, GCInfo& gcInfo) : m_rsCompiler(compiler), m_r rsMaskResvd = RBM_NONE; -#ifdef LEGACY_BACKEND - rsMaskMult = RBM_NONE; - rsMaskUsed = RBM_NONE; - rsMaskLock = RBM_NONE; -#endif // LEGACY_BACKEND - #ifdef _TARGET_ARMARCH_ rsMaskCalleeSaved = RBM_NONE; #endif // _TARGET_ARMARCH_ @@ -832,298 +208,21 @@ RegSet::RegSet(Compiler* compiler, GCInfo& gcInfo) : m_rsCompiler(compiler), m_r #endif // DEBUG } -#ifdef LEGACY_BACKEND -/***************************************************************************** - * - * Marks the register that holds the given operand value as 'used'. If 'addr' - * is non-zero, the register is part of a complex address mode that needs to - * be marked if the register is ever spilled. - */ - -void RegSet::rsMarkRegUsed(GenTree* tree, GenTree* addr) -{ - var_types type; - regNumber regNum; - regMaskTP regMask; - - /* The value must be sitting in a register */ - - assert(tree); - assert(tree->InReg()); - - type = tree->TypeGet(); - regNum = tree->gtRegNum; - - if (isFloatRegType(type)) - regMask = genRegMaskFloat(regNum, type); - else - regMask = genRegMask(regNum); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tThe register %s currently holds ", m_rsCompiler->compRegVarName(regNum)); - Compiler::printTreeID(tree); - if (addr != NULL) - { - printf("/"); - Compiler::printTreeID(addr); - } - else if (tree->gtOper == GT_CNS_INT) - { - if (tree->IsIconHandle()) - printf(" / Handle(0x%08p)", dspPtr(tree->gtIntCon.gtIconVal)); - else - printf(" / Constant(0x%X)", tree->gtIntCon.gtIconVal); - } - printf("\n"); - } -#endif // DEBUG - - /* Remember whether the register holds a pointer */ - - m_rsGCInfo.gcMarkRegPtrVal(regNum, type); - - /* No locked register may ever be marked as free */ - - assert((rsMaskLock & rsRegMaskFree()) == 0); - - /* Is the register used by two different values simultaneously? */ - - if (regMask & rsMaskUsed) - { - /* Save the preceding use information */ - - rsRecMultiReg(regNum, type); - } - - /* Set the register's bit in the 'used' bitset */ - - rsMaskUsed |= regMask; - - /* Remember what values are in what registers, in case we have to spill */ - assert(regNum != REG_SPBASE); - assert(rsUsedTree[regNum] == NULL); - rsUsedTree[regNum] = tree; - assert(rsUsedAddr[regNum] == NULL); - rsUsedAddr[regNum] = addr; -} - -void RegSet::rsMarkArgRegUsedByPromotedFieldArg(GenTree* promotedStructArg, regNumber regNum, bool isGCRef) -{ - regMaskTP regMask; - - /* The value must be sitting in a register */ - - assert(promotedStructArg); - assert(promotedStructArg->TypeGet() == TYP_STRUCT); - - assert(regNum < MAX_REG_ARG); - regMask = genRegMask(regNum); - assert((regMask & RBM_ARG_REGS) != RBM_NONE); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tThe register %s currently holds ", m_rsCompiler->compRegVarName(regNum)); - Compiler::printTreeID(promotedStructArg); - if (promotedStructArg->gtOper == GT_CNS_INT) - { - if (promotedStructArg->IsIconHandle()) - printf(" / Handle(0x%08p)", dspPtr(promotedStructArg->gtIntCon.gtIconVal)); - else - printf(" / Constant(0x%X)", promotedStructArg->gtIntCon.gtIconVal); - } - printf("\n"); - } -#endif - - /* Remember whether the register holds a pointer */ - - m_rsGCInfo.gcMarkRegPtrVal(regNum, (isGCRef ? TYP_REF : TYP_INT)); - - /* No locked register may ever be marked as free */ - - assert((rsMaskLock & rsRegMaskFree()) == 0); - - /* Is the register used by two different values simultaneously? */ - - if (regMask & rsMaskUsed) - { - /* Save the preceding use information */ - - assert(isValidIntArgReg(regNum)); // We are expecting only integer argument registers here - rsRecMultiReg(regNum, TYP_I_IMPL); - } - - /* Set the register's bit in the 'used' bitset */ - - rsMaskUsed |= regMask; - - /* Remember what values are in what registers, in case we have to spill */ - assert(regNum != REG_SPBASE); - assert(rsUsedTree[regNum] == 0); - rsUsedTree[regNum] = promotedStructArg; -} - -/***************************************************************************** - * - * Marks the register pair that holds the given operand value as 'used'. - */ - -void RegSet::rsMarkRegPairUsed(GenTree* tree) -{ - regNumber regLo; - regNumber regHi; - regPairNo regPair; - regMaskTP regMask; - - /* The value must be sitting in a register */ - - assert(tree); -#if CPU_HAS_FP_SUPPORT - assert(tree->gtType == TYP_LONG); -#else - assert(tree->gtType == TYP_LONG || tree->gtType == TYP_DOUBLE); -#endif - assert(tree->InReg()); - - regPair = tree->gtRegPair; - regMask = genRegPairMask(regPair); - - regLo = genRegPairLo(regPair); - regHi = genRegPairHi(regPair); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tThe register %s currently holds ", m_rsCompiler->compRegVarName(regLo)); - Compiler::printTreeID(tree); - printf("/lo32\n"); - printf("\t\t\t\t\t\t\tThe register %s currently holds ", m_rsCompiler->compRegVarName(regHi)); - Compiler::printTreeID(tree); - printf("/hi32\n"); - } -#endif - - /* Neither register obviously holds a pointer value */ - - m_rsGCInfo.gcMarkRegSetNpt(regMask); - - /* No locked register may ever be marked as free */ - - assert((rsMaskLock & rsRegMaskFree()) == 0); - - /* Are the registers used by two different values simultaneously? */ - - if (rsMaskUsed & genRegMask(regLo)) - { - /* Save the preceding use information */ - - rsRecMultiReg(regLo, TYP_INT); - } - - if (rsMaskUsed & genRegMask(regHi)) - { - /* Save the preceding use information */ - - rsRecMultiReg(regHi, TYP_INT); - } - - /* Can't mark a register pair more than once as used */ - - // assert((regMask & rsMaskUsed) == 0); - - /* Mark the registers as 'used' */ - - rsMaskUsed |= regMask; - - /* Remember what values are in what registers, in case we have to spill */ - - if (regLo != REG_STK) - { - assert(rsUsedTree[regLo] == 0); - assert(regLo != REG_SPBASE); - rsUsedTree[regLo] = tree; - } - - if (regHi != REG_STK) - { - assert(rsUsedTree[regHi] == 0); - assert(regHi != REG_SPBASE); - rsUsedTree[regHi] = tree; - } -} - -/***************************************************************************** - * - * Returns true if the given tree is currently held in reg. - * Note that reg may by used by multiple trees, in which case we have - * to search rsMultiDesc[reg]. - */ - -bool RegSet::rsIsTreeInReg(regNumber reg, GenTree* tree) -{ - /* First do the trivial check */ - - if (rsUsedTree[reg] == tree) - return true; - - /* If the register is used by multiple trees, we have to search the list - in rsMultiDesc[reg] */ - - if (genRegMask(reg) & rsMaskMult) - { - SpillDsc* multiDesc = rsMultiDesc[reg]; - assert(multiDesc); - - for (/**/; multiDesc; multiDesc = multiDesc->spillNext) - { - if (multiDesc->spillTree == tree) - return true; - - assert((!multiDesc->spillNext) == (!multiDesc->spillMoreMultis)); - } - } - - /* Not found. It must be spilled */ - - return false; -} -#endif // LEGACY_BACKEND - /***************************************************************************** * * Finds the SpillDsc corresponding to 'tree' assuming it was spilled from 'reg'. */ -RegSet::SpillDsc* RegSet::rsGetSpillInfo(GenTree* tree, - regNumber reg, - SpillDsc** pPrevDsc -#ifdef LEGACY_BACKEND - , - SpillDsc** pMultiDsc -#endif // LEGACY_BACKEND - ) +RegSet::SpillDsc* RegSet::rsGetSpillInfo(GenTree* tree, regNumber reg, SpillDsc** pPrevDsc) { /* Normally, trees are unspilled in the order of being spilled due to the post-order walking of trees during code-gen. However, this will not be true for something like a GT_ARR_ELEM node */ - CLANG_FORMAT_COMMENT_ANCHOR; - -#ifdef LEGACY_BACKEND - SpillDsc* multi = rsSpillDesc[reg]; -#endif // LEGACY_BACKEND SpillDsc* prev; SpillDsc* dsc; for (prev = nullptr, dsc = rsSpillDesc[reg]; dsc != nullptr; prev = dsc, dsc = dsc->spillNext) { -#ifdef LEGACY_BACKEND - if (prev && !prev->spillMoreMultis) - multi = dsc; -#endif // LEGACY_BACKEND - if (dsc->spillTree == tree) { break; @@ -1134,235 +233,10 @@ RegSet::SpillDsc* RegSet::rsGetSpillInfo(GenTree* tree, { *pPrevDsc = prev; } -#ifdef LEGACY_BACKEND - if (pMultiDsc) - *pMultiDsc = multi; -#endif // LEGACY_BACKEND return dsc; } -#ifdef LEGACY_BACKEND -/***************************************************************************** - * - * Mark the register set given by the register mask as not used. - */ - -void RegSet::rsMarkRegFree(regMaskTP regMask) -{ - /* Are we freeing any multi-use registers? */ - - if (regMask & rsMaskMult) - { - rsMultRegFree(regMask); - return; - } - - m_rsGCInfo.gcMarkRegSetNpt(regMask); - - regMaskTP regBit = 1; - - for (regNumber regNum = REG_FIRST; regNum < REG_COUNT; regNum = REG_NEXT(regNum), regBit <<= 1) - { - if (regBit > regMask) - break; - - if (regBit & regMask) - { -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tThe register %s no longer holds ", m_rsCompiler->compRegVarName(regNum)); - Compiler::printTreeID(rsUsedTree[regNum]); - if (rsUsedAddr[regNum] != nullptr) - { - Compiler::printTreeID(rsUsedAddr[regNum]); - } - - printf("\n"); - } -#endif - GenTree* usedTree = rsUsedTree[regNum]; - assert(usedTree != NULL); - rsUsedTree[regNum] = NULL; - rsUsedAddr[regNum] = NULL; -#ifdef _TARGET_ARM_ - if (usedTree->TypeGet() == TYP_DOUBLE) - { - regNum = REG_NEXT(regNum); - regBit <<= 1; - - assert(regBit & regMask); - assert(rsUsedTree[regNum] == NULL); - assert(rsUsedAddr[regNum] == NULL); - } -#endif - } - } - - /* Remove the register set from the 'used' set */ - - assert((regMask & rsMaskUsed) == regMask); - rsMaskUsed -= regMask; - - /* No locked register may ever be marked as free */ - - assert((rsMaskLock & rsRegMaskFree()) == 0); -} - -/***************************************************************************** - * - * Free the register from the given tree. If the register holds other tree, - * it will still be marked as used, else it will be completely free. - */ - -void RegSet::rsMarkRegFree(regNumber reg, GenTree* tree) -{ - assert(rsIsTreeInReg(reg, tree)); - regMaskTP regMask = genRegMask(reg); - - /* If the register is not multi-used, it's easy. Just do the default work */ - - if (!(regMask & rsMaskMult)) - { - rsMarkRegFree(regMask); - return; - } - - /* The tree is multi-used. We just have to free it off the given tree but - leave other trees which use the register as they are. The register may - not be multi-used after freeing it from the given tree */ - - /* Is the tree in rsUsedTree[] or in rsMultiDesc[]? - If it is in rsUsedTree[], update rsUsedTree[] */ - - if (rsUsedTree[reg] == tree) - { - rsRmvMultiReg(reg); - return; - } - - /* The tree is in rsMultiDesc[] instead of in rsUsedTree[]. Find the desc - corresponding to the tree and just remove it from there */ - - for (SpillDsc *multiDesc = rsMultiDesc[reg], *prevDesc = NULL; multiDesc; - prevDesc = multiDesc, multiDesc = multiDesc->spillNext) - { - /* If we find the descriptor with the tree we are looking for, - discard it */ - - if (multiDesc->spillTree != tree) - continue; - - if (prevDesc == NULL) - { - /* The very first desc in rsMultiDesc[] matched. If there are - no further descs, then the register is no longer multi-used */ - - if (!multiDesc->spillMoreMultis) - rsMaskMult -= regMask; - - rsMultiDesc[reg] = multiDesc->spillNext; - } - else - { - /* There are a couple of other descs before the match. So the - register is still multi-used. However, we may have to - update spillMoreMultis for the previous desc. */ - - if (!multiDesc->spillMoreMultis) - prevDesc->spillMoreMultis = false; - - prevDesc->spillNext = multiDesc->spillNext; - } - - SpillDsc::freeDsc(this, multiDesc); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tRegister %s multi-use dec for ", m_rsCompiler->compRegVarName(reg)); - Compiler::printTreeID(tree); - printf(" - now "); - Compiler::printTreeID(rsUsedTree[reg]); - printf(" multMask=" REG_MASK_ALL_FMT "\n", rsMaskMult); - } -#endif - - return; - } - - assert(!"Didn't find the spilled tree in rsMultiDesc[]"); -} - -/***************************************************************************** - * - * Mark the register set given by the register mask as not used; there may - * be some 'multiple-use' registers in the set. - */ - -void RegSet::rsMultRegFree(regMaskTP regMask) -{ - /* Free any multiple-use registers first */ - regMaskTP nonMultMask = regMask & ~rsMaskMult; - regMaskTP myMultMask = regMask & rsMaskMult; - - if (myMultMask) - { - regNumber regNum; - regMaskTP regBit; - - for (regNum = REG_FIRST, regBit = 1; regNum < REG_COUNT; regNum = REG_NEXT(regNum), regBit <<= 1) - { - if (regBit > myMultMask) - break; - - if (regBit & myMultMask) - { - /* Free the multi-use register 'regNum' */ - var_types type = rsRmvMultiReg(regNum); -#ifdef _TARGET_ARM_ - if (genIsValidFloatReg(regNum) && (type == TYP_DOUBLE)) - { - // On ARM32, We skip the second register for a TYP_DOUBLE - regNum = REG_NEXT(regNum); - regBit <<= 1; - } -#endif // _TARGET_ARM_ - } - } - } - - /* If there are any single-use registers, free them */ - - if (nonMultMask) - rsMarkRegFree(nonMultMask); -} - -/***************************************************************************** - * - * Returns the number of registers that are currently free which appear in needReg. - */ - -unsigned RegSet::rsFreeNeededRegCount(regMaskTP needReg) -{ - regMaskTP regNeededFree = rsRegMaskFree() & needReg; - unsigned cntFree = 0; - - /* While some registers are free ... */ - - while (regNeededFree) - { - /* Remove the next register bit and bump the count */ - - regNeededFree -= genFindLowestBit(regNeededFree); - cntFree += 1; - } - - return cntFree; -} -#endif // LEGACY_BACKEND - /***************************************************************************** * * Record the fact that the given register now contains the given local @@ -1378,11 +252,6 @@ void RegTracker::rsTrackRegLclVar(regNumber reg, unsigned var) #if CPU_HAS_FP_SUPPORT assert(varTypeIsFloating(varDsc->TypeGet()) == false); #endif -#ifdef LEGACY_BACKEND - // Kill the register before doing anything in case we take a - // shortcut out of here - rsRegValues[reg].rvdKind = RV_TRASH; -#endif if (compiler->lvaTable[var].lvAddrExposed) { @@ -1392,68 +261,10 @@ void RegTracker::rsTrackRegLclVar(regNumber reg, unsigned var) /* Keep track of which registers we ever touch */ regSet->rsSetRegsModified(genRegMask(reg)); - -#ifdef LEGACY_BACKEND - - /* Is the variable a pointer? */ - - if (varTypeIsGC(varDsc->TypeGet())) - { - /* Don't track pointer register vars */ - - if (varDsc->lvRegister) - { - return; - } - - /* Don't track when fully interruptible */ - - if (compiler->genInterruptible) - { - return; - } - } - else if (varDsc->lvNormalizeOnLoad()) - { - return; - } - -#ifdef DEBUG - if (compiler->verbose) - { - printf("\t\t\t\t\t\t\tThe register %s now holds V%02u\n", compiler->compRegVarName(reg), var); - } -#endif - - /* Record the new value for the register. ptr var needed for - * lifetime extension - */ - - rsRegValues[reg].rvdKind = RV_LCL_VAR; - - // If this is a cast of a 64 bit int, then we must have the low 32 bits. - if (genActualType(varDsc->TypeGet()) == TYP_LONG) - { - rsRegValues[reg].rvdKind = RV_LCL_VAR_LNG_LO; - } - - rsRegValues[reg].rvdLclVarNum = var; -#endif // LEGACY_BACKEND } /*****************************************************************************/ -#ifdef LEGACY_BACKEND -void RegTracker::rsTrackRegSwap(regNumber reg1, regNumber reg2) -{ - RegValDsc tmp; - - tmp = rsRegValues[reg1]; - rsRegValues[reg1] = rsRegValues[reg2]; - rsRegValues[reg2] = tmp; -} -#endif // LEGACY_BACKEND - void RegTracker::rsTrackRegCopy(regNumber reg1, regNumber reg2) { /* Keep track of which registers we ever touch */ @@ -1462,62 +273,8 @@ void RegTracker::rsTrackRegCopy(regNumber reg1, regNumber reg2) assert(reg2 < REG_COUNT); regSet->rsSetRegsModified(genRegMask(reg1)); - -#ifdef LEGACY_BACKEND - rsRegValues[reg1] = rsRegValues[reg2]; -#endif // LEGACY_BACKEND -} - -#ifdef LEGACY_BACKEND - -/***************************************************************************** - * One of the operands of this complex address mode has been spilled - */ - -void rsAddrSpillOper(GenTree* addr) -{ - if (addr) - { - assert(addr->gtOper == GT_IND || addr->gtOper == GT_ARR_ELEM || addr->gtOper == GT_LEA || - addr->gtOper == GT_CMPXCHG); - - // GTF_SPILLED_OP2 says "both operands have been spilled" - assert((addr->gtFlags & GTF_SPILLED_OP2) == 0); - - if ((addr->gtFlags & GTF_SPILLED_OPER) == 0) - addr->gtFlags |= GTF_SPILLED_OPER; - else - addr->gtFlags |= GTF_SPILLED_OP2; - } } -void rsAddrUnspillOper(GenTree* addr) -{ - if (addr) - { - assert(addr->gtOper == GT_IND || addr->gtOper == GT_ARR_ELEM || addr->gtOper == GT_LEA || - addr->gtOper == GT_CMPXCHG); - - assert((addr->gtFlags & GTF_SPILLED_OPER) != 0); - - // Both operands spilled? */ - if ((addr->gtFlags & GTF_SPILLED_OP2) != 0) - addr->gtFlags &= ~GTF_SPILLED_OP2; - else - addr->gtFlags &= ~GTF_SPILLED_OPER; - } -} - -void RegSet::rsSpillRegIfUsed(regNumber reg) -{ - if (rsMaskUsed & genRegMask(reg)) - { - rsSpillReg(reg); - } -} - -#endif // LEGACY_BACKEND - //------------------------------------------------------------ // rsSpillTree: Spill the tree held in 'reg'. // @@ -1543,12 +300,11 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) GenTreeCall* call = nullptr; var_types treeType; -#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) +#if defined(_TARGET_ARM_) GenTreePutArgSplit* splitArg = nullptr; GenTreeMultiRegOp* multiReg = nullptr; #endif -#ifndef LEGACY_BACKEND if (tree->IsMultiRegCall()) { call = tree->AsCall(); @@ -1568,7 +324,6 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) } #endif // _TARGET_ARM_ else -#endif // !LEGACY_BACKEND { treeType = tree->TypeGet(); } @@ -1589,16 +344,6 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) rsNeededSpillReg = true; -#ifdef LEGACY_BACKEND - // The register we're spilling must be used but not locked - // or an enregistered variable. - - assert((mask & rsMaskUsed) == mask); - assert((mask & rsMaskLock) == 0); - assert((mask & rsMaskVars) == 0); -#endif // LEGACY_BACKEND - -#ifndef LEGACY_BACKEND // We should only be spilling nodes marked for spill, // vars should be handled elsewhere, and to prevent // spilling twice clear GTF_SPILL flag on tree node. @@ -1635,27 +380,14 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) assert(!varTypeIsMultiReg(tree)); tree->gtFlags &= ~GTF_SPILL; } -#endif // !LEGACY_BACKEND -#if CPU_LONG_USES_REGPAIR - // Are we spilling a part of a register pair? - if (treeType == TYP_LONG) - { - tempType = TYP_I_IMPL; - assert(genRegPairLo(tree->gtRegPair) == reg || genRegPairHi(tree->gtRegPair) == reg); - } - else - { - assert(tree->InReg()); - assert(tree->gtRegNum == reg); - } -#elif defined(_TARGET_ARM_) +#if defined(_TARGET_ARM_) assert(tree->gtRegNum == reg || (call != nullptr && call->GetRegNumByIdx(regIdx) == reg) || (splitArg != nullptr && splitArg->GetRegNumByIdx(regIdx) == reg) || (multiReg != nullptr && multiReg->GetRegNumByIdx(regIdx) == reg)); #else assert(tree->gtRegNum == reg || (call != nullptr && call->GetRegNumByIdx(regIdx) == reg)); -#endif // !CPU_LONG_USES_REGPAIR && !_TARGET_ARM_ +#endif // !_TARGET_ARM_ // Are any registers free for spillage? SpillDsc* spill = SpillDsc::alloc(m_rsCompiler, this, tempType); @@ -1667,87 +399,19 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) // Remember what it is we have spilled spill->spillTree = tree; -#ifdef LEGACY_BACKEND - spill->spillAddr = rsUsedAddr[reg]; -#endif // LEGACY_BACKEND #ifdef DEBUG if (m_rsCompiler->verbose) { printf("\t\t\t\t\t\t\tThe register %s spilled with ", m_rsCompiler->compRegVarName(reg)); Compiler::printTreeID(spill->spillTree); -#ifdef LEGACY_BACKEND - if (spill->spillAddr != nullptr) - { - Compiler::printTreeID(spill->spillAddr); - } -#endif // LEGACY_BACKEND } #endif -#ifdef LEGACY_BACKEND - // Is the register part of a complex address mode? - rsAddrSpillOper(rsUsedAddr[reg]); -#endif // LEGACY_BACKEND - // 'lastDsc' is 'spill' for simple cases, and will point to the last // multi-use descriptor if 'reg' is being multi-used SpillDsc* lastDsc = spill; -#ifdef LEGACY_BACKEND - if ((rsMaskMult & mask) == 0) - { - spill->spillMoreMultis = false; - } - else - { - // The register is being multi-used and will have entries in - // rsMultiDesc[reg]. Spill all of them (ie. move them to - // rsSpillDesc[reg]). - // When we unspill the reg, they will all be moved back to - // rsMultiDesc[]. - - spill->spillMoreMultis = true; - - SpillDsc* nextDsc = rsMultiDesc[reg]; - - do - { - assert(nextDsc != nullptr); - - // Is this multi-use part of a complex address mode? - rsAddrSpillOper(nextDsc->spillAddr); - - // Mark the tree node as having been spilled - rsMarkSpill(nextDsc->spillTree, reg); - - // lastDsc points to the last of the multi-spill descrs for 'reg' - nextDsc->spillTemp = temp; - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf(", "); - Compiler::printTreeID(nextDsc->spillTree); - printf("/"); - Compiler::printTreeID(nextDsc->spillAddr); - } -#endif - - lastDsc->spillNext = nextDsc; - lastDsc = nextDsc; - - nextDsc = nextDsc->spillNext; - } while (lastDsc->spillMoreMultis); - - rsMultiDesc[reg] = nextDsc; - - // 'reg' is no longer considered to be multi-used. We will set this - // mask again when this value gets unspilled - rsMaskMult &= ~mask; - } -#endif // LEGACY_BACKEND - // Insert the spill descriptor(s) in the list lastDsc->spillNext = rsSpillDesc[reg]; rsSpillDesc[reg] = spill; @@ -1767,10 +431,6 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) // Mark the tree node as having been spilled rsMarkSpill(tree, reg); -#ifdef LEGACY_BACKEND - // The register is now free - rsMarkRegFree(mask); -#else // In case of multi-reg call node also mark the specific // result reg as spilled. if (call != nullptr) @@ -1790,10 +450,9 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) multiReg->SetRegSpillFlagByIdx(regFlags, regIdx); } #endif // _TARGET_ARM_ -#endif //! LEGACY_BACKEND } -#if defined(_TARGET_X86_) && !FEATURE_STACK_FP_X87 +#if defined(_TARGET_X86_) /***************************************************************************** * * Spill the top of the FP x87 stack. @@ -1823,342 +482,14 @@ void RegSet::rsSpillFPStack(GenTreeCall* call) if (m_rsCompiler->verbose) printf("\n"); #endif - // m_rsCompiler->codeGen->inst_FS_ST(INS_fstp, emitActualTypeSize(treeType), temp, 0); + m_rsCompiler->codeGen->getEmitter()->emitIns_S(INS_fstp, emitActualTypeSize(treeType), temp->tdTempNum(), 0); /* Mark the tree node as having been spilled */ rsMarkSpill(call, reg); } -#endif // defined(_TARGET_X86_) && !FEATURE_STACK_FP_X87 - -#ifdef LEGACY_BACKEND - -/***************************************************************************** - * - * Spill the given register (which we assume to be currently marked as used). - */ - -void RegSet::rsSpillReg(regNumber reg) -{ - /* We must know the value in the register that we are spilling */ - GenTree* tree = rsUsedTree[reg]; - -#ifdef _TARGET_ARM_ - if (tree == NULL && genIsValidFloatReg(reg) && !genIsValidDoubleReg(reg)) - { - reg = REG_PREV(reg); - assert(rsUsedTree[reg]); - assert(rsUsedTree[reg]->TypeGet() == TYP_DOUBLE); - tree = rsUsedTree[reg]; - } -#endif - - rsSpillTree(reg, tree); - - /* The register no longer holds its original value */ - - rsUsedTree[reg] = NULL; -} - -/***************************************************************************** - * - * Spill all registers in 'regMask' that are currently marked as used. - */ - -void RegSet::rsSpillRegs(regMaskTP regMask) -{ - /* The registers we're spilling must not be locked, - or enregistered variables */ - - assert((regMask & rsMaskLock) == 0); - assert((regMask & rsMaskVars) == 0); - - /* Only spill what's currently marked as used */ - - regMask &= rsMaskUsed; - assert(regMask); - - regNumber regNum; - regMaskTP regBit; - - for (regNum = REG_FIRST, regBit = 1; regNum < REG_COUNT; regNum = REG_NEXT(regNum), regBit <<= 1) - { - if (regMask & regBit) - { - rsSpillReg(regNum); - - regMask &= rsMaskUsed; - - if (!regMask) - break; - } - } -} - -/***************************************************************************** - * - * The following table determines the order in which registers are considered - * for internal tree temps to live in - */ - -#ifdef LEGACY_BACKEND -extern const regNumber raRegTmpOrder[] = {REG_TMP_ORDER}; -extern const regNumber rpRegTmpOrder[] = {REG_PREDICT_ORDER}; -#if FEATURE_FP_REGALLOC -extern const regNumber raRegFltTmpOrder[] = {REG_FLT_TMP_ORDER}; -#endif -#endif // LEGACY_BACKEND - -/***************************************************************************** - * - * Choose a register from the given set in the preferred order (see above); - * if no registers are in the set return REG_STK. - */ - -regNumber RegSet::rsPickRegInTmpOrder(regMaskTP regMask) -{ - if (regMask == RBM_NONE) - return REG_STK; - - bool firstPass = true; - regMaskTP avoidMask = - ~rsGetModifiedRegsMask() & RBM_CALLEE_SAVED; // We want to avoid using any new callee saved register - - while (true) - { - /* Iterate the registers in the order specified by raRegTmpOrder */ - - for (unsigned index = 0; index < REG_TMP_ORDER_COUNT; index++) - { - regNumber candidateReg = raRegTmpOrder[index]; - regMaskTP candidateMask = genRegMask(candidateReg); - - // For a FP base frame, don't use FP register. - if (m_rsCompiler->codeGen->isFramePointerUsed() && (candidateMask == RBM_FPBASE)) - continue; - - // For the first pass avoid selecting a never used register when there are other registers available - if (firstPass && ((candidateMask & avoidMask) != 0)) - continue; - - if (regMask & candidateMask) - return candidateReg; - } - - if (firstPass == true) - firstPass = false; // OK, now we are willing to select a never used register - else - break; - } - - return REG_STK; -} - -/***************************************************************************** - * Choose a register from the 'regMask' set and return it. If no registers in - * the set are currently free, one of them will be spilled (even if other - * registers - not in the set - are currently free). - * - * If you don't require a register from a particular set, you should use rsPickReg() instead. - * - * rsModifiedRegsMask is modified to include the returned register. - */ - -regNumber RegSet::rsGrabReg(regMaskTP regMask) -{ - regMaskTP OKmask; - regNumber regNum; - regMaskTP regBit; - - assert(regMask); - regMask &= ~rsMaskLock; - assert(regMask); - - /* See if one of the desired registers happens to be free */ - - OKmask = regMask & rsRegMaskFree(); - - regNum = rsPickRegInTmpOrder(OKmask); - if (REG_STK != regNum) - { - goto RET; - } - - /* We'll have to spill one of the registers in 'regMask' */ - - OKmask = regMask & rsRegMaskCanGrab(); - assert(OKmask); - - for (regNum = REG_FIRST, regBit = 1; (regBit & OKmask) == 0; regNum = REG_NEXT(regNum), regBit <<= 1) - { - if (regNum >= REG_COUNT) - { - assert(!"no register to grab!"); - NO_WAY("Could not grab a register, Predictor should have prevented this!"); - } - } - - /* This will be the victim -- spill it */ - rsSpillReg(regNum); - - /* Make sure we did find a register to spill */ - assert(genIsValidReg(regNum)); - -RET: - /* Keep track of which registers we ever touch */ - rsSetRegsModified(genRegMask(regNum)); - return regNum; -} - -/***************************************************************************** - * Find a register to use and return it, spilling if necessary. - * - * Look for a register in the following order: First, try and find a free register - * in 'regBest' (if 'regBest' is RBM_NONE, skip this step). Second, try to find a - * free register in 'regMask' (if 'regMask' is RBM_NONE, skip this step). Note that - * 'regBest' doesn't need to be a subset of 'regMask'. Third, find any free - * register. Fourth, spill a register. The register to spill will be in 'regMask', - * if 'regMask' is not RBM_NONE. - * - * Note that 'regMask' and 'regBest' are purely recommendations, and can be ignored; - * the caller can't expect that the returned register will be in those sets. In - * particular, under register stress, we specifically will pick registers not in - * these sets to ensure that callers don't require a register from those sets - * (and to ensure callers can handle the spilling that might ensue). - * - * Calling rsPickReg() with the default arguments (which sets 'regMask' and 'regBest' to RBM_NONE) - * is equivalent to calling rsGrabReg(rsRegMaskFree()). - * - * rsModifiedRegsMask is modified to include the returned register. - */ - -regNumber RegSet::rsPickReg(regMaskTP regMask, regMaskTP regBest) -{ - regNumber regNum; - regMaskTP spillMask; - regMaskTP canGrabMask; - -#ifdef DEBUG - if (rsStressRegs() >= 1) - { - /* 'regMask' is purely a recommendation, and callers should be - able to handle the case where it is not satisfied. - The logic here tries to return ~regMask to check that all callers - are prepared to handle such a case */ - - regMaskTP badRegs = rsMaskMult & rsRegMaskCanGrab(); - - badRegs = rsUseIfZero(badRegs, rsMaskUsed & rsRegMaskCanGrab()); - badRegs = rsUseIfZero(badRegs, rsRegMaskCanGrab()); - badRegs = rsExcludeHint(badRegs, regMask); - - assert(badRegs != RBM_NONE); - - return rsGrabReg(badRegs); - } - -#endif - - regMaskTP freeMask = rsRegMaskFree(); - -AGAIN: - - /* By default we'd prefer to accept all available registers */ - - regMaskTP OKmask = freeMask; - - // OKmask = rsNarrowHint(OKmask, rsUselessRegs()); - - /* Is there a 'best' register set? */ - - if (regBest) - { - OKmask &= regBest; - if (OKmask) - goto TRY_REG; - else - goto TRY_ALL; - } - - /* Was a register set recommended by the caller? */ - - if (regMask) - { - OKmask &= regMask; - if (!OKmask) - goto TRY_ALL; - } - -TRY_REG: - - /* Iterate the registers in the order specified by raRegTmpOrder */ - - regNum = rsPickRegInTmpOrder(OKmask); - if (REG_STK != regNum) - { - goto RET; - } - -TRY_ALL: - - /* Were we considering 'regBest' ? */ - - if (regBest) - { - /* 'regBest' is no good -- ignore it and try 'regMask' instead */ - - regBest = RBM_NONE; - goto AGAIN; - } - - /* Now let's consider all available registers */ - - /* Were we limited in our consideration? */ - - if (!regMask) - { - /* We need to spill one of the free registers */ - - spillMask = freeMask; - } - else - { - /* Did we not consider all free registers? */ - - if ((regMask & freeMask) != freeMask) - { - /* The recommended regset didn't work, so try all available regs */ - - regNum = rsPickRegInTmpOrder(freeMask); - if (REG_STK != regNum) - goto RET; - } - - /* If we're going to spill, might as well go for the right one */ - - spillMask = regMask; - } - - /* Make sure we can spill some register. */ - - canGrabMask = rsRegMaskCanGrab(); - if ((spillMask & canGrabMask) == 0) - spillMask = canGrabMask; - - assert(spillMask); - - /* We have no choice but to spill one of the regs */ - - return rsGrabReg(spillMask); - -RET: - - rsSetRegsModified(genRegMask(regNum)); - return regNum; -} - -#endif // LEGACY_BACKEND +#endif // defined(_TARGET_X86_) /***************************************************************************** * @@ -2170,13 +501,6 @@ TempDsc* RegSet::rsGetSpillTempWord(regNumber reg, SpillDsc* dsc, SpillDsc* prev { assert((prevDsc == nullptr) || (prevDsc->spillNext == dsc)); -#ifdef LEGACY_BACKEND - /* Is dsc the last of a set of multi-used values */ - - if (prevDsc && prevDsc->spillMoreMultis && !dsc->spillMoreMultis) - prevDsc->spillMoreMultis = false; -#endif // LEGACY_BACKEND - /* Remove this spill entry from the register's list */ (prevDsc ? prevDsc->spillNext : rsSpillDesc[reg]) = dsc->spillNext; @@ -2192,200 +516,6 @@ TempDsc* RegSet::rsGetSpillTempWord(regNumber reg, SpillDsc* dsc, SpillDsc* prev return temp; } -#ifdef LEGACY_BACKEND -/***************************************************************************** - * - * Reload the value that was spilled from the given register (and free its - * spill descriptor while we're at it). Returns the new register (which will - * be a member of 'needReg' if that value is non-zero). - * - * 'willKeepNewReg' indicates if the caller intends to mark newReg as used. - * If not, then we can't unspill the other multi-used descriptor (if any). - * Instead, we will just hold on to the temp and unspill them - * again as needed. - */ - -regNumber RegSet::rsUnspillOneReg(GenTree* tree, regNumber oldReg, KeepReg willKeepNewReg, regMaskTP needReg) -{ - /* Was oldReg multi-used when it was spilled? */ - - SpillDsc *prevDsc, *multiDsc; - SpillDsc* spillDsc = rsGetSpillInfo(tree, oldReg, &prevDsc, &multiDsc); - noway_assert((spillDsc != NULL) && (multiDsc != NULL)); - - bool multiUsed = multiDsc->spillMoreMultis; - - /* We will use multiDsc to walk the rest of the spill list (if it's - multiUsed). As we're going to remove spillDsc from the multiDsc - list in the rsGetSpillTempWord() call we have to take care of the - case where multiDsc==spillDsc. We will set multiDsc as spillDsc->spillNext */ - if (multiUsed && multiDsc == spillDsc) - { - assert(spillDsc->spillNext); - multiDsc = spillDsc->spillNext; - } - - /* Get the temp and free the spill-descriptor */ - - TempDsc* temp = rsGetSpillTempWord(oldReg, spillDsc, prevDsc); - - // Pick a new home for the value: - // This must be a register matching the 'needReg' mask, if it is non-zero. - // Additionally, if 'oldReg' is in 'needMask' and it is free we will select oldReg. - // Also note that the rsGrabReg() call below may cause the chosen register to be spilled. - // - regMaskTP prefMask; - regMaskTP freeMask; - regNumber newReg; - var_types regType; - var_types loadType; - - bool floatUnspill = false; - -#if FEATURE_FP_REGALLOC - floatUnspill = genIsValidFloatReg(oldReg); -#endif - - if (floatUnspill) - { - if (temp->tdTempType() == TYP_DOUBLE) - regType = TYP_DOUBLE; - else - regType = TYP_FLOAT; - loadType = regType; - prefMask = genRegMaskFloat(oldReg, regType); - freeMask = RegFreeFloat(); - } - else - { - regType = TYP_I_IMPL; - loadType = temp->tdTempType(); - prefMask = genRegMask(oldReg); - freeMask = rsRegMaskFree(); - } - - if ((((prefMask & needReg) != 0) || (needReg == 0)) && ((prefMask & freeMask) != 0)) - { - needReg = prefMask; - } - - if (floatUnspill) - { - RegisterPreference pref(RBM_ALLFLOAT, needReg); - newReg = PickRegFloat(regType, &pref, true); - } - else - { - newReg = rsGrabReg(rsUseIfZero(needReg, RBM_ALLINT)); - } - - m_rsCompiler->codeGen->trashReg(newReg); - - /* Reload the value from the saved location into the new register */ - - m_rsCompiler->codeGen->reloadReg(loadType, temp, newReg); - - if (multiUsed && (willKeepNewReg == KEEP_REG)) - { - /* We will unspill all the other multi-use trees if the register - is going to be marked as used. If it is not going to be marked - as used, we will have a problem if the new register gets spilled - again. - */ - - /* We don't do the extra unspilling for complex address modes, - since someone up the call chain may have a different idea about - what registers are used to form the complex address mode (the - addrReg return value from genMakeAddressable). - - Also, it is not safe to unspill all the multi-uses with a TYP_LONG. - - Finally, it is not safe to unspill into a different register, because - the caller of genMakeAddressable caches the addrReg return value - (register mask), but when unspilling into a different register it's - not possible to inform the caller that addrReg is now different. - See bug #89946 for an example of this. There is an assert for this - in rsMarkRegFree via genDoneAddressable. - */ - - for (SpillDsc* dsc = multiDsc; /**/; dsc = dsc->spillNext) - { - if ((oldReg != newReg) || (dsc->spillAddr != NULL) || (dsc->spillTree->gtType == TYP_LONG)) - { - return newReg; - } - - if (!dsc->spillMoreMultis) - { - /* All the remaining multi-uses are fine. We will now - unspill them all */ - break; - } - } - - bool bFound = false; - SpillDsc* pDsc; - SpillDsc** ppPrev; - - for (pDsc = rsSpillDesc[oldReg], ppPrev = &rsSpillDesc[oldReg];; pDsc = pDsc->spillNext) - { - if (pDsc == multiDsc) - { - // We've found the sequence we were searching for - bFound = true; - } - - if (bFound) - { - rsAddrUnspillOper(pDsc->spillAddr); - - // Mark the tree node as having been unspilled into newReg - rsMarkUnspill(pDsc->spillTree, newReg); - } - - if (!pDsc->spillMoreMultis) - { - if (bFound) - { - // End of sequence - - // We link remaining sides of list - *ppPrev = pDsc->spillNext; - - // Exit walk - break; - } - else - { - ppPrev = &(pDsc->spillNext); - } - } - } - - /* pDsc points to the last multi-used descriptor from the spill-list - for the current value (pDsc->spillMoreMultis == false) */ - - pDsc->spillNext = rsMultiDesc[newReg]; - rsMultiDesc[newReg] = multiDsc; - - if (floatUnspill) - rsMaskMult |= genRegMaskFloat(newReg, regType); - else - rsMaskMult |= genRegMask(newReg); - } - - if (!multiUsed || (willKeepNewReg == KEEP_REG)) - { - // Free the temp, it's no longer used. - // For multi-used regs that aren't (willKeepNewReg == KEEP_REG), we didn't unspill everything, so - // we need to leave the temp for future unspilling. - m_rsCompiler->tmpRlsTemp(temp); - } - - return newReg; -} -#endif // LEGACY_BACKEND - //--------------------------------------------------------------------- // rsUnspillInPlace: The given tree operand has been spilled; just mark // it as unspilled so that we can use it as "normal" local. @@ -2407,8 +537,6 @@ regNumber RegSet::rsUnspillOneReg(GenTree* tree, regNumber oldReg, KeepReg willK // TempDsc* RegSet::rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regIdx /* =0 */) { - assert(!isRegPairType(tree->gtType)); - // Get the tree's SpillDsc SpillDsc* prevDsc; SpillDsc* spillDsc = rsGetSpillInfo(tree, oldReg, &prevDsc); @@ -2425,7 +553,7 @@ TempDsc* RegSet::rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regI flags &= ~GTF_SPILLED; call->SetRegSpillFlagByIdx(flags, regIdx); } -#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) +#if defined(_TARGET_ARM_) else if (tree->OperIsPutArgSplit()) { GenTreePutArgSplit* splitArg = tree->AsPutArgSplit(); @@ -2440,7 +568,7 @@ TempDsc* RegSet::rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regI flags &= ~GTF_SPILLED; multiReg->SetRegSpillFlagByIdx(flags, regIdx); } -#endif // !LEGACY_BACKEND && _TARGET_ARM_ +#endif // _TARGET_ARM_ else { tree->gtFlags &= ~GTF_SPILLED; @@ -2458,734 +586,11 @@ TempDsc* RegSet::rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regI return temp; } -#ifdef LEGACY_BACKEND - -/***************************************************************************** - * - * The given tree operand has been spilled; reload it into a register that - * is in 'needReg' (if 'needReg' is RBM_NONE, any register will do). If 'keepReg' - * is set to KEEP_REG, we'll mark the new register as used. - */ - -void RegSet::rsUnspillReg(GenTree* tree, regMaskTP needReg, KeepReg keepReg) -{ - assert(!isRegPairType(tree->gtType)); // use rsUnspillRegPair() - regNumber oldReg = tree->gtRegNum; - - /* Get the SpillDsc for the tree */ - - SpillDsc* spillDsc = rsGetSpillInfo(tree, oldReg); - PREFIX_ASSUME(spillDsc != NULL); - - /* Before spillDsc is stomped on by rsUnspillOneReg(), note whether - * the reg was part of an address mode - */ - - GenTree* unspillAddr = spillDsc->spillAddr; - - /* Pick a new home for the value */ - - regNumber newReg = rsUnspillOneReg(tree, oldReg, keepReg, needReg); - - /* Mark the tree node as having been unspilled into newReg */ - - rsMarkUnspill(tree, newReg); - - // If this reg was part of a complex address mode, need to clear this flag which - // tells address mode building that a component has been spilled - - rsAddrUnspillOper(unspillAddr); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tThe register %s unspilled from ", m_rsCompiler->compRegVarName(newReg)); - Compiler::printTreeID(tree); - printf("\n"); - } -#endif - - /* Mark the new value as used, if the caller desires so */ - - if (keepReg == KEEP_REG) - rsMarkRegUsed(tree, unspillAddr); -} -#endif // LEGACY_BACKEND - void RegSet::rsMarkSpill(GenTree* tree, regNumber reg) { -#ifdef LEGACY_BACKEND - tree->SetInReg(false); -#endif tree->gtFlags |= GTF_SPILLED; } -#ifdef LEGACY_BACKEND - -void RegSet::rsMarkUnspill(GenTree* tree, regNumber reg) -{ -#ifndef _TARGET_AMD64_ - assert(tree->gtType != TYP_LONG); -#endif // _TARGET_AMD64_ - - tree->gtFlags &= ~GTF_SPILLED; - tree->gtRegNum = reg; - tree->SetInReg(); -} - -/***************************************************************************** - * - * Choose a register pair from the given set (note: only registers in the - * given set will be considered). - */ - -regPairNo RegSet::rsGrabRegPair(regMaskTP regMask) -{ - regPairNo regPair; - regMaskTP OKmask; - regNumber reg1; - regNumber reg2; - - assert(regMask); - regMask &= ~rsMaskLock; - assert(regMask); - - /* We'd prefer to choose a free register pair if possible */ - - OKmask = regMask & rsRegMaskFree(); - - /* Any takers in the recommended/free set? */ - - regPair = rsFindRegPairNo(OKmask); - - if (regPair != REG_PAIR_NONE) - { - // The normal early exit - - /* Keep track of which registers we ever touch */ - rsSetRegsModified(genRegPairMask(regPair)); - - return regPair; - } - - /* We have no choice but to spill one or two used regs */ - - if (OKmask) - { - /* One (and only one) register is free and acceptable - grab it */ - - assert(genMaxOneBit(OKmask)); - - for (reg1 = REG_INT_FIRST; reg1 <= REG_INT_LAST; reg1 = REG_NEXT(reg1)) - { - if (OKmask & genRegMask(reg1)) - break; - } - assert(OKmask & genRegMask(reg1)); - } - else - { - /* No register is free and acceptable - we'll have to spill two */ - - reg1 = rsGrabReg(regMask); - } - - /* Temporarily lock the first register so it doesn't go away */ - - rsLockReg(genRegMask(reg1)); - - /* Now grab another register */ - - reg2 = rsGrabReg(regMask); - - /* We can unlock the first register now */ - - rsUnlockReg(genRegMask(reg1)); - - /* Convert the two register numbers into a pair */ - - if (reg1 < reg2) - regPair = gen2regs2pair(reg1, reg2); - else - regPair = gen2regs2pair(reg2, reg1); - - return regPair; -} - -/***************************************************************************** - * - * Choose a register pair from the given set (if non-zero) or from the set of - * currently available registers (if 'regMask' is zero). - */ - -regPairNo RegSet::rsPickRegPair(regMaskTP regMask) -{ - regMaskTP OKmask; - regPairNo regPair; - - int repeat = 0; - - /* By default we'd prefer to accept all available registers */ - - OKmask = rsRegMaskFree(); - - if (regMask) - { - /* A register set was recommended by the caller */ - - OKmask &= regMask; - } - -AGAIN: - - regPair = rsFindRegPairNo(OKmask); - - if (regPair != REG_PAIR_NONE) - { - return regPair; // Normal early exit - } - - regMaskTP freeMask; - regMaskTP spillMask; - - /* Now let's consider all available registers */ - - freeMask = rsRegMaskFree(); - - /* Were we limited in our consideration? */ - - if (!regMask) - { - /* We need to spill two of the free registers */ - - spillMask = freeMask; - } - else - { - /* Did we not consider all free registers? */ - - if ((regMask & freeMask) != freeMask && repeat == 0) - { - /* The recommended regset didn't work, so try all available regs */ - - OKmask = freeMask; - repeat++; - goto AGAIN; - } - - /* If we're going to spill, might as well go for the right one */ - - spillMask = regMask; - } - - /* Make sure that we have at least two bits set */ - - if (genMaxOneBit(spillMask & rsRegMaskCanGrab())) - spillMask = rsRegMaskCanGrab(); - - assert(!genMaxOneBit(spillMask)); - - /* We have no choice but to spill 1/2 of the regs */ - - return rsGrabRegPair(spillMask); -} - -/***************************************************************************** - * - * The given tree operand has been spilled; reload it into a register pair - * that is in 'needReg' (if 'needReg' is RBM_NONE, any register pair will do). If - * 'keepReg' is KEEP_REG, we'll mark the new register pair as used. It is - * assumed that the current register pair has been marked as used (modulo - * any spillage, of course). - */ - -void RegSet::rsUnspillRegPair(GenTree* tree, regMaskTP needReg, KeepReg keepReg) -{ - assert(isRegPairType(tree->gtType)); - - regPairNo regPair = tree->gtRegPair; - regNumber regLo = genRegPairLo(regPair); - regNumber regHi = genRegPairHi(regPair); - - /* Has the register holding the lower half been spilled? */ - - if (!rsIsTreeInReg(regLo, tree)) - { - /* Is the upper half already in the right place? */ - - if (rsIsTreeInReg(regHi, tree)) - { - // Temporarily lock the high part if necessary. If this register is a multi-use register that is shared - // with another tree, the register may already be locked. - const regMaskTP regHiMask = genRegMask(regHi); - const bool lockReg = (rsMaskLock & regHiMask) == 0; - if (lockReg) - { - rsLockUsedReg(regHiMask); - } - - /* Pick a new home for the lower half */ - - regLo = rsUnspillOneReg(tree, regLo, keepReg, needReg); - - /* We can unlock the high part now */ - if (lockReg) - { - rsUnlockUsedReg(regHiMask); - } - } - else - { - /* Pick a new home for the lower half */ - - regLo = rsUnspillOneReg(tree, regLo, keepReg, needReg); - } - } - else - { - /* Free the register holding the lower half */ - - rsMarkRegFree(genRegMask(regLo)); - } - - if (regHi != REG_STK) - { - /* Has the register holding the upper half been spilled? */ - - if (!rsIsTreeInReg(regHi, tree)) - { - regMaskTP regLoUsed = RBM_NONE; - - // Temporarily lock the low part if necessary. If this register is a multi-use register that is shared - // with another tree, the register may already be locked. - const regMaskTP regLoMask = genRegMask(regLo); - const bool lockReg = (rsMaskLock & regLoMask) == 0; - if (lockReg) - { - rsLockReg(regLoMask, ®LoUsed); - } - - /* Pick a new home for the upper half */ - - regHi = rsUnspillOneReg(tree, regHi, keepReg, needReg); - - /* We can unlock the low register now */ - if (lockReg) - { - rsUnlockReg(regLoMask, regLoUsed); - } - } - else - { - /* Free the register holding the upper half */ - - rsMarkRegFree(genRegMask(regHi)); - } - } - - /* The value is now residing in the new register */ - - tree->SetInReg(); - tree->gtFlags &= ~GTF_SPILLED; - tree->gtRegPair = gen2regs2pair(regLo, regHi); - - /* Mark the new value as used, if the caller desires so */ - - if (keepReg == KEEP_REG) - rsMarkRegPairUsed(tree); -} - -/***************************************************************************** - * - * The given register is being used by multiple trees (all of which represent - * the same logical value). Happens mainly because of REDUNDANT_LOAD; - * We don't want to really spill the register as it actually holds the - * value we want. But the multiple trees may be part of different - * addressing modes. - * Save the previous 'use' info so that when we return the register will - * appear unused. - */ - -void RegSet::rsRecMultiReg(regNumber reg, var_types type) -{ - SpillDsc* spill; - regMaskTP regMask; - - if (genIsValidFloatReg(reg) && isFloatRegType(type)) - regMask = genRegMaskFloat(reg, type); - else - regMask = genRegMask(reg); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tRegister %s multi-use inc for ", m_rsCompiler->compRegVarName(reg)); - Compiler::printTreeID(rsUsedTree[reg]); - printf(" multMask=" REG_MASK_ALL_FMT "\n", rsMaskMult | regMask); - } -#endif - - /* The register is supposed to be already used */ - - assert(regMask & rsMaskUsed); - - assert(rsUsedTree[reg]); - - /* Allocate/reuse a spill descriptor */ - - spill = SpillDsc::alloc(m_rsCompiler, this, rsUsedTree[reg]->TypeGet()); - - /* Record the current 'use' info in the spill descriptor */ - - spill->spillTree = rsUsedTree[reg]; - rsUsedTree[reg] = 0; - spill->spillAddr = rsUsedAddr[reg]; - rsUsedAddr[reg] = 0; - - /* Remember whether the register is already 'multi-use' */ - - spill->spillMoreMultis = ((rsMaskMult & regMask) != 0); - - /* Insert the new multi-use record in the list for the register */ - - spill->spillNext = rsMultiDesc[reg]; - rsMultiDesc[reg] = spill; - - /* This register is now 'multi-use' */ - - rsMaskMult |= regMask; -} - -/***************************************************************************** - * - * Free the given register, which is known to have multiple uses. - */ - -var_types RegSet::rsRmvMultiReg(regNumber reg) -{ - SpillDsc* dsc; - - assert(rsMaskMult & genRegMask(reg)); - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tRegister %s multi-use dec for ", m_rsCompiler->compRegVarName(reg)); - Compiler::printTreeID(rsUsedTree[reg]); - printf(" multMask=" REG_MASK_ALL_FMT "\n", rsMaskMult); - } -#endif - - /* Get hold of the spill descriptor for the register */ - - dsc = rsMultiDesc[reg]; - assert(dsc); - rsMultiDesc[reg] = dsc->spillNext; - - /* Copy the previous 'use' info from the descriptor */ - - assert(reg != REG_SPBASE); - rsUsedTree[reg] = dsc->spillTree; - rsUsedAddr[reg] = dsc->spillAddr; - - if (!(dsc->spillTree->gtFlags & GTF_SPILLED)) - m_rsGCInfo.gcMarkRegPtrVal(reg, dsc->spillTree->TypeGet()); - - var_types type = dsc->spillTree->TypeGet(); - regMaskTP regMask; - - if (genIsValidFloatReg(reg) && isFloatRegType(type)) - regMask = genRegMaskFloat(reg, type); - else - regMask = genRegMask(reg); - - /* Is only one use of the register left? */ - - if (!dsc->spillMoreMultis) - { - rsMaskMult -= regMask; - } - -#ifdef DEBUG - if (m_rsCompiler->verbose) - { - printf("\t\t\t\t\t\t\tRegister %s multi-use dec - now ", m_rsCompiler->compRegVarName(reg)); - Compiler::printTreeID(rsUsedTree[reg]); - printf(" multMask=" REG_MASK_ALL_FMT "\n", rsMaskMult); - } -#endif - - SpillDsc::freeDsc(this, dsc); - return type; -} -/*****************************************************************************/ -/***************************************************************************** - * - * Search for a register which contains the given constant value. - * Return success/failure and set the register if success. - * If the closeDelta argument is non-NULL then look for a - * register that has a close constant value. For ARM, find - * the closest register value, independent of constant delta. - * For non-ARM, only consider values that are within -128..+127. - * If one is found, *closeDelta is set to the difference that needs - * to be added to the register returned. On x86/amd64, an lea instruction - * is used to set the target register using the register that - * contains the close integer constant. - */ - -regNumber RegTracker::rsIconIsInReg(ssize_t val, ssize_t* closeDelta /* = NULL */) -{ - regNumber closeReg = REG_NA; - - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return REG_NA; - } - - for (regNumber reg = REG_INT_FIRST; reg <= REG_INT_LAST; reg = REG_NEXT(reg)) - { - if (rsRegValues[reg].rvdKind == RV_INT_CNS) - { - ssize_t regCnsVal = rsRegValues[reg].rvdIntCnsVal; - if (regCnsVal == val) - { - if (closeDelta) - { - *closeDelta = 0; - } - return reg; - } - if (closeDelta) - { -#ifdef _TARGET_ARM_ - // Find the smallest delta; the caller checks the size - // TODO-CQ: find the smallest delta from a low register? - // That is, is it better to return a high register with a - // small constant delta, or a low register with - // a larger offset? It's better to have a low register with an offset within the low register - // range, or a high register otherwise... - - ssize_t regCnsDelta = val - regCnsVal; - if ((closeReg == REG_NA) || (unsigned_abs(regCnsDelta) < unsigned_abs(*closeDelta))) - { - closeReg = reg; - *closeDelta = regCnsDelta; - } -#else - if (closeReg == REG_NA) - { - ssize_t regCnsDelta = val - regCnsVal; - /* Does delta fit inside a byte [-128..127] */ - if (regCnsDelta == (signed char)regCnsDelta) - { - closeReg = reg; - *closeDelta = (int)regCnsDelta; - } - } -#endif - } - } - } - - /* There was not an exact match */ - - return closeReg; /* will always be REG_NA when closeDelta is NULL */ -} - -/***************************************************************************** - * - * Assume all non-integer registers contain garbage (this is called when - * we encounter a code label that isn't jumped by any block; we need to - * clear pointer values out of the table lest the GC pointer tables get - * out of date). - */ - -void RegTracker::rsTrackRegClrPtr() -{ - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - /* Preserve constant values */ - - if (rsRegValues[reg].rvdKind == RV_INT_CNS) - { - /* Make sure we don't preserve NULL (it's a pointer) */ - - if (rsRegValues[reg].rvdIntCnsVal != NULL) - { - continue; - } - } - - /* Preserve variables known to not be pointers */ - - if (rsRegValues[reg].rvdKind == RV_LCL_VAR) - { - if (!varTypeIsGC(compiler->lvaTable[rsRegValues[reg].rvdLclVarNum].TypeGet())) - { - continue; - } - } - - rsRegValues[reg].rvdKind = RV_TRASH; - } -} - -/***************************************************************************** - * - * This routine trashes the registers that hold stack GCRef/ByRef variables. (VSW: 561129) - * It should be called at each gc-safe point. - * - * It returns a mask of the registers that used to contain tracked stack variables that - * were trashed. - * - */ - -regMaskTP RegTracker::rsTrashRegsForGCInterruptability() -{ - regMaskTP result = RBM_NONE; - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - if (rsRegValues[reg].rvdKind == RV_LCL_VAR) - { - LclVarDsc* varDsc = &compiler->lvaTable[rsRegValues[reg].rvdLclVarNum]; - - if (!varTypeIsGC(varDsc->TypeGet())) - { - continue; - } - - // Only stack locals got tracked. - assert(!varDsc->lvRegister); - - rsRegValues[reg].rvdKind = RV_TRASH; - - result |= genRegMask(reg); - } - } - - return result; -} - -/***************************************************************************** - * - * Search for a register which contains the given local var. - * Return success/failure and set the register if success. - * Return FALSE on register variables, because otherwise their lifetimes - * can get bungled with respect to pointer tracking. - */ - -regNumber RegTracker::rsLclIsInReg(unsigned var) -{ - assert(var < compiler->lvaCount); - - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return REG_NA; - } - - /* return false if register var so genMarkLclVar can do its job */ - - if (compiler->lvaTable[var].lvRegister) - { - return REG_NA; - } - - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - if (rsRegValues[reg].rvdLclVarNum == var && rsRegValues[reg].rvdKind == RV_LCL_VAR) - { - return reg; - } - } - - return REG_NA; -} - -/*****************************************************************************/ - -regPairNo RegTracker::rsLclIsInRegPair(unsigned var) -{ - assert(var < compiler->lvaCount); - - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return REG_PAIR_NONE; - } - - regValKind rvKind = RV_TRASH; - regNumber regNo = DUMMY_INIT(REG_NA); - - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - if (rvKind != rsRegValues[reg].rvdKind && rsTrackIsLclVarLng(rsRegValues[reg].rvdKind) && - rsRegValues[reg].rvdLclVarNum == var) - { - /* first occurrence of this variable ? */ - - if (rvKind == RV_TRASH) - { - regNo = reg; - rvKind = rsRegValues[reg].rvdKind; - } - else if (rvKind == RV_LCL_VAR_LNG_HI) - { - /* We found the lower half of the long */ - - return gen2regs2pair(reg, regNo); - } - else - { - /* We found the upper half of the long */ - - assert(rvKind == RV_LCL_VAR_LNG_LO); - return gen2regs2pair(regNo, reg); - } - } - } - - return REG_PAIR_NONE; -} - -/*****************************************************************************/ - -void RegTracker::rsTrashLclLong(unsigned var) -{ - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return; - } - - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - if (rsTrackIsLclVarLng(rsRegValues[reg].rvdKind) && rsRegValues[reg].rvdLclVarNum == var) - { - rsRegValues[reg].rvdKind = RV_TRASH; - } - } -} - -/***************************************************************************** - * - * Local's value has changed, mark all regs which contained it as trash. - */ - -void RegTracker::rsTrashLcl(unsigned var) -{ - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return; - } - - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - if (rsRegValues[reg].rvdKind == RV_LCL_VAR && rsRegValues[reg].rvdLclVarNum == var) - { - rsRegValues[reg].rvdKind = RV_TRASH; - } - } -} -#endif // LEGACY_BACKEND - /***************************************************************************** * * A little helper to trash the given set of registers. @@ -3209,33 +614,6 @@ void RegTracker::rsTrashRegSet(regMaskTP regMask) } } -#ifdef LEGACY_BACKEND -/***************************************************************************** - * - * Return a mask of registers that hold no useful value. - */ - -regMaskTP RegTracker::rsUselessRegs() -{ - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return RBM_ALLINT; - } - - regMaskTP mask = RBM_NONE; - for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) - { - if (rsRegValues[reg].rvdKind == RV_TRASH) - { - mask |= genRegMask(reg); - } - } - - return mask; -} - -/*****************************************************************************/ -#endif // LEGACY_BACKEND /*****************************************************************************/ /* @@ -3252,11 +630,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void Compiler::tmpInit() { -#ifdef LEGACY_BACKEND - tmpDoubleSpillMax = 0; - tmpIntSpillMax = 0; -#endif // LEGACY_BACKEND - tmpCount = 0; tmpSize = 0; #ifdef DEBUG @@ -3270,8 +643,6 @@ void Compiler::tmpInit() /* static */ var_types Compiler::tmpNormalizeType(var_types type) { -#ifndef LEGACY_BACKEND - type = genActualType(type); #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_) @@ -3284,23 +655,6 @@ var_types Compiler::tmpNormalizeType(var_types type) } #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_) -#else // LEGACY_BACKEND - if (!varTypeIsGC(type)) - { - switch (genTypeStSz(type)) - { - case 1: - type = TYP_INT; // Maps all 4-byte non-GC types to TYP_INT temps - break; - case 2: - type = TYP_DOUBLE; // Maps all 8-byte types to TYP_DOUBLE temps - break; - default: - assert(!"unexpected type"); - } - } -#endif // LEGACY_BACKEND - return type; } @@ -3345,35 +699,8 @@ TempDsc* Compiler::tmpGetTemp(var_types type) bool isNewTemp = false; #endif // DEBUG -#ifndef LEGACY_BACKEND - noway_assert(temp != nullptr); -#else // LEGACY_BACKEND - - if (temp == nullptr) - { -#ifdef DEBUG - isNewTemp = true; -#endif // DEBUG - tmpCount++; - tmpSize += (unsigned)size; - -#ifdef _TARGET_ARM_ - if (type == TYP_DOUBLE) - { - // Adjust tmpSize in case it needs alignment - tmpSize += TARGET_POINTER_SIZE; - } -#endif // _TARGET_ARM_ - - genEmitter->emitTmpSizeChanged(tmpSize); - - temp = new (this, CMK_Unknown) TempDsc(-((int)tmpCount), size, type); - } - -#endif // LEGACY_BACKEND - #ifdef DEBUG if (verbose) { @@ -3389,8 +716,6 @@ TempDsc* Compiler::tmpGetTemp(var_types type) return temp; } -#ifndef LEGACY_BACKEND - /***************************************************************************** * Preallocate 'count' temps of type 'type'. This type must be a normalized * type (by the definition of tmpNormalizeType()). @@ -3444,8 +769,6 @@ void Compiler::tmpPreAllocateTemps(var_types type, unsigned count) } } -#endif // !LEGACY_BACKEND - /***************************************************************************** * * Release the given temp. @@ -3628,38 +951,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /***************************************************************************** * - * Returns whether regPair is a combination of two x86 registers or - * contains a pseudo register. - * In debug it also asserts that reg1 and reg2 are not the same. - */ - -bool genIsProperRegPair(regPairNo regPair) -{ - regNumber rlo = genRegPairLo(regPair); - regNumber rhi = genRegPairHi(regPair); - - assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST); - - if (rlo == rhi) - { - return false; - } - - if (rlo == REG_L_STK || rhi == REG_L_STK) - { - return false; - } - - if (rlo >= REG_COUNT || rhi >= REG_COUNT) - { - return false; - } - - return (rlo != REG_STK && rhi != REG_STK); -} - -/***************************************************************************** - * * Given a register that is an argument register * returns the next argument register * @@ -3738,13 +1029,6 @@ void RegSet::rsSpillInit() memset(rsSpillDesc, 0, sizeof(rsSpillDesc)); -#ifdef LEGACY_BACKEND - memset(rsUsedTree, 0, sizeof(rsUsedTree)); - memset(rsUsedAddr, 0, sizeof(rsUsedAddr)); - memset(rsMultiDesc, 0, sizeof(rsMultiDesc)); - rsSpillFloat = nullptr; -#endif // LEGACY_BACKEND - rsNeededSpillReg = false; /* We don't have any descriptors allocated */ @@ -3840,11 +1124,6 @@ void RegSet::rsSpillChk() for (regNumber reg = REG_FIRST; reg < REG_COUNT; reg = REG_NEXT(reg)) { assert(rsSpillDesc[reg] == nullptr); - -#ifdef LEGACY_BACKEND - assert(rsUsedTree[reg] == NULL); - assert(rsMultiDesc[reg] == NULL); -#endif // LEGACY_BACKEND } } @@ -3856,24 +1135,3 @@ void RegSet::rsSpillChk() } #endif - -/*****************************************************************************/ -#ifdef LEGACY_BACKEND - -// inline -bool RegTracker::rsIconIsInReg(ssize_t val, regNumber reg) -{ - if (compiler->opts.MinOpts() || compiler->opts.compDbgCode) - { - return false; - } - - if (rsRegValues[reg].rvdKind == RV_INT_CNS && rsRegValues[reg].rvdIntCnsVal == val) - { - return true; - } - return false; -} - -#endif // LEGACY_BACKEND -/*****************************************************************************/ |