diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 21d87671a4143..21d2117447da7 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -7866,9 +7866,7 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa // Liveness phase will remove unnecessary initializations. if (info.compInitMem || compSuppressedZeroInit) { - unsigned varNum; - LclVarDsc* varDsc; - for (varNum = 0, varDsc = lvaTable; varNum < lvaCount; varNum++, varDsc++) + for (unsigned varNum = 0; varNum < lvaCount; varNum++) { #if FEATURE_FIXED_OUT_ARGS if (varNum == lvaOutgoingArgSpaceVar) @@ -7876,29 +7874,55 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa continue; } #endif // FEATURE_FIXED_OUT_ARGS - if (!varDsc->lvIsParam) + + LclVarDsc* varDsc = lvaGetDesc(varNum); + + if (varDsc->lvIsParam) { - var_types lclType = varDsc->TypeGet(); - bool isUserLocal = (varNum < info.compLocalsCount); - bool structWithGCFields = ((lclType == TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr()); - bool hadSuppressedInit = varDsc->lvSuppressedZeroInit; - if ((info.compInitMem && (isUserLocal || structWithGCFields)) || hadSuppressedInit) + continue; + } + +#if FEATURE_IMPLICIT_BYREFS + if (varDsc->lvPromoted) + { + LclVarDsc* firstField = lvaGetDesc(varDsc->lvFieldLclStart); + if (firstField->lvParentLcl != varNum) { - GenTree* lcl = gtNewLclvNode(varNum, lclType); - GenTree* init = nullptr; - if (varTypeIsStruct(lclType)) - { - init = gtNewBlkOpNode(lcl, gtNewIconNode(0)); - init = fgMorphInitBlock(init); - } - else - { - GenTree* zero = gtNewZeroConNode(lclType); - init = gtNewAssignNode(lcl, zero); - } - Statement* initStmt = gtNewStmt(init, callDI); - fgInsertStmtBefore(block, lastStmt, initStmt); + // Local copy for implicit byref promotion that was undone. Do + // not introduce new references to it, all uses have been + // morphed to access the parameter. + CLANG_FORMAT_COMMENT_ANCHOR; + +#ifdef DEBUG + LclVarDsc* param = lvaGetDesc(firstField->lvParentLcl); + assert(param->lvIsImplicitByRef && !param->lvPromoted); + assert(param->lvFieldLclStart == varNum); +#endif + continue; + } + } +#endif + + var_types lclType = varDsc->TypeGet(); + bool isUserLocal = (varNum < info.compLocalsCount); + bool structWithGCFields = ((lclType == TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr()); + bool hadSuppressedInit = varDsc->lvSuppressedZeroInit; + if ((info.compInitMem && (isUserLocal || structWithGCFields)) || hadSuppressedInit) + { + GenTree* lcl = gtNewLclvNode(varNum, lclType); + GenTree* init = nullptr; + if (varTypeIsStruct(lclType)) + { + init = gtNewBlkOpNode(lcl, gtNewIconNode(0)); + init = fgMorphInitBlock(init); + } + else + { + GenTree* zero = gtNewZeroConNode(lclType); + init = gtNewAssignNode(lcl, zero); } + Statement* initStmt = gtNewStmt(init, callDI); + fgInsertStmtBefore(block, lastStmt, initStmt); } } } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_81081/Runtime_81081.cs b/src/tests/JIT/Regression/JitBlue/Runtime_81081/Runtime_81081.cs new file mode 100644 index 0000000000000..3ca57de390d9c --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_81081/Runtime_81081.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +class Runtime_81081 +{ + static int Main() + { + Test(1234, default); + return 100; + } + + static int Test(int count, S16 s) + { + object o = "1234"; + if (count == 0 || o.GetHashCode() == 1234) + return 42; + + return Test(count - 1, s); + } + + struct S16 + { + public object A, B; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_81081/Runtime_81081.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_81081/Runtime_81081.csproj new file mode 100644 index 0000000000000..35f4225d00463 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_81081/Runtime_81081.csproj @@ -0,0 +1,10 @@ + + + Exe + True + + + + + +