diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 4093f3b796bdf..3a6adb1a2a5da 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17974,11 +17974,14 @@ GenTreeLclVarCommon* GenTree::IsImplicitByrefParameterValuePreMorph(Compiler* co // compiler - compiler instance // addr - [out] tree representing the address computation on top of the implicit byref. // Will be the same as the return value if the whole implicit byref is used, for example. +// offset - [out] Offset that "addr" is adding on top of the returned local. // // Return Value: // Node for the local, or nullptr. // -GenTreeLclVar* GenTree::IsImplicitByrefParameterValuePostMorph(Compiler* compiler, GenTree** addr) +GenTreeLclVar* GenTree::IsImplicitByrefParameterValuePostMorph(Compiler* compiler, + GenTree** addr, + target_ssize_t* offset) { #if FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) // TODO-LOONGARCH64-CQ: enable this. @@ -17987,13 +17990,10 @@ GenTreeLclVar* GenTree::IsImplicitByrefParameterValuePostMorph(Compiler* compile return nullptr; } - *addr = AsIndir()->Addr(); - GenTree* innerAddr = *addr; + *addr = AsIndir()->Addr(); - while (innerAddr->OperIs(GT_ADD) && innerAddr->gtGetOp2()->IsCnsIntOrI()) - { - innerAddr = innerAddr->gtGetOp1(); - } + GenTree* innerAddr = *addr; + compiler->gtPeelOffsets(&innerAddr, offset); if (innerAddr->OperIs(GT_LCL_VAR)) { diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index ec043090da346..ec56b4d248d20 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1972,7 +1972,7 @@ struct GenTree unsigned* pSize = nullptr); GenTreeLclVarCommon* IsImplicitByrefParameterValuePreMorph(Compiler* compiler); - GenTreeLclVar* IsImplicitByrefParameterValuePostMorph(Compiler* compiler, GenTree** addr); + GenTreeLclVar* IsImplicitByrefParameterValuePostMorph(Compiler* compiler, GenTree** addr, target_ssize_t* offset); unsigned IsLclVarUpdateTree(GenTree** otherTree, genTreeOps* updateOper); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 0205f020825ff..981669da08e62 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -3157,13 +3157,15 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) if (opts.OptimizationEnabled() && arg->AbiInfo.PassedByRef) { GenTree* implicitByRefLclAddr; + target_ssize_t implicitByRefLclOffs; GenTreeLclVarCommon* implicitByRefLcl = - argx->IsImplicitByrefParameterValuePostMorph(this, &implicitByRefLclAddr); + argx->IsImplicitByrefParameterValuePostMorph(this, &implicitByRefLclAddr, &implicitByRefLclOffs); GenTreeLclVarCommon* lcl = implicitByRefLcl; if ((lcl == nullptr) && argx->OperIsLocal()) { - lcl = argx->AsLclVarCommon(); + lcl = argx->AsLclVarCommon(); + implicitByRefLclOffs = lcl->GetLclOffs(); } if (lcl != nullptr) @@ -3191,6 +3193,28 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) !varDsc->lvPromoted && !varDsc->lvIsStructField && ((lcl->gtFlags & GTF_VAR_DEATH) != 0); } + // Disallow the argument from potentially aliasing the return + // buffer. + if (omitCopy) + { + GenTreeLclVarCommon* retBuffer = gtCallGetDefinedRetBufLclAddr(call); + if ((retBuffer != nullptr) && (retBuffer->GetLclNum() == varNum)) + { + unsigned retBufferSize = typGetObjLayout(call->gtRetClsHnd)->GetSize(); + target_ssize_t retBufferStart = retBuffer->GetLclOffs(); + target_ssize_t retBufferEnd = retBufferStart + static_cast(retBufferSize); + + unsigned argSize = arg->GetSignatureType() == TYP_STRUCT + ? typGetObjLayout(arg->GetSignatureClassHandle())->GetSize() + : genTypeSize(arg->GetSignatureType()); + target_ssize_t implByrefStart = implicitByRefLclOffs; + target_ssize_t implByrefEnd = implByrefStart + static_cast(argSize); + + bool disjoint = (retBufferEnd <= implByrefStart) || (implByrefEnd <= retBufferStart); + omitCopy = disjoint; + } + } + if (omitCopy) { if (implicitByRefLcl != nullptr) @@ -3218,6 +3242,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) #endif JITDUMP("making an outgoing copy for struct arg\n"); + assert(!call->IsTailCall() || !arg->AbiInfo.PassedByRef); CORINFO_CLASS_HANDLE copyBlkClass = arg->GetSignatureClassHandle(); unsigned tmp = 0;