Skip to content

Commit 50b426b

Browse files
authored
JIT: extend copy prop to local fields (#74384)
Allow copy prop to update GT_LCL_FLD nodes. Update local assertion gen for block opts to use a mid-morph (after child nodes are morphed) tree to generate copy or zero assertions, since the semantics of the post-morph tree are often obscured by the copy/zero expansions.
1 parent 0ce9c8c commit 50b426b

4 files changed

Lines changed: 235 additions & 58 deletions

File tree

src/coreclr/jit/assertionprop.cpp

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1636,8 +1636,35 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
16361636
//
16371637
// Copy Assertions
16381638
//
1639+
case GT_OBJ:
1640+
case GT_BLK:
1641+
{
1642+
// TODO-ADDR: delete once local morph folds SIMD-typed indirections.
1643+
//
1644+
GenTree* const addr = op2->AsIndir()->Addr();
1645+
1646+
if (addr->OperIs(GT_ADDR))
1647+
{
1648+
GenTree* const base = addr->AsOp()->gtOp1;
1649+
1650+
if (base->OperIs(GT_LCL_VAR) && varTypeIsStruct(base))
1651+
{
1652+
ClassLayout* const varLayout = base->GetLayout(this);
1653+
ClassLayout* const objLayout = op2->GetLayout(this);
1654+
if (ClassLayout::AreCompatible(varLayout, objLayout))
1655+
{
1656+
op2 = base;
1657+
goto IS_COPY;
1658+
}
1659+
}
1660+
}
1661+
1662+
goto DONE_ASSERTION;
1663+
}
1664+
16391665
case GT_LCL_VAR:
16401666
{
1667+
IS_COPY:
16411668
//
16421669
// Must either be an OAK_EQUAL or an OAK_NOT_EQUAL assertion
16431670
//
@@ -3416,7 +3443,14 @@ bool Compiler::optZeroObjAssertionProp(GenTree* tree, ASSERT_VALARG_TP assertion
34163443
return false;
34173444
}
34183445

3419-
unsigned lclNum = tree->AsLclVar()->GetLclNum();
3446+
// No ZEROOBJ assertions for simd.
3447+
//
3448+
if (varTypeIsSIMD(tree))
3449+
{
3450+
return false;
3451+
}
3452+
3453+
const unsigned lclNum = tree->AsLclVar()->GetLclNum();
34203454
AssertionIndex assertionIndex = optLocalAssertionIsEqualOrNotEqual(O1K_LCLVAR, lclNum, O2K_ZEROOBJ, 0, assertions);
34213455
if (assertionIndex == NO_ASSERTION_INDEX)
34223456
{
@@ -3568,6 +3602,20 @@ GenTree* Compiler::optCopyAssertionProp(AssertionDsc* curAssertion,
35683602
return nullptr;
35693603
}
35703604

3605+
// Heuristic: for LclFld prop, don't force the copy or its promoted fields to be in memory.
3606+
//
3607+
if (tree->OperIs(GT_LCL_FLD))
3608+
{
3609+
if (copyVarDsc->IsEnregisterableLcl() || copyVarDsc->lvPromotedStruct())
3610+
{
3611+
return nullptr;
3612+
}
3613+
else
3614+
{
3615+
lvaSetVarDoNotEnregister(copyLclNum DEBUGARG(DoNotEnregisterReason::LocalField));
3616+
}
3617+
}
3618+
35713619
tree->SetLclNum(copyLclNum);
35723620
tree->SetSsaNum(copySsaNum);
35733621

@@ -3689,6 +3737,71 @@ GenTree* Compiler::optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTreeL
36893737
return nullptr;
36903738
}
36913739

3740+
//------------------------------------------------------------------------
3741+
// optAssertionProp_LclFld: try and optimize a local field use via assertions
3742+
//
3743+
// Arguments:
3744+
// assertions - set of live assertions
3745+
// tree - local field use to optimize
3746+
// stmt - statement containing the tree
3747+
//
3748+
// Returns:
3749+
// Updated tree, or nullptr
3750+
//
3751+
// Notes:
3752+
// stmt may be nullptr during local assertion prop
3753+
//
3754+
GenTree* Compiler::optAssertionProp_LclFld(ASSERT_VALARG_TP assertions, GenTreeLclVarCommon* tree, Statement* stmt)
3755+
{
3756+
// If we have a var definition then bail or
3757+
// If this is the address of the var then it will have the GTF_DONT_CSE
3758+
// flag set and we don't want to to assertion prop on it.
3759+
if (tree->gtFlags & (GTF_VAR_DEF | GTF_DONT_CSE))
3760+
{
3761+
return nullptr;
3762+
}
3763+
3764+
// Only run during local prop and if copies are available.
3765+
//
3766+
if (!optLocalAssertionProp || !optCanPropLclVar)
3767+
{
3768+
return nullptr;
3769+
}
3770+
3771+
BitVecOps::Iter iter(apTraits, assertions);
3772+
unsigned index = 0;
3773+
while (iter.NextElem(&index))
3774+
{
3775+
AssertionIndex assertionIndex = GetAssertionIndex(index);
3776+
if (assertionIndex > optAssertionCount)
3777+
{
3778+
break;
3779+
}
3780+
3781+
// See if the variable is equal to another variable.
3782+
AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
3783+
if (!curAssertion->CanPropLclVar())
3784+
{
3785+
continue;
3786+
}
3787+
3788+
// Copy prop.
3789+
if (curAssertion->op2.kind == O2K_LCLVAR_COPY)
3790+
{
3791+
// Perform copy assertion prop.
3792+
GenTree* newTree = optCopyAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));
3793+
if (newTree != nullptr)
3794+
{
3795+
return newTree;
3796+
}
3797+
}
3798+
3799+
continue;
3800+
}
3801+
3802+
return nullptr;
3803+
}
3804+
36923805
//------------------------------------------------------------------------
36933806
// optAssertionProp_Asg: Try and optimize an assignment via assertions.
36943807
//
@@ -4916,6 +5029,9 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
49165029
case GT_LCL_VAR:
49175030
return optAssertionProp_LclVar(assertions, tree->AsLclVarCommon(), stmt);
49185031

5032+
case GT_LCL_FLD:
5033+
return optAssertionProp_LclFld(assertions, tree->AsLclVarCommon(), stmt);
5034+
49195035
case GT_ASG:
49205036
return optAssertionProp_Asg(assertions, tree->AsOp(), stmt);
49215037

src/coreclr/jit/compiler.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5767,7 +5767,7 @@ class Compiler
57675767
GenTree* fgMorphCopyBlock(GenTree* tree);
57685768
GenTree* fgMorphStoreDynBlock(GenTreeStoreDynBlk* tree);
57695769
GenTree* fgMorphForRegisterFP(GenTree* tree);
5770-
GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
5770+
GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optAssertionPropDone = nullptr);
57715771
GenTree* fgOptimizeCast(GenTreeCast* cast);
57725772
GenTree* fgOptimizeCastOnAssignment(GenTreeOp* asg);
57735773
GenTree* fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp);
@@ -5786,7 +5786,7 @@ class Compiler
57865786
GenTree* fgMorphRetInd(GenTreeUnOp* tree);
57875787
GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
57885788
GenTree* fgMorphUModToAndSub(GenTreeOp* tree);
5789-
GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
5789+
GenTree* fgMorphSmpOpOptional(GenTreeOp* tree, bool* optAssertionPropDone);
57905790
GenTree* fgMorphMultiOp(GenTreeMultiOp* multiOp);
57915791
GenTree* fgMorphConst(GenTree* tree);
57925792

@@ -5802,7 +5802,8 @@ class Compiler
58025802
private:
58035803
void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* tree));
58045804
void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree));
5805-
void fgMorphTreeDone(GenTree* tree, GenTree* oldTree = nullptr DEBUGARG(int morphNum = 0));
5805+
void fgMorphTreeDone(GenTree* tree);
5806+
void fgMorphTreeDone(GenTree* tree, bool optAssertionPropDone, bool isMorphedTree DEBUGARG(int morphNum = 0));
58065807

58075808
Statement* fgMorphStmt;
58085809

@@ -7368,6 +7369,7 @@ class Compiler
73687369
// Assertion propagation functions.
73697370
GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt, BasicBlock* block);
73707371
GenTree* optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTreeLclVarCommon* tree, Statement* stmt);
7372+
GenTree* optAssertionProp_LclFld(ASSERT_VALARG_TP assertions, GenTreeLclVarCommon* tree, Statement* stmt);
73717373
GenTree* optAssertionProp_Asg(ASSERT_VALARG_TP assertions, GenTreeOp* asg, Statement* stmt);
73727374
GenTree* optAssertionProp_Return(ASSERT_VALARG_TP assertions, GenTreeUnOp* ret, Statement* stmt);
73737375
GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt);

0 commit comments

Comments
 (0)