Skip to content
Draft
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
109 changes: 18 additions & 91 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3970,19 +3970,14 @@ void Compiler::optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
// Let's see if MergeEdgeAssertions can help us:
if (tree->TypeIs(TYP_INT))
{
Range rng = Range(Limit(Limit::keUnknown));
if (RangeCheck::TryGetRangeFromAssertions(this, treeVN, assertions, &rng))
Range rng = RangeCheck::GetRangeFromAssertions(this, treeVN, assertions);
if (rng.LowerLimit().GetConstant() >= 0)
{
Limit lowerBound = rng.LowerLimit();
assert(lowerBound.IsConstant());
if (lowerBound.GetConstant() >= 0)
{
*isKnownNonNegative = true;
}
if (lowerBound.GetConstant() > 0)
{
*isKnownNonZero = true;
}
*isKnownNonNegative = true;
}
if (rng.LowerLimit().GetConstant() > 0)
{
*isKnownNonZero = true;
}
}
}
Expand Down Expand Up @@ -4250,68 +4245,6 @@ GenTree* Compiler::optAssertionProp_RelOp(ASSERT_VALARG_TP assertions,
return optAssertionPropLocal_RelOp(assertions, tree, stmt);
}

//--------------------------------------------------------------------------------
// optVisitReachingAssertions: given a vn, call the specified callback function on all
// the assertions that reach it via PHI definitions if any.
//
// Arguments:
// vn - The vn to visit all the reaching assertions for
// argVisitor - The callback function to call on the vn and its reaching assertions
//
// Return Value:
// AssertVisit::Aborted - an argVisitor returned AssertVisit::Abort, we stop the walk and return
// AssertVisit::Continue - all argVisitor returned AssertVisit::Continue
//
template <typename TAssertVisitor>
Compiler::AssertVisit Compiler::optVisitReachingAssertions(ValueNum vn, TAssertVisitor argVisitor)
{
VNPhiDef phiDef;
if (!vnStore->GetPhiDef(vn, &phiDef))
{
// We assume that the caller already checked assertions for the current block, so we're
// interested only in assertions for PHI definitions.
return AssertVisit::Abort;
}

LclSsaVarDsc* ssaDef = lvaGetDesc(phiDef.LclNum)->GetPerSsaData(phiDef.SsaDef);
GenTreeLclVarCommon* node = ssaDef->GetDefNode();
assert(node->IsPhiDefn());

// Keep track of the set of phi-preds
//
BitVecTraits traits(fgBBNumMax + 1, this);
BitVec visitedBlocks = BitVecOps::MakeEmpty(&traits);

for (GenTreePhi::Use& use : node->Data()->AsPhi()->Uses())
{
GenTreePhiArg* phiArg = use.GetNode()->AsPhiArg();
const ValueNum phiArgVN = vnStore->VNConservativeNormalValue(phiArg->gtVNPair);
ASSERT_TP assertions = optGetEdgeAssertions(ssaDef->GetBlock(), phiArg->gtPredBB);
if (argVisitor(phiArgVN, assertions) == AssertVisit::Abort)
{
// The visitor wants to abort the walk.
return AssertVisit::Abort;
}
BitVecOps::AddElemD(&traits, visitedBlocks, phiArg->gtPredBB->bbNum);
}

// Verify the set of phi-preds covers the set of block preds
//
for (BasicBlock* const pred : ssaDef->GetBlock()->PredBlocks())
{
if (!BitVecOps::IsMember(&traits, visitedBlocks, pred->bbNum))
{
JITDUMP("... optVisitReachingAssertions in " FMT_BB ": pred " FMT_BB " not a phi-pred\n",
ssaDef->GetBlock()->bbNum, pred->bbNum);

// We missed examining a block pred. Fail the phi inference.
//
return AssertVisit::Abort;
}
}
return AssertVisit::Continue;
}

//------------------------------------------------------------------------
// optAssertionProp: try and optimize a relop via assertion propagation
//
Expand Down Expand Up @@ -4400,23 +4333,17 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
ValueNum op1VN = vnStore->VNConservativeNormalValue(op1->gtVNPair);
ValueNum op2VN = vnStore->VNConservativeNormalValue(op2->gtVNPair);

// See if we can fold "X relop CNS" using TryGetRangeFromAssertions.
int op2cns;
if (op1->TypeIs(TYP_INT) && op2->TypeIs(TYP_INT) && vnStore->IsVNIntegralConstant(op2VN, &op2cns))
if (op1->TypeIs(TYP_INT) && op2->TypeIs(TYP_INT))
{
// NOTE: we can call TryGetRangeFromAssertions for op2 as well if we want, but it's not cheap.
Range rng1 = Range(Limit(Limit::keUnknown));
Range rng2 = Range(Limit(Limit::keConstant, op2cns));
Range rng1 = RangeCheck::GetRangeFromAssertions(this, op1VN, assertions);
Range rng2 = RangeCheck::GetRangeFromAssertions(this, op2VN, assertions);

if (RangeCheck::TryGetRangeFromAssertions(this, op1VN, assertions, &rng1))
RangeOps::RelationKind kind = RangeOps::EvalRelop(tree->OperGet(), tree->IsUnsigned(), rng1, rng2);
if ((kind != RangeOps::RelationKind::Unknown))
{
RangeOps::RelationKind kind = RangeOps::EvalRelop(tree->OperGet(), tree->IsUnsigned(), rng1, rng2);
if ((kind != RangeOps::RelationKind::Unknown))
{
newTree = kind == RangeOps::RelationKind::AlwaysTrue ? gtNewTrue() : gtNewFalse();
newTree = gtWrapWithSideEffects(newTree, tree, GTF_ALL_EFFECT);
return optAssertionProp_Update(newTree, tree, stmt);
}
newTree = kind == RangeOps::RelationKind::AlwaysTrue ? gtNewTrue() : gtNewFalse();
newTree = gtWrapWithSideEffects(newTree, tree, GTF_ALL_EFFECT);
return optAssertionProp_Update(newTree, tree, stmt);
}
}

Expand Down Expand Up @@ -5346,10 +5273,10 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
std::swap(funcApp.m_args[0], funcApp.m_args[1]);
}

Range rng = Range(Limit(Limit::keUnknown));
if ((funcApp.m_args[0] == vnCurLen) && vnStore->IsVNInt32Constant(funcApp.m_args[1]) &&
RangeCheck::TryGetRangeFromAssertions(this, vnCurLen, assertions, &rng) && rng.LowerLimit().IsConstant())
Range(Limit(Limit::keUnknown));
if ((funcApp.m_args[0] == vnCurLen) && vnStore->IsVNInt32Constant(funcApp.m_args[1]))
{
Range rng = RangeCheck::GetRangeFromAssertions(this, vnCurLen, assertions);
// Lower known limit of ArrLen:
const int lenLowerLimit = rng.LowerLimit().GetConstant();

Expand Down
62 changes: 61 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8129,8 +8129,68 @@ class Compiler
Continue,
Abort,
};

//--------------------------------------------------------------------------------
// optVisitReachingAssertions: given a vn, call the specified callback function on all
// the assertions that reach it via PHI definitions if any.
//
// Arguments:
// vn - The vn to visit all the reaching assertions for
// argVisitor - The callback function to call on the vn and its reaching assertions
//
// Return Value:
// AssertVisit::Aborted - an argVisitor returned AssertVisit::Abort, we stop the walk and return
// AssertVisit::Continue - all argVisitor returned AssertVisit::Continue
//
template <typename TAssertVisitor>
AssertVisit optVisitReachingAssertions(ValueNum vn, TAssertVisitor argVisitor);
AssertVisit optVisitReachingAssertions(ValueNum vn, TAssertVisitor argVisitor)
{
VNPhiDef phiDef;
if (!vnStore->GetPhiDef(vn, &phiDef))
{
// We assume that the caller already checked assertions for the current block, so we're
// interested only in assertions for PHI definitions.
return AssertVisit::Abort;
}

LclSsaVarDsc* ssaDef = lvaGetDesc(phiDef.LclNum)->GetPerSsaData(phiDef.SsaDef);
GenTreeLclVarCommon* node = ssaDef->GetDefNode();
assert(node->IsPhiDefn());

// Keep track of the set of phi-preds
//
BitVecTraits traits(fgBBNumMax + 1, this);
BitVec visitedBlocks = BitVecOps::MakeEmpty(&traits);

for (GenTreePhi::Use& use : node->Data()->AsPhi()->Uses())
{
GenTreePhiArg* phiArg = use.GetNode()->AsPhiArg();
const ValueNum phiArgVN = vnStore->VNConservativeNormalValue(phiArg->gtVNPair);
ASSERT_TP assertions = optGetEdgeAssertions(ssaDef->GetBlock(), phiArg->gtPredBB);
if (argVisitor(phiArgVN, assertions) == AssertVisit::Abort)
{
// The visitor wants to abort the walk.
return AssertVisit::Abort;
}
BitVecOps::AddElemD(&traits, visitedBlocks, phiArg->gtPredBB->bbNum);
}

// Verify the set of phi-preds covers the set of block preds
//
for (BasicBlock* const pred : ssaDef->GetBlock()->PredBlocks())
{
if (!BitVecOps::IsMember(&traits, visitedBlocks, pred->bbNum))
{
JITDUMP("... optVisitReachingAssertions in " FMT_BB ": pred " FMT_BB " not a phi-pred\n",
ssaDef->GetBlock()->bbNum, pred->bbNum);

// We missed examining a block pred. Fail the phi inference.
//
return AssertVisit::Abort;
}
}
return AssertVisit::Continue;
}

void optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
GenTree* tree,
Expand Down
Loading
Loading