Skip to content

Commit 0349889

Browse files
authored
JIT: implied Boolean range assertions for local prop (#109481)
If morph sees an assignment of 0/1 to a local, have it generate a [0..1] range assertion in addition to the constant assertion. This helps morph propagate more Boolean ranges at merges, which allows morph to elide more casts. Also, bump up the local assertion table size since morph is now generating more assertions.
1 parent f1332ab commit 0349889

File tree

4 files changed

+69
-6
lines changed

4 files changed

+69
-6
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -659,11 +659,21 @@ void Compiler::optAssertionInit(bool isLocalProp)
659659

660660
if (optCrossBlockLocalAssertionProp)
661661
{
662-
// We may need a fairly large table.
663-
// Allow for roughly one assertion per local, up to the tracked limit.
664-
// (empirical studies show about 0.6 asserions/local)
662+
// We may need a fairly large table. Keep size a multiple of 64.
663+
// Empirical studies show about 1.16 asserions/ tracked local.
665664
//
666-
optMaxAssertionCount = (AssertionIndex)min(maxTrackedLocals, ((lvaCount / 64) + 1) * 64);
665+
if (lvaTrackedCount < 24)
666+
{
667+
optMaxAssertionCount = 64;
668+
}
669+
else if (lvaTrackedCount < 64)
670+
{
671+
optMaxAssertionCount = 128;
672+
}
673+
else
674+
{
675+
optMaxAssertionCount = (AssertionIndex)min(maxTrackedLocals, ((3 * lvaTrackedCount / 128) + 1) * 64);
676+
}
667677
}
668678
else
669679
{

src/coreclr/jit/jitmetadatalist.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ JITMETADATAMETRIC(NewRefClassHelperCalls, int, 0)
8383
JITMETADATAMETRIC(StackAllocatedRefClasses, int, 0)
8484
JITMETADATAMETRIC(NewBoxedValueClassHelperCalls, int, 0)
8585
JITMETADATAMETRIC(StackAllocatedBoxedValueClasses, int, 0)
86+
JITMETADATAMETRIC(LocalAssertionCount, int, 0)
87+
JITMETADATAMETRIC(LocalAssertionOverflow, int, 0)
88+
JITMETADATAMETRIC(MorphTrackedLocals, int, 0)
89+
JITMETADATAMETRIC(MorphLocals, int, 0)
8690

8791
#undef JITMETADATA
8892
#undef JITMETADATAINFO

src/coreclr/jit/morph.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

src/coreclr/scripts/superpmi.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ def add_core_root_arguments(parser, build_type_default, build_type_help):
338338
replay_common_parser.add_argument("-private_store", action="append", help=private_store_help)
339339
replay_common_parser.add_argument("-compile", "-c", help=compile_help)
340340
replay_common_parser.add_argument("--produce_repro", action="store_true", help=produce_repro_help)
341+
replay_common_parser.add_argument("-details", help="Specify full path to details file")
341342

342343
# subparser for replay
343344
replay_parser = subparsers.add_parser("replay", description=replay_description, parents=[core_root_parser, target_parser, superpmi_common_parser, replay_common_parser])
@@ -1734,7 +1735,11 @@ def replay(self):
17341735
flags = common_flags.copy()
17351736

17361737
fail_mcl_file = os.path.join(temp_location, os.path.basename(mch_file) + "_fail.mcl")
1737-
details_info_file = os.path.join(temp_location, os.path.basename(mch_file) + "_details.csv")
1738+
1739+
if self.coreclr_args.details:
1740+
details_info_file = self.coreclr_args.details
1741+
else:
1742+
details_info_file = os.path.join(temp_location, os.path.basename(mch_file) + "_details.csv")
17381743

17391744
flags += [
17401745
"-f", fail_mcl_file, # Failing mc List
@@ -4985,6 +4990,11 @@ def verify_base_diff_args():
49854990
lambda unused: True,
49864991
"Unable to set jitoption")
49874992

4993+
coreclr_args.verify(args,
4994+
"details",
4995+
lambda unused: True,
4996+
"Unable to set details")
4997+
49884998
jit_in_product_location = False
49894999
if coreclr_args.product_location.lower() in coreclr_args.jit_path.lower():
49905000
jit_in_product_location = True

0 commit comments

Comments
 (0)