Skip to content
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
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7362,7 +7362,7 @@ class Compiler
LclNumToLiveDefsMap* curSsaName);
void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap* curSsaName);
bool optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaName);
void optCopyPropPushDef(GenTree* defNode, GenTreeLclVarCommon* lclNode, LclNumToLiveDefsMap* curSsaName);
void optCopyPropPushDef(GenTreeLclVarCommon* lclNode, LclNumToLiveDefsMap* curSsaName);
int optCopyProp_LclVarScore(const LclVarDsc* lclVarDsc, const LclVarDsc* copyVarDsc, bool preferOp2);
PhaseStatus optVnCopyProp();
INDEBUG(void optDumpCopyPropStack(LclNumToLiveDefsMap* curSsaName));
Expand Down
99 changes: 99 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4703,6 +4703,105 @@ GenTree::VisitResult GenTree::VisitOperands(TVisitor visitor)
}
}

//------------------------------------------------------------------------
// VisitLocalDefs: Visit locals being defined by this node.
//
// Arguments:
// comp - the compiler instance
// visitor - Functor of type GenTree::VisitResult(LocalDef)
//
// Return Value:
// VisitResult::Abort if the functor aborted; otherwise VisitResult::Continue.
//
// Notes:
// This function is contractually bound to recognize a superset of stores
// that "LocalAddressVisitor" recognizes and transforms, as it is used to
// detect which trees can define tracked locals.
//
template <typename TVisitor>
GenTree::VisitResult GenTree::VisitLocalDefs(Compiler* comp, TVisitor visitor)
{
if (OperIs(GT_STORE_LCL_VAR))
{
unsigned size = comp->lvaLclExactSize(AsLclVarCommon()->GetLclNum());
return visitor(LocalDef(AsLclVarCommon(), /* isEntire */ true, 0, size));
}
if (OperIs(GT_STORE_LCL_FLD))
{
GenTreeLclFld* fld = AsLclFld();
return visitor(LocalDef(fld, !fld->IsPartialLclFld(comp), fld->GetLclOffs(), fld->GetSize()));
}
if (OperIs(GT_CALL))
{
GenTreeLclVarCommon* lclAddr = comp->gtCallGetDefinedRetBufLclAddr(AsCall());
if (lclAddr != nullptr)
{
unsigned storeSize = comp->typGetObjLayout(AsCall()->gtRetClsHnd)->GetSize();

bool isEntire = storeSize == comp->lvaLclExactSize(lclAddr->GetLclNum());

return visitor(LocalDef(lclAddr, isEntire, lclAddr->GetLclOffs(), storeSize));
}
}

return VisitResult::Continue;
}

//------------------------------------------------------------------------
// VisitLocalDefNodes: Visit GenTreeLclVarCommon nodes representing definitions in the specified node.
//
// Arguments:
// comp - the compiler instance
// visitor - Functor of type GenTree::VisitResult(GenTreeLclVarCommon*)
//
// Return Value:
// VisitResult::Abort if the functor aborted; otherwise VisitResult::Continue.
//
// Notes:
// This function is contractually bound to recognize a superset of stores
// that "LocalAddressVisitor" recognizes and transforms, as it is used to
// detect which trees can define tracked locals.
//
template <typename TVisitor>
GenTree::VisitResult GenTree::VisitLocalDefNodes(Compiler* comp, TVisitor visitor)
{
if (OperIs(GT_STORE_LCL_VAR))
{
return visitor(AsLclVarCommon());
}
if (OperIs(GT_STORE_LCL_FLD))
{
return visitor(AsLclFld());
}
if (OperIs(GT_CALL))
{
GenTreeLclVarCommon* lclAddr = comp->gtCallGetDefinedRetBufLclAddr(AsCall());
if (lclAddr != nullptr)
{
return visitor(lclAddr);
}
}

return VisitResult::Continue;
}

//------------------------------------------------------------------------
// HasAnyLocalDefs:
// Check if a tree is considered as defining any locals.
//
// Arguments:
// comp - the compiler instance
//
// Return Value:
// True if it is.
//
inline bool GenTree::HasAnyLocalDefs(Compiler* comp)
{
return VisitLocalDefNodes(comp, [](GenTreeLclVarCommon* lcl) {
return GenTree::VisitResult::Abort;
}) == GenTree::VisitResult::Abort;
}

/*****************************************************************************
* operator new
*
Expand Down
36 changes: 23 additions & 13 deletions src/coreclr/jit/copyprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,31 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap*
{
for (GenTree* const tree : stmt->TreeList())
{
GenTreeLclVarCommon* lclDefNode = nullptr;
if (tree->OperIsSsaDef() && tree->DefinesLocal(this, &lclDefNode))
if (!tree->OperIsSsaDef())
{
if (lclDefNode->HasCompositeSsaName())
continue;
}

auto visitDef = [=](GenTreeLclVarCommon* lcl) {
if (lcl->HasCompositeSsaName())
{
LclVarDsc* varDsc = lvaGetDesc(lclDefNode);
LclVarDsc* varDsc = lvaGetDesc(lcl);
assert(varDsc->lvPromoted);

for (unsigned index = 0; index < varDsc->lvFieldCnt; index++)
{
popDef(varDsc->lvFieldLclStart + index, lclDefNode->GetSsaNum(this, index));
popDef(varDsc->lvFieldLclStart + index, lcl->GetSsaNum(this, index));
}
}
else
{
popDef(lclDefNode->GetLclNum(), lclDefNode->GetSsaNum());
popDef(lcl->GetLclNum(), lcl->GetSsaNum());
}
}

return GenTree::VisitResult::Continue;
};

tree->VisitLocalDefNodes(this, visitDef);
}
}
}
Expand Down Expand Up @@ -304,11 +311,10 @@ bool Compiler::optCopyProp(
// optCopyPropPushDef: Push the new live SSA def on the stack for "lclNode".
//
// Arguments:
// defNode - The definition node for this def (store/GT_CALL) (will be "nullptr" for "use" defs)
// lclNode - The local tree representing "the def"
// curSsaName - The map of local numbers to stacks of their defs
//
void Compiler::optCopyPropPushDef(GenTree* defNode, GenTreeLclVarCommon* lclNode, LclNumToLiveDefsMap* curSsaName)
void Compiler::optCopyPropPushDef(GenTreeLclVarCommon* lclNode, LclNumToLiveDefsMap* curSsaName)
{
unsigned lclNum = lclNode->GetLclNum();

Expand Down Expand Up @@ -400,10 +406,14 @@ bool Compiler::optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaNa
{
treeLifeUpdater.UpdateLife(tree);

GenTreeLclVarCommon* lclDefNode = nullptr;
if (tree->OperIsSsaDef() && tree->DefinesLocal(this, &lclDefNode))
if (tree->OperIsSsaDef())
{
optCopyPropPushDef(tree, lclDefNode, curSsaName);
auto visitDef = [=](GenTreeLclVarCommon* lcl) {
optCopyPropPushDef(lcl, curSsaName);
return GenTree::VisitResult::Continue;
};

tree->VisitLocalDefNodes(this, visitDef);
}
else if (tree->OperIs(GT_LCL_VAR, GT_LCL_FLD) && tree->AsLclVarCommon()->HasSsaName())
{
Expand All @@ -413,7 +423,7 @@ bool Compiler::optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaNa
// live definition. Since they are always live, we'll do it only once.
if ((lvaGetDesc(lclNum)->lvIsParam || (lclNum == info.compThisArg)) && !curSsaName->Lookup(lclNum))
{
optCopyPropPushDef(nullptr, tree->AsLclVarCommon(), curSsaName);
optCopyPropPushDef(tree->AsLclVarCommon(), curSsaName);
}

// TODO-Review: EH successor/predecessor iteration seems broken.
Expand Down
83 changes: 40 additions & 43 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4326,61 +4326,58 @@ class SsaCheckVisitor : public GenTreeVisitor<SsaCheckVisitor>

void ProcessDefs(GenTree* tree)
{
GenTreeLclVarCommon* lclNode;
bool isFullDef = false;
ssize_t offset = 0;
unsigned storeSize = 0;
bool definesLocal = tree->DefinesLocal(m_compiler, &lclNode, &isFullDef, &offset, &storeSize);

if (!definesLocal)
{
return;
}

const bool isUse = (lclNode->gtFlags & GTF_VAR_USEASG) != 0;
unsigned const lclNum = lclNode->GetLclNum();
LclVarDsc* const varDsc = m_compiler->lvaGetDesc(lclNum);
auto visitDef = [=](const LocalDef& def) {
const bool isUse = (def.Def->gtFlags & GTF_VAR_USEASG) != 0;
unsigned const lclNum = def.Def->GetLclNum();
LclVarDsc* const varDsc = m_compiler->lvaGetDesc(lclNum);

assert(!(isFullDef && isUse));
assert(!(def.IsEntire && isUse));

if (lclNode->HasCompositeSsaName())
{
for (unsigned index = 0; index < varDsc->lvFieldCnt; index++)
if (def.Def->HasCompositeSsaName())
{
unsigned const fieldLclNum = varDsc->lvFieldLclStart + index;
LclVarDsc* const fieldVarDsc = m_compiler->lvaGetDesc(fieldLclNum);
unsigned const fieldSsaNum = lclNode->GetSsaNum(m_compiler, index);

ssize_t fieldStoreOffset;
unsigned fieldStoreSize;
if (m_compiler->gtStoreDefinesField(fieldVarDsc, offset, storeSize, &fieldStoreOffset, &fieldStoreSize))
for (unsigned index = 0; index < varDsc->lvFieldCnt; index++)
{
ProcessDef(lclNode, fieldLclNum, fieldSsaNum);

if (!ValueNumStore::LoadStoreIsEntire(genTypeSize(fieldVarDsc), fieldStoreOffset, fieldStoreSize))
unsigned const fieldLclNum = varDsc->lvFieldLclStart + index;
LclVarDsc* const fieldVarDsc = m_compiler->lvaGetDesc(fieldLclNum);
unsigned const fieldSsaNum = def.Def->GetSsaNum(m_compiler, index);

ssize_t fieldStoreOffset;
unsigned fieldStoreSize;
if (m_compiler->gtStoreDefinesField(fieldVarDsc, def.Offset, def.Size, &fieldStoreOffset,
&fieldStoreSize))
{
assert(isUse);
unsigned const fieldUseSsaNum = fieldVarDsc->GetPerSsaData(fieldSsaNum)->GetUseDefSsaNum();
ProcessUse(lclNode, fieldLclNum, fieldUseSsaNum);
ProcessDef(def.Def, fieldLclNum, fieldSsaNum);

if (!ValueNumStore::LoadStoreIsEntire(genTypeSize(fieldVarDsc), fieldStoreOffset,
fieldStoreSize))
{
assert(isUse);
unsigned const fieldUseSsaNum = fieldVarDsc->GetPerSsaData(fieldSsaNum)->GetUseDefSsaNum();
ProcessUse(def.Def, fieldLclNum, fieldUseSsaNum);
}
}
}
}
}
else
{
unsigned const ssaNum = lclNode->GetSsaNum();
ProcessDef(lclNode, lclNum, ssaNum);

if (isUse)
else
{
unsigned useSsaNum = SsaConfig::RESERVED_SSA_NUM;
if (ssaNum != SsaConfig::RESERVED_SSA_NUM)
unsigned const ssaNum = def.Def->GetSsaNum();
ProcessDef(def.Def, lclNum, ssaNum);

if (isUse)
{
useSsaNum = varDsc->GetPerSsaData(ssaNum)->GetUseDefSsaNum();
unsigned useSsaNum = SsaConfig::RESERVED_SSA_NUM;
if (ssaNum != SsaConfig::RESERVED_SSA_NUM)
{
useSsaNum = varDsc->GetPerSsaData(ssaNum)->GetUseDefSsaNum();
}
ProcessUse(def.Def, lclNum, useSsaNum);
}
ProcessUse(lclNode, lclNum, useSsaNum);
}
}

return GenTree::VisitResult::Continue;
};

tree->VisitLocalDefs(m_compiler, visitDef);
}

void ProcessUse(GenTreeLclVarCommon* tree, unsigned lclNum, unsigned ssaNum)
Expand Down
10 changes: 6 additions & 4 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5391,11 +5391,13 @@ bool FlowGraphNaturalLoop::VisitDefs(TFunc func)
return Compiler::WALK_SKIP_SUBTREES;
}

GenTreeLclVarCommon* lclDef;
if (tree->DefinesLocal(m_compiler, &lclDef))
auto visitDef = [=](GenTreeLclVarCommon* lcl) {
return m_func(lcl) ? GenTree::VisitResult::Continue : GenTree::VisitResult::Abort;
};

if (tree->VisitLocalDefNodes(m_compiler, visitDef) == GenTree::VisitResult::Abort)
{
if (!m_func(lclDef))
return Compiler::WALK_ABORT;
return Compiler::WALK_ABORT;
}

return Compiler::WALK_CONTINUE;
Expand Down
Loading
Loading