diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index a5472a3be8de06..61aa9207d05a66 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4091,6 +4091,8 @@ class Compiler unsigned lvaInlineeReturnSpillTemp = BAD_VAR_NUM; // The temp to spill the non-VOID return expression // in case there are multiple BBJ_RETURN blocks in the inlinee // or if the inlinee has GC ref locals. + + bool lvaInlineeReturnSpillTempFreshlyCreated = false; // True if the temp was freshly created for the inlinee return #if FEATURE_FIXED_OUT_ARGS unsigned lvaOutgoingArgSpaceVar = BAD_VAR_NUM; // var that represents outgoing argument space @@ -4355,7 +4357,7 @@ class Compiler // If the local is TYP_REF, set or update the associated class information. void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false); void lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr); - void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false); + void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false, bool singleDefOnly = true); void lvaUpdateClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr); #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index a34e2622157ba3..6772977aed91a4 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -3562,6 +3562,8 @@ void Compiler::fgFindBasicBlocks() lvaSetClass(lvaInlineeReturnSpillTemp, retClassHnd); } } + + lvaInlineeReturnSpillTempFreshlyCreated = true; } } diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 2c0ca450bc8243..8c8376694281f6 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -309,7 +309,7 @@ PhaseStatus Compiler::fgPostImportationCleanup() { // Update type of return spill temp if we have gathered // better info when importing the inlinee, and the return - // spill temp is single def. + // spill temp is single def or was freshly created for this inlinee if (fgNeedReturnSpillTemp()) { CORINFO_CLASS_HANDLE retExprClassHnd = impInlineInfo->retExprClassHnd; @@ -317,9 +317,11 @@ PhaseStatus Compiler::fgPostImportationCleanup() { LclVarDsc* returnSpillVarDsc = lvaGetDesc(lvaInlineeReturnSpillTemp); - if ((returnSpillVarDsc->lvType == TYP_REF) && returnSpillVarDsc->lvSingleDef) + if (returnSpillVarDsc->lvType == TYP_REF && + (returnSpillVarDsc->lvSingleDef || lvaInlineeReturnSpillTempFreshlyCreated)) { - lvaUpdateClass(lvaInlineeReturnSpillTemp, retExprClassHnd, impInlineInfo->retExprClassHndIsExact); + lvaUpdateClass(lvaInlineeReturnSpillTemp, retExprClassHnd, impInlineInfo->retExprClassHndIsExact, + false); } } } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 0435ecf0b514e4..4246e58f9fd869 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -11076,13 +11076,21 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) impInlineInfo->retExprClassHnd = returnClsHnd; impInlineInfo->retExprClassHndIsExact = isExact; } - else if (impInlineInfo->retExprClassHnd != returnClsHnd) + else { - // This return site type differs from earlier seen sites, - // so reset the info and we'll fall back to using the method's - // declared return type for the return spill temp. - impInlineInfo->retExprClassHnd = nullptr; - impInlineInfo->retExprClassHndIsExact = false; + if (impInlineInfo->retExprClassHnd != returnClsHnd) + { + // This return site type differs from earlier seen sites, + // so reset the info and we'll fall back to using the method's + // declared return type for the return spill temp. + impInlineInfo->retExprClassHnd = nullptr; + impInlineInfo->retExprClassHndIsExact = false; + } + else + { + // Same return type, but we may need to update exactness. + impInlineInfo->retExprClassHndIsExact &= isExact; + } } } diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index ad9b203b454e3b..dc5144b0431659 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -3601,6 +3601,7 @@ void Compiler::lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE // varNum -- number of the variable // clsHnd -- class handle to use in set or update // isExact -- true if class is known exactly +// singleDefOnly -- true if we should only update single-def locals // // Notes: // @@ -3618,7 +3619,7 @@ void Compiler::lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE // for shared code, so ensuring this is so is currently not // possible. -void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact) +void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact, bool singleDefOnly) { assert(varNum < lvaCount); @@ -3631,8 +3632,12 @@ void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool // We should already have a class assert(varDsc->lvClassHnd != NO_CLASS_HANDLE); - // We should only be updating classes for single-def locals. - assert(varDsc->lvSingleDef); + // We should only be updating classes for single-def locals if requested + if (singleDefOnly && !varDsc->lvSingleDef) + { + assert(!"Updating class for multi-def local"); + return; + } // Now see if we should update. // @@ -3679,7 +3684,7 @@ void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool } //------------------------------------------------------------------------ -// lvaUpdateClass: Uupdate class information for a local var from a tree +// lvaUpdateClass: Update class information for a local var from a tree // or stack type // // Arguments: