Skip to content

Commit 5fda6fd

Browse files
authored
JIT: Allow forwarding field accesses off of implicit byrefs (#80852)
The JIT currently allows forwarding implicit byrefs at their last uses to calls, but only if the full implicit byref is used. This change allows the JIT to forward any such access off of an implicit byref parameter.
1 parent a39435f commit 5fda6fd

File tree

3 files changed

+58
-24
lines changed

3 files changed

+58
-24
lines changed

src/coreclr/jit/gentree.cpp

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16963,38 +16963,71 @@ const GenTreeLclVarCommon* GenTree::IsLocalAddrExpr() const
1696316963
}
1696416964

1696516965
//------------------------------------------------------------------------
16966-
// IsImplicitByrefParameterValue: determine if this tree is the entire
16967-
// value of a local implicit byref parameter
16966+
// IsImplicitByrefParameterValuePreMorph:
16967+
// Determine if this tree represents the value of an implicit byref
16968+
// parameter, and if so return the tree for the parameter. To be used
16969+
// before implicit byrefs have been morphed.
1696816970
//
1696916971
// Arguments:
16970-
// compiler -- compiler instance
16972+
// compiler - compiler instance
1697116973
//
1697216974
// Return Value:
16973-
// GenTreeLclVar node for the local, or nullptr.
16975+
// Node for the local, or nullptr.
1697416976
//
16975-
GenTreeLclVar* GenTree::IsImplicitByrefParameterValue(Compiler* compiler)
16977+
GenTreeLclVarCommon* GenTree::IsImplicitByrefParameterValuePreMorph(Compiler* compiler)
1697616978
{
1697716979
#if FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) // TODO-LOONGARCH64-CQ: enable this.
1697816980

16979-
GenTreeLclVar* lcl = nullptr;
16981+
GenTreeLclVarCommon* lcl = OperIsLocal() ? AsLclVarCommon() : nullptr;
1698016982

16981-
if (OperIs(GT_LCL_VAR))
16983+
if ((lcl != nullptr) && compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum()))
1698216984
{
16983-
lcl = AsLclVar();
16985+
return lcl;
1698416986
}
16985-
else if (OperIsIndir())
16987+
16988+
#endif // FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64)
16989+
16990+
return nullptr;
16991+
}
16992+
16993+
//------------------------------------------------------------------------
16994+
// IsImplicitByrefParameterValuePostMorph:
16995+
// Determine if this tree represents the value of an implicit byref
16996+
// parameter, and if so return the tree for the parameter. To be used after
16997+
// implicit byrefs have been morphed.
16998+
//
16999+
// Arguments:
17000+
// compiler - compiler instance
17001+
// addr - [out] tree representing the address computation on top of the implicit byref.
17002+
// Will be the same as the return value if the whole implicit byref is used, for example.
17003+
//
17004+
// Return Value:
17005+
// Node for the local, or nullptr.
17006+
//
17007+
GenTreeLclVar* GenTree::IsImplicitByrefParameterValuePostMorph(Compiler* compiler, GenTree** addr)
17008+
{
17009+
#if FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) // TODO-LOONGARCH64-CQ: enable this.
17010+
17011+
if (!OperIsIndir())
1698617012
{
16987-
GenTree* addr = AsIndir()->Addr();
17013+
return nullptr;
17014+
}
1698817015

16989-
if (addr->OperIs(GT_LCL_VAR, GT_LCL_VAR_ADDR))
16990-
{
16991-
lcl = addr->AsLclVar();
16992-
}
17016+
*addr = AsIndir()->Addr();
17017+
GenTree* innerAddr = *addr;
17018+
17019+
while (innerAddr->OperIs(GT_ADD) && innerAddr->gtGetOp2()->IsCnsIntOrI())
17020+
{
17021+
innerAddr = innerAddr->gtGetOp1();
1699317022
}
1699417023

16995-
if ((lcl != nullptr) && compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum()))
17024+
if (innerAddr->OperIs(GT_LCL_VAR))
1699617025
{
16997-
return lcl;
17026+
GenTreeLclVar* lcl = innerAddr->AsLclVar();
17027+
if (compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum()))
17028+
{
17029+
return lcl;
17030+
}
1699817031
}
1699917032

1700017033
#endif // FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64)

src/coreclr/jit/gentree.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,9 +1971,8 @@ struct GenTree
19711971
return const_cast<GenTreeLclVarCommon*>(static_cast<const GenTree*>(this)->IsLocalAddrExpr());
19721972
}
19731973

1974-
// Determine if this tree represents the value of an entire implicit byref parameter,
1975-
// and if so return the tree for the parameter.
1976-
GenTreeLclVar* IsImplicitByrefParameterValue(Compiler* compiler);
1974+
GenTreeLclVarCommon* IsImplicitByrefParameterValuePreMorph(Compiler* compiler);
1975+
GenTreeLclVar* IsImplicitByrefParameterValuePostMorph(Compiler* compiler, GenTree** addr);
19771976

19781977
// Determine whether this is an assignment tree of the form X = X (op) Y,
19791978
// where Y is an arbitrary tree, and X is a lclVar.

src/coreclr/jit/morph.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3947,7 +3947,9 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
39473947
//
39483948
if (opts.OptimizationEnabled() && arg->AbiInfo.PassedByRef)
39493949
{
3950-
GenTreeLclVarCommon* implicitByRefLcl = argx->IsImplicitByrefParameterValue(this);
3950+
GenTree* implicitByRefLclAddr;
3951+
GenTreeLclVarCommon* implicitByRefLcl =
3952+
argx->IsImplicitByrefParameterValuePostMorph(this, &implicitByRefLclAddr);
39513953

39523954
GenTreeLclVarCommon* lcl = implicitByRefLcl;
39533955
if ((lcl == nullptr) && argx->OperIsLocal())
@@ -3993,7 +3995,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
39933995
{
39943996
if (implicitByRefLcl != nullptr)
39953997
{
3996-
arg->SetEarlyNode(lcl);
3998+
arg->SetEarlyNode(implicitByRefLclAddr);
39973999
}
39984000
else
39994001
{
@@ -5920,8 +5922,8 @@ bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* callee)
59205922
// and so still be able to avoid a struct copy.
59215923
if (opts.OptimizationEnabled())
59225924
{
5923-
// First, see if this arg is an implicit byref param.
5924-
GenTreeLclVar* const lcl = arg.GetNode()->IsImplicitByrefParameterValue(this);
5925+
// First, see if this is an arg off of an implicit byref param.
5926+
GenTreeLclVarCommon* const lcl = arg.GetNode()->IsImplicitByrefParameterValuePreMorph(this);
59255927

59265928
if (lcl != nullptr)
59275929
{
@@ -5993,7 +5995,7 @@ bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* callee)
59935995
if (arg2.AbiInfo.IsStruct && arg2.AbiInfo.PassedByRef)
59945996
{
59955997
GenTreeLclVarCommon* const lcl2 =
5996-
arg2.GetNode()->IsImplicitByrefParameterValue(this);
5998+
arg2.GetNode()->IsImplicitByrefParameterValuePreMorph(this);
59975999

59986000
if ((lcl2 != nullptr) && (lclNum == lcl2->GetLclNum()))
59996001
{

0 commit comments

Comments
 (0)