Skip to content

Commit 3f70252

Browse files
authored
JIT: revise local assertion prop to use bit vectors for live assertion tracking (#94322)
Track the set of active local assertions via a bit vector, rather than assuming all entries in the table are live. Doing so required a number of changes in assertion prop to ensure the vector is consulted before deciding an assertion is valid. This will (eventually) allow us to propagate assertions cross-block. For now we reset the bit vector and assertion table back to empty at the start of each block so nothing propagates past the end of a block. The table can fill and cause the JIT to miss assertions in very large blocks as morph will no longer remove assertions while processing a block. Previously this would happen if there were more than 64 live assertions in a block, and now it can happen if there are more than 64 assertions in block (so somewhat more frequently). Contributes to #93246.
1 parent ede2cb2 commit 3f70252

File tree

5 files changed

+124
-143
lines changed

5 files changed

+124
-143
lines changed

src/coreclr/jit/assertionprop.cpp

+25-16
Original file line numberDiff line numberDiff line change
@@ -554,14 +554,14 @@ void Compiler::optAssertionInit(bool isLocalProp)
554554

555555
optLocalAssertionProp = isLocalProp;
556556
optAssertionTabPrivate = new (this, CMK_AssertionProp) AssertionDsc[optMaxAssertionCount];
557-
optComplementaryAssertionMap =
558-
new (this, CMK_AssertionProp) AssertionIndex[optMaxAssertionCount + 1](); // zero-inited (NO_ASSERTION_INDEX)
559557
assert(NO_ASSERTION_INDEX == 0);
560558

561559
if (!isLocalProp)
562560
{
563561
optValueNumToAsserts =
564562
new (getAllocator(CMK_AssertionProp)) ValueNumToAssertsMap(getAllocator(CMK_AssertionProp));
563+
optComplementaryAssertionMap = new (this, CMK_AssertionProp)
564+
AssertionIndex[optMaxAssertionCount + 1](); // zero-inited (NO_ASSERTION_INDEX)
565565
}
566566

567567
if (optAssertionDep == nullptr)
@@ -572,6 +572,7 @@ void Compiler::optAssertionInit(bool isLocalProp)
572572

573573
optAssertionTraitsInit(optMaxAssertionCount);
574574
optAssertionCount = 0;
575+
optAssertionOverflow = 0;
575576
optAssertionPropagated = false;
576577
bbJtrueAssertionOut = nullptr;
577578
optCanPropLclVar = false;
@@ -1607,6 +1608,7 @@ AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion)
16071608
// Check if we are within max count.
16081609
if (optAssertionCount >= optMaxAssertionCount)
16091610
{
1611+
optAssertionOverflow++;
16101612
return NO_ASSERTION_INDEX;
16111613
}
16121614

@@ -2370,8 +2372,7 @@ void Compiler::optAssertionGen(GenTree* tree)
23702372
break;
23712373
}
23722374

2373-
// For global assertion prop we must store the assertion number in the tree node
2374-
if (assertionInfo.HasAssertion() && assertionProven && !optLocalAssertionProp)
2375+
if (assertionInfo.HasAssertion() && assertionProven)
23752376
{
23762377
tree->SetAssertionInfo(assertionInfo);
23772378
}
@@ -2459,9 +2460,7 @@ AssertionIndex Compiler::optAssertionIsSubrange(GenTree* tree, IntegralRange ran
24592460
for (AssertionIndex index = 1; index <= optAssertionCount; index++)
24602461
{
24612462
AssertionDsc* curAssertion = optGetAssertion(index);
2462-
if ((optLocalAssertionProp ||
2463-
BitVecOps::IsMember(apTraits, assertions, index - 1)) && // either local prop or use propagated assertions
2464-
curAssertion->CanPropSubRange())
2463+
if (BitVecOps::IsMember(apTraits, assertions, index - 1) && curAssertion->CanPropSubRange())
24652464
{
24662465
// For local assertion prop use comparison on locals, and use comparison on vns for global prop.
24672466
bool isEqual = optLocalAssertionProp
@@ -2493,13 +2492,13 @@ AssertionIndex Compiler::optAssertionIsSubrange(GenTree* tree, IntegralRange ran
24932492
*/
24942493
AssertionIndex Compiler::optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions)
24952494
{
2496-
if (!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions))
2495+
if (BitVecOps::IsEmpty(apTraits, assertions))
24972496
{
24982497
return NO_ASSERTION_INDEX;
24992498
}
25002499
for (AssertionIndex index = 1; index <= optAssertionCount; index++)
25012500
{
2502-
if (!optLocalAssertionProp && !BitVecOps::IsMember(apTraits, assertions, index - 1))
2501+
if (!BitVecOps::IsMember(apTraits, assertions, index - 1))
25032502
{
25042503
continue;
25052504
}
@@ -3594,15 +3593,15 @@ AssertionIndex Compiler::optLocalAssertionIsEqualOrNotEqual(
35943593
{
35953594
noway_assert((op1Kind == O1K_LCLVAR) || (op1Kind == O1K_EXACT_TYPE) || (op1Kind == O1K_SUBTYPE));
35963595
noway_assert((op2Kind == O2K_CONST_INT) || (op2Kind == O2K_IND_CNS_INT) || (op2Kind == O2K_ZEROOBJ));
3597-
if (!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions))
3596+
if (BitVecOps::IsEmpty(apTraits, assertions))
35983597
{
35993598
return NO_ASSERTION_INDEX;
36003599
}
36013600

36023601
for (AssertionIndex index = 1; index <= optAssertionCount; ++index)
36033602
{
36043603
AssertionDsc* curAssertion = optGetAssertion(index);
3605-
if (optLocalAssertionProp || BitVecOps::IsMember(apTraits, assertions, index - 1))
3604+
if (BitVecOps::IsMember(apTraits, assertions, index - 1))
36063605
{
36073606
if ((curAssertion->assertionKind != OAK_EQUAL) && (curAssertion->assertionKind != OAK_NOT_EQUAL))
36083607
{
@@ -4386,17 +4385,27 @@ AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* op,
43864385
}
43874386
else
43884387
{
4389-
unsigned lclNum = op->AsLclVarCommon()->GetLclNum();
4390-
// Check each assertion to find if we have a variable == or != null assertion.
4391-
for (AssertionIndex index = 1; index <= optAssertionCount; index++)
4388+
// Find live assertions related to lclNum
4389+
//
4390+
unsigned const lclNum = op->AsLclVarCommon()->GetLclNum();
4391+
ASSERT_TP apDependent = GetAssertionDep(lclNum);
4392+
BitVecOps::IntersectionD(apTraits, apDependent, apLocal);
4393+
4394+
// Scan those looking for a suitable assertion
4395+
//
4396+
BitVecOps::Iter iter(apTraits, assertions);
4397+
unsigned index = 0;
4398+
while (iter.NextElem(&index))
43924399
{
4393-
AssertionDsc* curAssertion = optGetAssertion(index);
4400+
AssertionIndex assertionIndex = GetAssertionIndex(index);
4401+
AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
4402+
43944403
if ((curAssertion->assertionKind == OAK_NOT_EQUAL) && // kind
43954404
(curAssertion->op1.kind == O1K_LCLVAR) && // op1
43964405
(curAssertion->op2.kind == O2K_CONST_INT) && // op2
43974406
(curAssertion->op1.lcl.lclNum == lclNum) && (curAssertion->op2.u1.iconVal == 0))
43984407
{
4399-
return index;
4408+
return assertionIndex;
44004409
}
44014410
}
44024411
}

src/coreclr/jit/bitset.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,11 @@ class BitSetOps
172172
// Returns "true" iff "bs" may be the uninit value.
173173
static bool MayBeUninit(BitSetValueArgType bs);
174174

175-
// Returns the a new BitSet that is empty. Uses the Allocator of "env" to allocate memory for
175+
// Returns a new BitSet that is empty. Uses the Allocator of "env" to allocate memory for
176176
// the representation, if necessary.
177177
static BitSetValueRetType MakeEmpty(Env env);
178178

179-
// Returns the a new BitSet that is "full" -- represents all the integers in the current range.
179+
// Returns a new BitSet that is "full" -- represents all the integers in the current range.
180180
// Uses the Allocator of "env" to allocate memory for the representation, if necessary.
181181
static BitSetValueRetType MakeFull(Env env);
182182

src/coreclr/jit/compiler.h

+3
Original file line numberDiff line numberDiff line change
@@ -6064,6 +6064,7 @@ class Compiler
60646064
GenTree* fgMorphTree(GenTree* tree, MorphAddrContext* mac = nullptr);
60656065

60666066
private:
6067+
void fgAssertionGen(GenTree* tree);
60676068
void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* tree));
60686069
void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree));
60696070
void fgMorphTreeDone(GenTree* tree);
@@ -7354,6 +7355,7 @@ class Compiler
73547355
// Data structures for assertion prop
73557356
BitVecTraits* apTraits;
73567357
ASSERT_TP apFull;
7358+
ASSERT_TP apLocal;
73577359

73587360
enum optAssertionKind
73597361
{
@@ -7638,6 +7640,7 @@ class Compiler
76387640
AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
76397641
AssertionIndex optAssertionCount; // total number of assertions in the assertion table
76407642
AssertionIndex optMaxAssertionCount;
7643+
unsigned optAssertionOverflow;
76417644
bool optCanPropLclVar;
76427645
bool optCanPropEqual;
76437646
bool optCanPropNonNull;

0 commit comments

Comments
 (0)