Skip to content

Commit 618a00d

Browse files
committed
Analyze reaching PHI in GetRangeFromAssertions (more branch foldings)
1 parent 24c42f9 commit 618a00d

File tree

4 files changed

+156
-100
lines changed

4 files changed

+156
-100
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 4 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4250,68 +4250,6 @@ GenTree* Compiler::optAssertionProp_RelOp(ASSERT_VALARG_TP assertions,
42504250
return optAssertionPropLocal_RelOp(assertions, tree, stmt);
42514251
}
42524252

4253-
//--------------------------------------------------------------------------------
4254-
// optVisitReachingAssertions: given a vn, call the specified callback function on all
4255-
// the assertions that reach it via PHI definitions if any.
4256-
//
4257-
// Arguments:
4258-
// vn - The vn to visit all the reaching assertions for
4259-
// argVisitor - The callback function to call on the vn and its reaching assertions
4260-
//
4261-
// Return Value:
4262-
// AssertVisit::Aborted - an argVisitor returned AssertVisit::Abort, we stop the walk and return
4263-
// AssertVisit::Continue - all argVisitor returned AssertVisit::Continue
4264-
//
4265-
template <typename TAssertVisitor>
4266-
Compiler::AssertVisit Compiler::optVisitReachingAssertions(ValueNum vn, TAssertVisitor argVisitor)
4267-
{
4268-
VNPhiDef phiDef;
4269-
if (!vnStore->GetPhiDef(vn, &phiDef))
4270-
{
4271-
// We assume that the caller already checked assertions for the current block, so we're
4272-
// interested only in assertions for PHI definitions.
4273-
return AssertVisit::Abort;
4274-
}
4275-
4276-
LclSsaVarDsc* ssaDef = lvaGetDesc(phiDef.LclNum)->GetPerSsaData(phiDef.SsaDef);
4277-
GenTreeLclVarCommon* node = ssaDef->GetDefNode();
4278-
assert(node->IsPhiDefn());
4279-
4280-
// Keep track of the set of phi-preds
4281-
//
4282-
BitVecTraits traits(fgBBNumMax + 1, this);
4283-
BitVec visitedBlocks = BitVecOps::MakeEmpty(&traits);
4284-
4285-
for (GenTreePhi::Use& use : node->Data()->AsPhi()->Uses())
4286-
{
4287-
GenTreePhiArg* phiArg = use.GetNode()->AsPhiArg();
4288-
const ValueNum phiArgVN = vnStore->VNConservativeNormalValue(phiArg->gtVNPair);
4289-
ASSERT_TP assertions = optGetEdgeAssertions(ssaDef->GetBlock(), phiArg->gtPredBB);
4290-
if (argVisitor(phiArgVN, assertions) == AssertVisit::Abort)
4291-
{
4292-
// The visitor wants to abort the walk.
4293-
return AssertVisit::Abort;
4294-
}
4295-
BitVecOps::AddElemD(&traits, visitedBlocks, phiArg->gtPredBB->bbNum);
4296-
}
4297-
4298-
// Verify the set of phi-preds covers the set of block preds
4299-
//
4300-
for (BasicBlock* const pred : ssaDef->GetBlock()->PredBlocks())
4301-
{
4302-
if (!BitVecOps::IsMember(&traits, visitedBlocks, pred->bbNum))
4303-
{
4304-
JITDUMP("... optVisitReachingAssertions in " FMT_BB ": pred " FMT_BB " not a phi-pred\n",
4305-
ssaDef->GetBlock()->bbNum, pred->bbNum);
4306-
4307-
// We missed examining a block pred. Fail the phi inference.
4308-
//
4309-
return AssertVisit::Abort;
4310-
}
4311-
}
4312-
return AssertVisit::Continue;
4313-
}
4314-
43154253
//------------------------------------------------------------------------
43164254
// optAssertionProp: try and optimize a relop via assertion propagation
43174255
//
@@ -4400,7 +4338,7 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
44004338
ValueNum op1VN = vnStore->VNConservativeNormalValue(op1->gtVNPair);
44014339
ValueNum op2VN = vnStore->VNConservativeNormalValue(op2->gtVNPair);
44024340

4403-
// See if we can fold "X relop CNS" using TryGetRangeFromAssertions.
4341+
// IsVNIntegralConstant for op2VN is for reducing the TP regression, can be removed.
44044342
int op2cns;
44054343
if (op1->TypeIs(TYP_INT) && op2->TypeIs(TYP_INT) && vnStore->IsVNIntegralConstant(op2VN, &op2cns))
44064344
{
@@ -4439,11 +4377,12 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
44394377
{
44404378
JITDUMP("Checking PHI [%06u] arguments for non-nullness\n", dspTreeID(op1))
44414379
auto visitor = [this](ValueNum reachingVN, ASSERT_TP reachingAssertions) {
4442-
return optAssertionVNIsNonNull(reachingVN, reachingAssertions) ? AssertVisit::Continue : AssertVisit::Abort;
4380+
return optAssertionVNIsNonNull(reachingVN, reachingAssertions) ? RangeCheck::AssertVisit::Continue
4381+
: RangeCheck::AssertVisit::Abort;
44434382
};
44444383

44454384
ValueNum op1vn = vnStore->VNConservativeNormalValue(op1->gtVNPair);
4446-
if (optVisitReachingAssertions(op1vn, visitor) == AssertVisit::Continue)
4385+
if (RangeCheck::optVisitReachingAssertions(this, op1vn, visitor) == RangeCheck::AssertVisit::Continue)
44474386
{
44484387
JITDUMP("... all of PHI's arguments are never null!\n");
44494388
assert(newTree->OperIs(GT_EQ, GT_NE));

src/coreclr/jit/compiler.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8124,14 +8124,6 @@ class Compiler
81248124
bool optNonNullAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* indir);
81258125
bool optWriteBarrierAssertionProp_StoreInd(ASSERT_VALARG_TP assertions, GenTreeStoreInd* indir);
81268126

8127-
enum class AssertVisit
8128-
{
8129-
Continue,
8130-
Abort,
8131-
};
8132-
template <typename TAssertVisitor>
8133-
AssertVisit optVisitReachingAssertions(ValueNum vn, TAssertVisitor argVisitor);
8134-
81358127
void optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
81368128
GenTree* tree,
81378129
Statement* stmt,

src/coreclr/jit/rangecheck.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -648,9 +648,9 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
648648
// Return Value:
649649
// The computed range
650650
//
651-
Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VALARG_TP assertions)
651+
Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VALARG_TP assertions, int maxDepth)
652652
{
653-
if (num == ValueNumStore::NoVN)
653+
if (num == ValueNumStore::NoVN || maxDepth <= 0)
654654
{
655655
return Range(Limit(Limit::keUnknown));
656656
}
@@ -711,6 +711,17 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
711711
}
712712
break;
713713

714+
case VNF_NEG:
715+
{
716+
Range r1 = GetRangeFromAssertions(comp, funcApp.m_args[0], assertions, maxDepth - 1);
717+
Range unaryOpResult = RangeOps::Negate(r1);
718+
if (unaryOpResult.IsConstantRange())
719+
{
720+
result = unaryOpResult;
721+
}
722+
break;
723+
}
724+
714725
case VNF_LSH:
715726
case VNF_ADD:
716727
case VNF_MUL:
@@ -721,8 +732,8 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
721732
case VNF_UMOD:
722733
{
723734
// Get ranges of both operands and perform the same operation on the ranges.
724-
Range r1 = GetRangeFromAssertions(comp, funcApp.m_args[0], assertions);
725-
Range r2 = GetRangeFromAssertions(comp, funcApp.m_args[1], assertions);
735+
Range r1 = GetRangeFromAssertions(comp, funcApp.m_args[0], assertions, maxDepth - 1);
736+
Range r2 = GetRangeFromAssertions(comp, funcApp.m_args[1], assertions, maxDepth - 1);
726737
Range binOpResult = Range(Limit(Limit::keUnknown));
727738
switch (funcApp.m_func)
728739
{
@@ -796,6 +807,19 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
796807
}
797808
}
798809

810+
Range phiRange = Range(Limit(Limit::keUndef));
811+
812+
if ((maxDepth > 1) &&
813+
optVisitReachingAssertions(comp, num,
814+
[comp, &phiRange, maxDepth](ValueNum reachingVN, ASSERT_TP reachingAssertions) {
815+
Range edgeRange = GetRangeFromAssertions(comp, reachingVN, reachingAssertions, maxDepth - 1);
816+
phiRange = phiRange.LowerLimit().IsUndef() ? edgeRange : RangeOps::Union(phiRange, edgeRange);
817+
return edgeRange.IsConstantRange() && !edgeRange.IsFullRange() ? AssertVisit::Continue : AssertVisit::Abort;
818+
}) == AssertVisit::Continue)
819+
{
820+
result = phiRange;
821+
}
822+
799823
MergeEdgeAssertions(comp, num, ValueNumStore::NoVN, assertions, &result, false);
800824
assert(result.IsConstantRange());
801825
return result;

0 commit comments

Comments
 (0)