Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Allow forwarding field accesses off of implicit byrefs #80852

Merged
merged 2 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 49 additions & 16 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16961,38 +16961,71 @@ const GenTreeLclVarCommon* GenTree::IsLocalAddrExpr() const
}

//------------------------------------------------------------------------
// IsImplicitByrefParameterValue: determine if this tree is the entire
// value of a local implicit byref parameter
// IsImplicitByrefParameterValuePreMorph:
// Determine if this tree represents the value of an implicit byref
// parameter, and if so return the tree for the parameter. To be used
// before implicit byrefs have been morphed.
//
// Arguments:
// compiler -- compiler instance
// compiler - compiler instance
//
// Return Value:
// GenTreeLclVar node for the local, or nullptr.
// Node for the local, or nullptr.
//
GenTreeLclVar* GenTree::IsImplicitByrefParameterValue(Compiler* compiler)
GenTreeLclVarCommon* GenTree::IsImplicitByrefParameterValuePreMorph(Compiler* compiler)
{
#if FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) // TODO-LOONGARCH64-CQ: enable this.

GenTreeLclVar* lcl = nullptr;
GenTreeLclVarCommon* lcl = OperIsLocal() ? AsLclVarCommon() : nullptr;

if (OperIs(GT_LCL_VAR))
if ((lcl != nullptr) && compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum()))
{
lcl = AsLclVar();
return lcl;
}
else if (OperIsIndir())

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

return nullptr;
}

//------------------------------------------------------------------------
// IsImplicitByrefParameterValuePostMorph:
// Determine if this tree represents the value of an implicit byref
// parameter, and if so return the tree for the parameter. To be used after
// implicit byrefs have been morphed.
//
// Arguments:
// 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.
//
// Return Value:
// Node for the local, or nullptr.
//
GenTreeLclVar* GenTree::IsImplicitByrefParameterValuePostMorph(Compiler* compiler, GenTree** addr)
{
#if FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) // TODO-LOONGARCH64-CQ: enable this.

if (!OperIsIndir())
{
GenTree* addr = AsIndir()->Addr();
return nullptr;
}

if (addr->OperIs(GT_LCL_VAR, GT_LCL_VAR_ADDR))
{
lcl = addr->AsLclVar();
}
*addr = AsIndir()->Addr();
GenTree* innerAddr = *addr;

while (innerAddr->OperIs(GT_ADD) && innerAddr->gtGetOp2()->IsCnsIntOrI())
{
innerAddr = innerAddr->gtGetOp1();
}

if ((lcl != nullptr) && compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum()))
if (innerAddr->OperIs(GT_LCL_VAR))
{
return lcl;
GenTreeLclVar* lcl = innerAddr->AsLclVar();
if (compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum()))
{
return lcl;
}
}

#endif // FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64)
Expand Down
5 changes: 2 additions & 3 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1970,9 +1970,8 @@ struct GenTree
return const_cast<GenTreeLclVarCommon*>(static_cast<const GenTree*>(this)->IsLocalAddrExpr());
}

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

// Determine whether this is an assignment tree of the form X = X (op) Y,
// where Y is an arbitrary tree, and X is a lclVar.
Expand Down
12 changes: 7 additions & 5 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3947,7 +3947,9 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
//
if (opts.OptimizationEnabled() && arg->AbiInfo.PassedByRef)
{
GenTreeLclVarCommon* implicitByRefLcl = argx->IsImplicitByrefParameterValue(this);
GenTree* implicitByRefLclAddr;
GenTreeLclVarCommon* implicitByRefLcl =
argx->IsImplicitByrefParameterValuePostMorph(this, &implicitByRefLclAddr);

GenTreeLclVarCommon* lcl = implicitByRefLcl;
if ((lcl == nullptr) && argx->OperIsLocal())
Expand Down Expand Up @@ -3993,7 +3995,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
{
if (implicitByRefLcl != nullptr)
{
arg->SetEarlyNode(lcl);
arg->SetEarlyNode(implicitByRefLclAddr);
}
else
{
Expand Down Expand Up @@ -5890,8 +5892,8 @@ bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* callee)
// and so still be able to avoid a struct copy.
if (opts.OptimizationEnabled())
{
// First, see if this arg is an implicit byref param.
GenTreeLclVar* const lcl = arg.GetNode()->IsImplicitByrefParameterValue(this);
// First, see if this is an arg off of an implicit byref param.
GenTreeLclVarCommon* const lcl = arg.GetNode()->IsImplicitByrefParameterValuePreMorph(this);

if (lcl != nullptr)
{
Expand Down Expand Up @@ -5963,7 +5965,7 @@ bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* callee)
if (arg2.AbiInfo.IsStruct && arg2.AbiInfo.PassedByRef)
{
GenTreeLclVarCommon* const lcl2 =
arg2.GetNode()->IsImplicitByrefParameterValue(this);
arg2.GetNode()->IsImplicitByrefParameterValuePreMorph(this);

if ((lcl2 != nullptr) && (lclNum == lcl2->GetLclNum()))
{
Expand Down