Skip to content

Commit c4321eb

Browse files
committed
Rebased
1 parent 77115c3 commit c4321eb

3 files changed

Lines changed: 141 additions & 4 deletions

File tree

src/coreclr/jit/assertionprop.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4043,6 +4043,7 @@ void Compiler::optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
40434043
GenTree* tree,
40444044
Statement* stmt,
40454045
BasicBlock* block,
4046+
bool onlyIfCheap,
40464047
bool* isKnownNonZero,
40474048
bool* isKnownNonNegative)
40484049
{
@@ -4169,6 +4170,29 @@ void Compiler::optAssertionProp_RangeProperties(ASSERT_VALARG_TP assertions,
41694170
// Let's see if MergeEdgeAssertions can help us:
41704171
if (tree->TypeIs(TYP_INT))
41714172
{
4173+
if (!onlyIfCheap)
4174+
{
4175+
// For SSA-based we also need to check whether it overflows or not.
4176+
Range range = Range(Limit(Limit::keUndef));
4177+
if (GetRangeCheck()->TryGetRange(block, tree, &range))
4178+
{
4179+
if (range.LowerLimit().IsConstant())
4180+
{
4181+
if (range.LowerLimit().IsConstant())
4182+
{
4183+
if (range.LowerLimit().GetConstant() >= 0)
4184+
{
4185+
*isKnownNonNegative = true;
4186+
}
4187+
if (range.LowerLimit().GetConstant() > 0)
4188+
{
4189+
*isKnownNonZero = true;
4190+
}
4191+
}
4192+
}
4193+
}
4194+
}
4195+
41724196
// See if (X + CNS) is known to be non-negative
41734197
if (tree->OperIs(GT_ADD) && tree->gtGetOp2()->IsIntCnsFitsInI32())
41744198
{
@@ -4257,8 +4281,8 @@ GenTree* Compiler::optAssertionProp_ModDiv(ASSERT_VALARG_TP assertions,
42574281
bool op2IsNotZero;
42584282
bool op1IsNotNegative;
42594283
bool op2IsNotNegative;
4260-
optAssertionProp_RangeProperties(assertions, op1, stmt, block, &op1IsNotZero, &op1IsNotNegative);
4261-
optAssertionProp_RangeProperties(assertions, op2, stmt, block, &op2IsNotZero, &op2IsNotNegative);
4284+
optAssertionProp_RangeProperties(assertions, op1, stmt, block, false, &op1IsNotZero, &op1IsNotNegative);
4285+
optAssertionProp_RangeProperties(assertions, op2, stmt, block, false, &op2IsNotZero, &op2IsNotNegative);
42624286

42634287
bool changed = false;
42644288
if (op1IsNotNegative && op2IsNotNegative && tree->OperIs(GT_DIV, GT_MOD))
@@ -4561,7 +4585,7 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
45614585
if (op2->IsIntegralConst(0) && tree->OperIsCmpCompare())
45624586
{
45634587
bool isNonZero, isNeverNegative;
4564-
optAssertionProp_RangeProperties(assertions, op1, stmt, block, &isNonZero, &isNeverNegative);
4588+
optAssertionProp_RangeProperties(assertions, op1, stmt, block, true, &isNonZero, &isNeverNegative);
45654589

45664590
if (tree->OperIs(GT_GE, GT_LT) && isNeverNegative)
45674591
{
@@ -4595,6 +4619,25 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions,
45954619
}
45964620
}
45974621

4622+
if (tree->OperIsCmpCompare() && op1->TypeIs(TYP_INT) && op2->IsIntCnsFitsInI32() &&
4623+
// JIT-TP: Ignore "X relop 0" - it will be handled below
4624+
!op2->IsIntegralConst(0))
4625+
{
4626+
// NOTE: we can call GetRange for op2 as well, but that will be even more expensive,
4627+
Range rng1 = Range(Limit(Limit::keUndef));
4628+
if (GetRangeCheck()->TryGetRange(block, op1, &rng1))
4629+
{
4630+
Range rng2 = Range(Limit(Limit::keConstant, static_cast<int>(op2->AsIntCon()->IconValue())));
4631+
RangeOps::RelationKind kind = RangeOps::EvalRelop(tree->OperGet(), tree->IsUnsigned(), rng1, rng2);
4632+
if ((kind != RangeOps::RelationKind::Unknown))
4633+
{
4634+
newTree = kind == RangeOps::RelationKind::AlwaysTrue ? gtNewTrue() : gtNewFalse();
4635+
newTree = gtWrapWithSideEffects(newTree, tree, GTF_ALL_EFFECT);
4636+
return optAssertionProp_Update(newTree, tree, stmt);
4637+
}
4638+
}
4639+
}
4640+
45984641
// Look for assertions of the form (tree EQ/NE 0)
45994642
AssertionIndex index = optGlobalAssertionIsEqualOrNotEqualZero(assertions, tree);
46004643

@@ -4975,7 +5018,7 @@ GenTree* Compiler::optAssertionProp_Cast(ASSERT_VALARG_TP assertions,
49755018
{
49765019
bool isKnownNonZero;
49775020
bool isKnownNonNegative;
4978-
optAssertionProp_RangeProperties(assertions, lcl, stmt, block, &isKnownNonZero, &isKnownNonNegative);
5021+
optAssertionProp_RangeProperties(assertions, lcl, stmt, block, false, &isKnownNonZero, &isKnownNonNegative);
49795022
if (isKnownNonNegative)
49805023
{
49815024
cast->SetUnsigned();

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8129,6 +8129,7 @@ class Compiler
81298129
GenTree* tree,
81308130
Statement* stmt,
81318131
BasicBlock* block,
8132+
bool onlyIfCheap,
81328133
bool* isKnownNonZero,
81338134
bool* isKnownNonNegative);
81348135

src/coreclr/jit/rangecheck.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,99 @@ struct RangeOps
585585
result.uLimit = Limit(Limit::keConstant, -lo);
586586
return result;
587587
}
588+
589+
enum class RelationKind
590+
{
591+
AlwaysTrue,
592+
AlwaysFalse,
593+
Unknown
594+
};
595+
596+
//------------------------------------------------------------------------
597+
// EvalRelop: Evaluate the relation between two ranges for the given relop
598+
// Example: "x >= y" is AlwaysTrue when "x.LowerLimit() >= y.UpperLimit()"
599+
//
600+
// Arguments:
601+
// relop - The relational operator (LE,LT,GE,GT,EQ,NE)
602+
// isUnsigned - True if the comparison is unsigned
603+
// x - The left range
604+
// y - The right range
605+
//
606+
// Returns:
607+
// AlwaysTrue when the given relop always evaluates to true for the given ranges
608+
// AlwaysFalse when the given relop always evaluates to false for the given ranges
609+
// Otherwise Unknown
610+
//
611+
static RelationKind EvalRelop(const genTreeOps relop, bool isUnsigned, const Range& x, const Range& y)
612+
{
613+
// NOTE: we can also handle BinOpArray here, but it doesn't seem worth it
614+
615+
// For unsigned comparisons, we only support non-negative ranges.
616+
if (isUnsigned)
617+
{
618+
if ((!x.LowerLimit().IsConstant() || !y.UpperLimit().IsConstant()) ||
619+
(x.LowerLimit().GetConstant() < 0 || y.LowerLimit().GetConstant() < 0))
620+
{
621+
return RelationKind::Unknown;
622+
}
623+
}
624+
625+
switch (relop)
626+
{
627+
case GT_GE:
628+
case GT_LT:
629+
{
630+
if (x.LowerLimit().IsConstant() && y.UpperLimit().IsConstant() &&
631+
x.LowerLimit().GetConstant() >= y.UpperLimit().GetConstant())
632+
{
633+
return relop == GT_GE ? RelationKind::AlwaysTrue : RelationKind::AlwaysFalse;
634+
}
635+
636+
if (x.UpperLimit().IsConstant() && y.LowerLimit().IsConstant() &&
637+
x.UpperLimit().GetConstant() < y.LowerLimit().GetConstant())
638+
{
639+
return relop == GT_GE ? RelationKind::AlwaysFalse : RelationKind::AlwaysTrue;
640+
}
641+
break;
642+
}
643+
644+
case GT_GT:
645+
case GT_LE:
646+
{
647+
if (x.LowerLimit().IsConstant() && y.UpperLimit().IsConstant() &&
648+
x.LowerLimit().GetConstant() > y.UpperLimit().GetConstant())
649+
{
650+
return relop == GT_GT ? RelationKind::AlwaysTrue : RelationKind::AlwaysFalse;
651+
}
652+
653+
if (x.UpperLimit().IsConstant() && y.LowerLimit().IsConstant() &&
654+
x.UpperLimit().GetConstant() <= y.LowerLimit().GetConstant())
655+
{
656+
return relop == GT_GT ? RelationKind::AlwaysFalse : RelationKind::AlwaysTrue;
657+
}
658+
break;
659+
}
660+
661+
case GT_EQ:
662+
case GT_NE:
663+
{
664+
if ((x.LowerLimit().IsConstant() && y.UpperLimit().IsConstant() &&
665+
x.LowerLimit().GetConstant() > y.UpperLimit().GetConstant()) ||
666+
(x.UpperLimit().IsConstant() && y.LowerLimit().IsConstant() &&
667+
x.UpperLimit().GetConstant() < y.LowerLimit().GetConstant()))
668+
{
669+
return relop == GT_EQ ? RelationKind::AlwaysFalse : RelationKind::AlwaysTrue;
670+
}
671+
672+
break;
673+
}
674+
675+
default:
676+
assert(!"unknown comparison operator");
677+
break;
678+
}
679+
return RelationKind::Unknown;
680+
}
588681
};
589682

590683
class RangeCheck

0 commit comments

Comments
 (0)