@@ -12443,6 +12443,34 @@ void Compiler::fgAssertionGen(GenTree* tree)
1244312443#endif
1244412444 };
1244512445
12446+ // If this tree creates an assignment of 0 or 1 to an int local, also create a [0..1] subrange
12447+ // assertion for that local, in case this local is used as a bool.
12448+ //
12449+ auto addImpliedBoolSubrangeAssertion = [=](AssertionIndex index, ASSERT_TP assertions) {
12450+ AssertionDsc* const assertion = optGetAssertion(index);
12451+ if ((assertion->assertionKind == OAK_EQUAL) && (assertion->op1.kind == O1K_LCLVAR) &&
12452+ (assertion->op2.kind == O2K_CONST_INT))
12453+ {
12454+ ssize_t iconVal = assertion->op2.u1.iconVal;
12455+ if ((iconVal == 0) || (iconVal == 1))
12456+ {
12457+ AssertionDsc extraAssertion = {OAK_SUBRANGE};
12458+ extraAssertion.op1.kind = O1K_LCLVAR;
12459+ extraAssertion.op1.lcl.lclNum = assertion->op1.lcl.lclNum;
12460+ extraAssertion.op2.kind = O2K_SUBRANGE;
12461+ extraAssertion.op2.u2 = IntegralRange(SymbolicIntegerValue::Zero, SymbolicIntegerValue::One);
12462+
12463+ AssertionIndex extraIndex = optFinalizeCreatingAssertion(&extraAssertion);
12464+ if (extraIndex != NO_ASSERTION_INDEX)
12465+ {
12466+ unsigned const bvIndex = extraIndex - 1;
12467+ BitVecOps::AddElemD(apTraits, assertions, bvIndex);
12468+ announce(extraIndex, "[bool range] ");
12469+ }
12470+ }
12471+ }
12472+ };
12473+
1244612474 // For BBJ_COND nodes, we have two assertion out BVs.
1244712475 // apLocal will be stored on bbAssertionOutIfFalse and be used for false successors.
1244812476 // apLocalIfTrue will be stored on bbAssertionOutIfTrue and be used for true successors.
@@ -12467,7 +12495,7 @@ void Compiler::fgAssertionGen(GenTree* tree)
1246712495
1246812496 if (makeCondAssertions)
1246912497 {
12470- // Update apLocal and apIfTrue with suitable assertions
12498+ // Update apLocal and apLocalIfTrue with suitable assertions
1247112499 // from the JTRUE
1247212500 //
1247312501 assert(optCrossBlockLocalAssertionProp);
@@ -12491,13 +12519,15 @@ void Compiler::fgAssertionGen(GenTree* tree)
1249112519 announce(ifTrueAssertionIndex, "[if true] ");
1249212520 unsigned const bvIndex = ifTrueAssertionIndex - 1;
1249312521 BitVecOps::AddElemD(apTraits, apLocalIfTrue, bvIndex);
12522+ addImpliedBoolSubrangeAssertion(ifTrueAssertionIndex, apLocalIfTrue);
1249412523 }
1249512524
1249612525 if (ifFalseAssertionIndex != NO_ASSERTION_INDEX)
1249712526 {
1249812527 announce(ifFalseAssertionIndex, "[if false] ");
1249912528 unsigned const bvIndex = ifFalseAssertionIndex - 1;
1250012529 BitVecOps::AddElemD(apTraits, apLocal, ifFalseAssertionIndex - 1);
12530+ addImpliedBoolSubrangeAssertion(ifFalseAssertionIndex, apLocal);
1250112531 }
1250212532 }
1250312533 else
@@ -12506,6 +12536,7 @@ void Compiler::fgAssertionGen(GenTree* tree)
1250612536 announce(apIndex, "");
1250712537 unsigned const bvIndex = apIndex - 1;
1250812538 BitVecOps::AddElemD(apTraits, apLocal, bvIndex);
12539+ addImpliedBoolSubrangeAssertion(apIndex, apLocal);
1250912540 }
1251012541}
1251112542
@@ -13604,6 +13635,14 @@ PhaseStatus Compiler::fgMorphBlocks()
1360413635 }
1360513636#endif
1360613637
13638+ if (optLocalAssertionProp)
13639+ {
13640+ Metrics.LocalAssertionCount = optAssertionCount;
13641+ Metrics.LocalAssertionOverflow = optAssertionOverflow;
13642+ Metrics.MorphTrackedLocals = lvaTrackedCount;
13643+ Metrics.MorphLocals = lvaCount;
13644+ }
13645+
1360713646 return PhaseStatus::MODIFIED_EVERYTHING;
1360813647}
1360913648
0 commit comments