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
30 changes: 30 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4461,6 +4461,36 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
return optAssertionProp_Update(newTree, tree, stmt);
}
}

// If op1VN is actually ADD(X, CNS), we can try peeling the constant offset and adjusting op2Cns accordingly.
// It's a bit more complicated for unsigned comparisons, so only do it for signed ones for now.
//
if (!tree->IsUnsigned())
{
ValueNum peeledOp1VN = op1VN;
int peeledOffset = 0;
vnStore->PeelOffsetsI32(&peeledOp1VN, &peeledOffset);

if (peeledOffset != 0)
{
Range peeledOffsetRng = Range(Limit(Limit::keConstant, peeledOffset));
Range peeledOp1Rng = Range(Limit(Limit::keUnknown));
if (RangeCheck::TryGetRangeFromAssertions(this, peeledOp1VN, assertions, &peeledOp1Rng))
{
// Subtract handles overflow internally.
rng2 = RangeOps::Subtract(rng2, peeledOffsetRng);

RangeOps::RelationKind kind =
RangeOps::EvalRelop(tree->OperGet(), tree->IsUnsigned(), peeledOp1Rng, 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);
}
}
}
}
}

// Else check if we have an equality check involving a local or an indir
Expand Down
96 changes: 48 additions & 48 deletions src/coreclr/jit/rangecheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,25 @@ struct RangeOps
return Limit(Limit::keUnknown);
}

// Perform 'value' - 'cns'
static Limit SubtractConstantLimit(const Limit& value, const Limit& cns)
{
assert(cns.IsConstant());

if (cns.GetConstant() == INT_MIN)
{
// Subtracting INT_MIN would overflow
return Limit(Limit::keUnknown);
}

Limit l = value;
if (l.AddConstant(-cns.GetConstant()))
{
return l;
}
return Limit(Limit::keUnknown);
}

// Perform 'value' * 'cns'
static Limit MultiplyConstantLimit(const Limit& value, const Limit& cns)
{
Expand All @@ -352,9 +371,9 @@ struct RangeOps
return Limit(Limit::keUnknown);
}

// Given two ranges "r1" and "r2", perform an add operation on the
// ranges.
static Range Add(Range& r1, Range& r2)
// Given two ranges "r1" and "r2", perform a generic 'op' operation on the ranges.
template <typename Operation>
static Range ApplyRangeOp(Range& r1, Range& r2, Operation op)
{
Limit& r1lo = r1.LowerLimit();
Limit& r1hi = r1.UpperLimit();
Expand All @@ -376,23 +395,45 @@ struct RangeOps

if (r1lo.IsConstant())
{
result.lLimit = AddConstantLimit(r2lo, r1lo);
result.lLimit = op(r2lo, r1lo);
}
if (r2lo.IsConstant())
{
result.lLimit = AddConstantLimit(r1lo, r2lo);
result.lLimit = op(r1lo, r2lo);
}
if (r1hi.IsConstant())
{
result.uLimit = AddConstantLimit(r2hi, r1hi);
result.uLimit = op(r2hi, r1hi);
}
if (r2hi.IsConstant())
{
result.uLimit = AddConstantLimit(r1hi, r2hi);
result.uLimit = op(r1hi, r2hi);
}

return result;
}

static Range Add(Range& r1, Range& r2)
{
return ApplyRangeOp(r1, r2, [](Limit& a, Limit& b) {
return AddConstantLimit(a, b);
});
}

static Range Subtract(Range& r1, Range& r2)
{
return ApplyRangeOp(r1, r2, [](Limit& a, Limit& b) {
return SubtractConstantLimit(a, b);
});
}

static Range Multiply(Range& r1, Range& r2)
{
return ApplyRangeOp(r1, r2, [](Limit& a, Limit& b) {
return MultiplyConstantLimit(a, b);
});
}

static Range ShiftRight(Range& r1, Range& r2)
{
Limit& r1lo = r1.LowerLimit();
Expand Down Expand Up @@ -430,47 +471,6 @@ struct RangeOps
return result;
}

// Given two ranges "r1" and "r2", perform an multiply operation on the
// ranges.
static Range Multiply(Range& r1, Range& r2)
{
Limit& r1lo = r1.LowerLimit();
Limit& r1hi = r1.UpperLimit();
Limit& r2lo = r2.LowerLimit();
Limit& r2hi = r2.UpperLimit();

Range result = Limit(Limit::keUnknown);

// Check lo ranges if they are dependent and not unknown.
if ((r1lo.IsDependent() && !r1lo.IsUnknown()) || (r2lo.IsDependent() && !r2lo.IsUnknown()))
{
result.lLimit = Limit(Limit::keDependent);
}
// Check hi ranges if they are dependent and not unknown.
if ((r1hi.IsDependent() && !r1hi.IsUnknown()) || (r2hi.IsDependent() && !r2hi.IsUnknown()))
{
result.uLimit = Limit(Limit::keDependent);
}

if (r1lo.IsConstant())
{
result.lLimit = MultiplyConstantLimit(r2lo, r1lo);
}
if (r2lo.IsConstant())
{
result.lLimit = MultiplyConstantLimit(r1lo, r2lo);
}
if (r1hi.IsConstant())
{
result.uLimit = MultiplyConstantLimit(r2hi, r1hi);
}
if (r2hi.IsConstant())
{
result.uLimit = MultiplyConstantLimit(r1hi, r2hi);
}
return result;
}

// Given two ranges "r1" and "r2", do a Phi merge. If "monIncreasing" is true,
// then ignore the dependent variables for the lower bound but not for the upper bound.
static Range Merge(const Range& r1, const Range& r2, bool monIncreasing)
Expand Down
Loading