diff options
Diffstat (limited to 'src/jit/regalloc.cpp')
-rw-r--r-- | src/jit/regalloc.cpp | 208 |
1 files changed, 93 insertions, 115 deletions
diff --git a/src/jit/regalloc.cpp b/src/jit/regalloc.cpp index 9dd7299906..8a7ad5a163 100644 --- a/src/jit/regalloc.cpp +++ b/src/jit/regalloc.cpp @@ -53,8 +53,6 @@ regMaskTP Compiler::raConfigRestrictMaskFP() return result; } -#ifdef LEGACY_BACKEND // We don't use any of the old register allocator functions when LSRA is used instead. - #if DOUBLE_ALIGN DWORD Compiler::getCanDoubleAlign() { @@ -67,8 +65,84 @@ DWORD Compiler::getCanDoubleAlign() return DEFAULT_DOUBLE_ALIGN; #endif } + +//------------------------------------------------------------------------ +// shouldDoubleAlign: Determine whether to double-align the frame +// +// Arguments: +// refCntStk - sum of ref counts for all stack based variables +// refCntEBP - sum of ref counts for EBP enregistered variables +// refCntWtdEBP - sum of wtd ref counts for EBP enregistered variables +// refCntStkParam - sum of ref counts for all stack based parameters +// refCntWtdStkDbl - sum of wtd ref counts for stack based doubles (including structs +// with double fields). +// +// Return Value: +// Returns true if this method estimates that a double-aligned frame would be beneficial +// +// Notes: +// The impact of a double-aligned frame is computed as follows: +// - We save a byte of code for each parameter reference (they are frame-pointer relative) +// - We pay a byte of code for each non-parameter stack reference. +// - We save the misalignment penalty and possible cache-line crossing penalty. +// This is estimated as 0 for SMALL_CODE, 16 for FAST_CODE and 4 otherwise. +// - We pay 7 extra bytes for: +// MOV EBP,ESP, +// LEA ESP,[EBP-offset] +// AND ESP,-8 to double align ESP +// - We pay one extra memory reference for each variable that could have been enregistered in EBP (refCntWtdEBP). +// +// If the misalignment penalty is estimated to be less than the bytes used, we don't double align. +// Otherwise, we compare the weighted ref count of ebp-enregistered variables aginst double the +// ref count for double-aligned values. +// +bool Compiler::shouldDoubleAlign( + unsigned refCntStk, unsigned refCntEBP, unsigned refCntWtdEBP, unsigned refCntStkParam, unsigned refCntWtdStkDbl) +{ + bool doDoubleAlign = false; + const unsigned DBL_ALIGN_SETUP_SIZE = 7; + + unsigned bytesUsed = refCntStk + refCntEBP - refCntStkParam + DBL_ALIGN_SETUP_SIZE; + unsigned misaligned_weight = 4; + + if (compCodeOpt() == Compiler::SMALL_CODE) + misaligned_weight = 0; + + if (compCodeOpt() == Compiler::FAST_CODE) + misaligned_weight *= 4; + + JITDUMP("\nDouble alignment:\n"); + JITDUMP(" Bytes that could be saved by not using EBP frame: %i\n", bytesUsed); + JITDUMP(" Sum of weighted ref counts for EBP enregistered variables: %i\n", refCntWtdEBP); + JITDUMP(" Sum of weighted ref counts for weighted stack based doubles: %i\n", refCntWtdStkDbl); + + if (bytesUsed > ((refCntWtdStkDbl * misaligned_weight) / BB_UNITY_WEIGHT)) + { + JITDUMP(" Predicting not to double-align ESP to save %d bytes of code.\n", bytesUsed); + } + else if (refCntWtdEBP > refCntWtdStkDbl * 2) + { + // TODO-CQ: On P4 2 Proc XEON's, SciMark.FFT degrades if SciMark.FFT.transform_internal is + // not double aligned. + // Here are the numbers that make this not double-aligned. + // refCntWtdStkDbl = 0x164 + // refCntWtdEBP = 0x1a4 + // We think we do need to change the heuristic to be in favor of double-align. + + JITDUMP(" Predicting not to double-align ESP to allow EBP to be used to enregister variables.\n"); + } + else + { + // OK we passed all of the benefit tests, so we'll predict a double aligned frame. + JITDUMP(" Predicting to create a double-aligned frame\n"); + doDoubleAlign = true; + } + return doDoubleAlign; +} #endif // DOUBLE_ALIGN +#ifdef LEGACY_BACKEND // We don't use any of the old register allocator functions when LSRA is used instead. + void Compiler::raInit() { #if FEATURE_STACK_FP_X87 @@ -2415,12 +2489,6 @@ regMaskTP Compiler::rpPredictTreeRegUse(GenTreePtr tree, { case GT_ASG: - if (tree->OperIsBlkOp()) - { - interferingRegs |= rpPredictBlkAsgRegUse(tree, predictReg, lockedRegs, rsvdRegs); - regMask = 0; - goto RETURN_CHECK; - } /* Is the value being assigned into a LCL_VAR? */ if (op1->gtOper == GT_LCL_VAR) { @@ -2486,6 +2554,12 @@ regMaskTP Compiler::rpPredictTreeRegUse(GenTreePtr tree, } } } + else if (tree->OperIsBlkOp()) + { + interferingRegs |= rpPredictBlkAsgRegUse(tree, predictReg, lockedRegs, rsvdRegs); + regMask = 0; + goto RETURN_CHECK; + } __fallthrough; case GT_CHS: @@ -4384,6 +4458,13 @@ regMaskTP Compiler::rpPredictTreeRegUse(GenTreePtr tree, case GT_ARR_LENGTH: goto GENERIC_UNARY; + case GT_INIT_VAL: + // This unary operator simply passes through the value from its child (much like GT_NOP) + // and thus won't need a scratch register. + regMask = rpPredictTreeRegUse(op1, predictReg, lockedRegs, rsvdRegs); + tree->gtUsedRegs = op1->gtUsedRegs; + goto RETURN_CHECK; + default: #ifdef DEBUG gtDispTree(tree); @@ -4525,7 +4606,7 @@ regMaskTP Compiler::rpPredictTreeRegUse(GenTreePtr tree, curArgMask = RBM_NONE; // Set of argument registers that are going to be setup by this arg tmpMask = RBM_NONE; // Set of additional temp registers that are need only to setup the current arg - assert(list->IsList()); + assert(list->OperIsList()); args = list->Current(); list = list->Rest(); @@ -5840,114 +5921,14 @@ regMaskTP Compiler::rpPredictAssignRegVars(regMaskTP regAvail) if (getCanDoubleAlign() == CAN_DOUBLE_ALIGN && (refCntWtdStkDbl > 0)) { - /* OK, there may be some benefit to double-aligning the frame */ - /* But let us compare the benefits vs. the costs of this */ - - /* - One cost to consider is the benefit of smaller code - when using EBP as a frame pointer register - - Each stack variable reference is an extra byte of code - if we use a double-aligned frame, parameters are - accessed via EBP for a double-aligned frame so they - don't use an extra byte of code. - - We pay one byte of code for each refCntStk and we pay - one byte or more for each refCntEBP but we save one - byte for each refCntStkParam. - - Our savings are the elimination of a possible misaligned - access and a possible DCU spilt when an access crossed - a cache-line boundry. - - We use the loop weighted value of - refCntWtdStkDbl * misaligned_weight (0, 4, 16) - to represent this savings. - */ - - // We also pay 7 extra bytes for the MOV EBP,ESP, - // LEA ESP,[EBP-0x10] and the AND ESP,-8 to double align ESP - const unsigned DBL_ALIGN_SETUP_SIZE = 7; - - unsigned bytesUsed = refCntStk + refCntEBP - refCntStkParam + DBL_ALIGN_SETUP_SIZE; - unsigned misaligned_weight = 4; - - if (compCodeOpt() == SMALL_CODE) - misaligned_weight = 0; - - if (compCodeOpt() == FAST_CODE) - misaligned_weight *= 4; - -#ifdef DEBUG - if (verbose) - { - printf("; Double alignment:\n"); - printf("; Bytes that could be save by not using EBP frame: %i\n", bytesUsed); - printf("; Sum of weighted ref counts for EBP enregistered variables: %i\n", refCntWtdEBP); - printf("; Sum of weighted ref counts for weighted stack based doubles: %i\n", refCntWtdStkDbl); - } -#endif - - if (bytesUsed > ((refCntWtdStkDbl * misaligned_weight) / BB_UNITY_WEIGHT)) - { - /* It's probably better to use EBP as a frame pointer */ - CLANG_FORMAT_COMMENT_ANCHOR; - -#ifdef DEBUG - if (verbose) - printf("; Predicting not to double-align ESP to save %d bytes of code.\n", bytesUsed); -#endif - goto NO_DOUBLE_ALIGN; - } - - /* - Another cost to consider is the benefit of using EBP to enregister - one or more integer variables - - We pay one extra memory reference for each refCntWtdEBP - - Our savings are the elimination of a possible misaligned - access and a possible DCU spilt when an access crossed - a cache-line boundry. - - */ - - // <BUGNUM> - // VSW 346717: On P4 2 Proc XEON's, SciMark.FFT degrades if SciMark.FFT.transform_internal is - // not double aligned. - // Here are the numbers that make this not double-aligned. - // refCntWtdStkDbl = 0x164 - // refCntWtdEBP = 0x1a4 - // We think we do need to change the heuristic to be in favor of double-align. - // </BUGNUM> - - if (refCntWtdEBP > refCntWtdStkDbl * 2) + if (shouldDoubleAlign(refCntStk, refCntEBP, refCntWtdEBP, refCntStkParam, refCntWtdStkDbl)) { - /* It's probably better to use EBP to enregister integer variables */ - CLANG_FORMAT_COMMENT_ANCHOR; - -#ifdef DEBUG - if (verbose) - printf("; Predicting not to double-align ESP to allow EBP to be used to enregister variables\n"); -#endif - goto NO_DOUBLE_ALIGN; + rpFrameType = FT_DOUBLE_ALIGN_FRAME; + goto REVERSE_EBP_ENREG; } - -#ifdef DEBUG - if (verbose) - printf("; Predicting to create a double-aligned frame\n"); -#endif - /* - OK we passed all of the benefit tests - so we'll predict a double aligned frame - */ - - rpFrameType = FT_DOUBLE_ALIGN_FRAME; - goto REVERSE_EBP_ENREG; } } -NO_DOUBLE_ALIGN: #endif // DOUBLE_ALIGN if (!codeGen->isFramePointerRequired() && !codeGen->isFrameRequired()) @@ -6673,8 +6654,6 @@ void Compiler::raMarkStkVars() #endif // FEATURE_FIXED_OUT_ARGS -#ifdef DEBUGGING_SUPPORT - #ifdef DEBUG /* For debugging, note that we have to reserve space even for unused variables if they are ever in scope. However, this is not @@ -6709,7 +6688,6 @@ void Compiler::raMarkStkVars() varDsc->lvMustInit = true; } } -#endif // DEBUGGING_SUPPORT #ifndef LEGACY_BACKEND varDsc->lvOnFrame = needSlot; |