Skip to content

Commit

Permalink
Fold all local addresses in local morph (#79194)
Browse files Browse the repository at this point in the history
* Fix FIELD<struct> size calculation

"getFieldClass" returns the field's owner class, not its own.

* Precise value numbering for local addresses

* ADD(LCL_ADDR, CONST) => LCL_FLD_ADDR

* Fold to local address nodes in local morph

Unconditionally.

* Clean up lvQuirkToLong

* Support ADD(ADDR(LCL), CONST) in local morph

* Morph the local address for locations

* Fold hidden buffer args too

* Fix gcWriteBarrierFormFromTargetAddress

* Simplify IsLocalAddrExpr equivalents

No diffs except for one regression in a 400K bytes struct test.
  • Loading branch information
SingleAccretion authored Dec 6, 2022
1 parent 2b52095 commit e1081df
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 292 deletions.
2 changes: 0 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2970,8 +2970,6 @@ class Compiler

typedef ArrayStack<GenTree*> GenTreeStack;

static bool gtHasCallOnStack(GenTreeStack* parentStack);

//=========================================================================
// BasicBlock functions
#ifdef DEBUG
Expand Down
23 changes: 0 additions & 23 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,29 +754,6 @@ GenTreeLclVar* Compiler::fgIsIndirOfAddrOfLocal(GenTree* tree)
{
GenTree* addr = tree->AsIndir()->Addr();

// Post rationalization, we can have Indir(Lea(..) trees. Therefore to recognize
// Indir of addr of a local, skip over Lea in Indir(Lea(base, index, scale, offset))
// to get to base variable.
if (addr->OperGet() == GT_LEA)
{
// We use this method in backward dataflow after liveness computation - fgInterBlockLocalVarLiveness().
// Therefore it is critical that we don't miss 'uses' of any local. It may seem this method overlooks
// if the index part of the LEA has indir( someAddrOperator ( lclVar ) ) to search for a use but it's
// covered by the fact we're traversing the expression in execution order and we also visit the index.
GenTreeAddrMode* lea = addr->AsAddrMode();
GenTree* base = lea->Base();

if (base != nullptr)
{
if (base->OperGet() == GT_IND)
{
return fgIsIndirOfAddrOfLocal(base);
}
// else use base as addr
addr = base;
}
}

if (addr->OperGet() == GT_ADDR)
{
GenTree* lclvar = addr->AsOp()->gtOp1;
Expand Down
14 changes: 7 additions & 7 deletions src/coreclr/jit/gcinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,13 @@ GCInfo::WriteBarrierForm GCInfo::gcIsWriteBarrierCandidate(GenTreeStoreInd* stor
//
GCInfo::WriteBarrierForm GCInfo::gcWriteBarrierFormFromTargetAddress(GenTree* tgtAddr)
{
// We will assume there is no point in trying to deconstruct a TYP_I_IMPL address.
if (tgtAddr->IsLocalAddrExpr() != nullptr)
{
// No need for a GC barrier when writing to a local variable.
return GCInfo::WBF_NoBarrier;
}

// No point in trying to further deconstruct a TYP_I_IMPL address.
if (tgtAddr->TypeGet() == TYP_I_IMPL)
{
return GCInfo::WBF_BarrierUnknown;
Expand Down Expand Up @@ -347,12 +353,6 @@ GCInfo::WriteBarrierForm GCInfo::gcWriteBarrierFormFromTargetAddress(GenTree* tg
}
}

if (tgtAddr->IsLocalAddrExpr() != nullptr)
{
// No need for a GC barrier when writing to a local variable.
return GCInfo::WBF_NoBarrier;
}

if (tgtAddr->TypeGet() == TYP_REF)
{
return GCInfo::WBF_BarrierUnchecked;
Expand Down
122 changes: 8 additions & 114 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16407,33 +16407,6 @@ bool Compiler::gtHasCatchArg(GenTree* tree)
return false;
}

//------------------------------------------------------------------------
// gtHasCallOnStack:
//
// Arguments:
// parentStack: a context (stack of parent nodes)
//
// Return Value:
// returns true if any of the parent nodes are a GT_CALL
//
// Assumptions:
// We have a stack of parent nodes. This generally requires that
// we are performing a recursive tree walk using struct fgWalkData
//
//------------------------------------------------------------------------
/* static */ bool Compiler::gtHasCallOnStack(GenTreeStack* parentStack)
{
for (int i = 0; i < parentStack->Height(); i++)
{
GenTree* node = parentStack->Top(i);
if (node->OperGet() == GT_CALL)
{
return true;
}
}
return false;
}

//------------------------------------------------------------------------
// gtGetTypeProducerKind: determine if a tree produces a runtime type, and
// if so, how.
Expand Down Expand Up @@ -16829,87 +16802,27 @@ bool GenTree::DefinesLocal(
// Return Value:
// Whether "this" is a LCL_VAR|FLD_ADDR-equivalent tree.
//
// Notes:
// This function is contractually bound to recognize a superset of trees
// that "LocalAddressVisitor" recognizes, as it is used by "DefinesLocal"
// to detect stores to tracked locals.
//
bool GenTree::DefinesLocalAddr(GenTreeLclVarCommon** pLclVarTree, ssize_t* pOffset)
{
if (OperIs(GT_ADDR, GT_LCL_VAR_ADDR, GT_LCL_FLD_ADDR))
if (OperIs(GT_ADDR) || OperIsLocalAddr())
{
GenTree* addrArg = this;
GenTree* lclNode = this;
if (OperGet() == GT_ADDR)
{
addrArg = AsOp()->gtOp1;
lclNode = AsOp()->gtOp1;
}

if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
if (lclNode->IsLocal() || lclNode->OperIsLocalAddr())
{
GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
*pLclVarTree = addrArgLcl;
*pLclVarTree = lclNode->AsLclVarCommon();

if (pOffset != nullptr)
{
*pOffset += addrArgLcl->GetLclOffs();
*pOffset += lclNode->AsLclVarCommon()->GetLclOffs();
}

return true;
}
else if (addrArg->OperGet() == GT_IND)
{
// A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
return addrArg->AsIndir()->Addr()->DefinesLocalAddr(pLclVarTree, pOffset);
}
}
else if (OperGet() == GT_ADD)
{
if (AsOp()->gtOp1->IsCnsIntOrI())
{
if (pOffset != nullptr)
{
*pOffset += AsOp()->gtOp1->AsIntCon()->IconValue();
}

return AsOp()->gtOp2->DefinesLocalAddr(pLclVarTree, pOffset);
}
else if (AsOp()->gtOp2->IsCnsIntOrI())
{
if (pOffset != nullptr)
{
*pOffset += AsOp()->gtOp2->AsIntCon()->IconValue();
}

return AsOp()->gtOp1->DefinesLocalAddr(pLclVarTree, pOffset);
}
}
// Post rationalization we could have GT_IND(GT_LEA(..)) trees.
else if (OperGet() == GT_LEA)
{
// This method gets invoked during liveness computation and therefore it is critical
// that we don't miss 'use' of any local. The below logic is making the assumption
// that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
// and index is not.
CLANG_FORMAT_COMMENT_ANCHOR;

#ifdef DEBUG
GenTree* index = AsOp()->gtOp2;
if (index != nullptr)
{
assert(!index->DefinesLocalAddr(pLclVarTree, pOffset));
}
#endif // DEBUG

GenTree* base = AsAddrMode()->Base();
if (base != nullptr)
{
if (pOffset != nullptr)
{
*pOffset += AsAddrMode()->Offset();
}

return base->DefinesLocalAddr(pLclVarTree, pOffset);
}
}

// Otherwise...
Expand All @@ -16929,17 +16842,7 @@ const GenTreeLclVarCommon* GenTree::IsLocalAddrExpr() const
{
return this->AsLclVarCommon();
}
else if (OperGet() == GT_ADD)
{
if (AsOp()->gtOp1->OperGet() == GT_CNS_INT)
{
return AsOp()->gtOp2->IsLocalAddrExpr();
}
else if (AsOp()->gtOp2->OperGet() == GT_CNS_INT)
{
return AsOp()->gtOp1->IsLocalAddrExpr();
}
}

// Otherwise...
return nullptr;
}
Expand Down Expand Up @@ -18395,12 +18298,6 @@ bool Compiler::gtIsTypeof(GenTree* tree, CORINFO_CLASS_HANDLE* handle)
// Returns:
// A tree representing the address of a local.
//
// Remarks:
// This function should not be used until after morph when local address
// nodes have been normalized. However, before that IsOptimizingRetBufAsLocal
// can be used to at least check if the call has a retbuf that we are
// optimizing.
//
GenTree* Compiler::gtCallGetDefinedRetBufLclAddr(GenTreeCall* call)
{
if (!call->IsOptimizingRetBufAsLocal())
Expand All @@ -18427,10 +18324,7 @@ GenTree* Compiler::gtCallGetDefinedRetBufLclAddr(GenTreeCall* call)
// This may be called very late to check validity of LIR.
node = node->gtSkipReloadOrCopy();

#ifdef DEBUG
GenTreeLclVarCommon* lcl;
assert(node->DefinesLocalAddr(&lcl) && lvaGetDesc(lcl)->lvHiddenBufferStructArg);
#endif
assert(node->OperIsLocalAddr() && lvaGetDesc(node->AsLclVarCommon())->lvHiddenBufferStructArg);

return node;
}
Expand Down
Loading

0 comments on commit e1081df

Please sign in to comment.