Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase max loops optimized by RyuJIT from 16 to 64. #55614

Merged
merged 1 commit into from
Jul 15, 2021
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
2 changes: 1 addition & 1 deletion src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
}

// Make sure we reserve a NOT_IN_LOOP value that isn't a legal table index.
static_assert_no_msg(MAX_LOOP_NUM < BasicBlock::NOT_IN_LOOP);
static_assert_no_msg(BasicBlock::MAX_LOOP_NUM < BasicBlock::NOT_IN_LOOP);

block->bbNatLoopNum = BasicBlock::NOT_IN_LOOP;

Expand Down
6 changes: 2 additions & 4 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,14 +1019,12 @@ struct BasicBlock : private LIR::Range

// The following fields are used for loop detection
typedef unsigned char loopNumber;
static const unsigned NOT_IN_LOOP = UCHAR_MAX;
static const unsigned NOT_IN_LOOP = UCHAR_MAX;
static const unsigned MAX_LOOP_NUM = 64;

loopNumber bbNatLoopNum; // Index, in optLoopTable, of most-nested loop that contains this block,
// or else NOT_IN_LOOP if this block is not in a loop.

#define MAX_LOOP_NUM 16 // we're using a 'short' for the mask
#define LOOP_MASK_TP unsigned // must be big enough for a mask

// TODO-Cleanup: Get rid of bbStkDepth and use bbStackDepthOnEntry() instead
union {
unsigned short bbStkDepth; // stack depth on entry
Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1045,8 +1045,8 @@ bool Compiler::optRecordLoop(BasicBlock* head,
{
// Record this loop in the table, if there's room.

assert(optLoopCount <= MAX_LOOP_NUM);
if (optLoopCount == MAX_LOOP_NUM)
assert(optLoopCount <= BasicBlock::MAX_LOOP_NUM);
if (optLoopCount == BasicBlock::MAX_LOOP_NUM)
{
#if COUNT_LOOPS
loopOverflowThisMethod = true;
Expand All @@ -1065,7 +1065,7 @@ bool Compiler::optRecordLoop(BasicBlock* head,
if (optLoopTable == nullptr)
{
assert(loopInd == 0);
optLoopTable = getAllocator(CMK_LoopOpt).allocate<LoopDsc>(MAX_LOOP_NUM);
optLoopTable = getAllocator(CMK_LoopOpt).allocate<LoopDsc>(BasicBlock::MAX_LOOP_NUM);
}
else
{
Expand Down Expand Up @@ -2391,13 +2391,13 @@ void Compiler::optFindNaturalLoops()
loopExitCountTable.record(static_cast<unsigned>(search.GetExitCount()));

// Note that we continue to look for loops even if
// (optLoopCount == MAX_LOOP_NUM), in contrast to the !COUNT_LOOPS code below.
// (optLoopCount == BasicBlock::MAX_LOOP_NUM), in contrast to the !COUNT_LOOPS code below.
// This gives us a better count and stats. Hopefully it doesn't affect actual codegen.
CLANG_FORMAT_COMMENT_ANCHOR;

#else // COUNT_LOOPS
assert(recordedLoop);
if (optLoopCount == MAX_LOOP_NUM)
if (optLoopCount == BasicBlock::MAX_LOOP_NUM)
{
// We won't be able to record any more loops, so stop looking.
goto NO_MORE_LOOPS;
Expand Down Expand Up @@ -6588,7 +6588,7 @@ bool Compiler::optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* loo
// their definition occurs.
BasicBlock::loopNumber vnLoopNum = vnStore->LoopOfVN(vn);

if (vnLoopNum == MAX_LOOP_NUM)
if (vnLoopNum == BasicBlock::MAX_LOOP_NUM)
{
res = false;
}
Expand Down
19 changes: 10 additions & 9 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ ValueNumStore::ValueNumStore(Compiler* comp, CompAllocator alloc)
// We have no current allocation chunks.
for (unsigned i = 0; i < TYP_COUNT; i++)
{
for (unsigned j = CEA_None; j <= CEA_Count + MAX_LOOP_NUM; j++)
for (unsigned j = CEA_None; j <= CEA_Count + BasicBlock::MAX_LOOP_NUM; j++)
{
m_curAllocChunk[i][j] = NoChunk;
}
Expand All @@ -466,7 +466,8 @@ ValueNumStore::ValueNumStore(Compiler* comp, CompAllocator alloc)
}
// We will reserve chunk 0 to hold some special constants, like the constant NULL, the "exception" value, and the
// "zero map."
Chunk* specialConstChunk = new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, TYP_REF, CEA_Const, MAX_LOOP_NUM);
Chunk* specialConstChunk =
new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, TYP_REF, CEA_Const, BasicBlock::MAX_LOOP_NUM);
specialConstChunk->m_numUsed +=
SRC_NumSpecialRefConsts; // Implicitly allocate 0 ==> NULL, and 1 ==> Exception, 2 ==> ZeroMap.
ChunkNum cn = m_chunks.Push(specialConstChunk);
Expand Down Expand Up @@ -1624,7 +1625,7 @@ ValueNumStore::Chunk* ValueNumStore::GetAllocChunk(var_types typ,
{
Chunk* res;
unsigned index;
if (loopNum == MAX_LOOP_NUM)
if (loopNum == BasicBlock::MAX_LOOP_NUM)
{
// Loop nest is unknown/irrelevant for this VN.
index = attribs;
Expand All @@ -1634,8 +1635,8 @@ ValueNumStore::Chunk* ValueNumStore::GetAllocChunk(var_types typ,
// Loop nest is interesting. Since we know this is only true for unique VNs, we know attribs will
// be CEA_None and can just index based on loop number.
noway_assert(attribs == CEA_None);
// Map NOT_IN_LOOP -> MAX_LOOP_NUM to make the index range contiguous [0..MAX_LOOP_NUM]
index = CEA_Count + (loopNum == BasicBlock::NOT_IN_LOOP ? MAX_LOOP_NUM : loopNum);
// Map NOT_IN_LOOP -> BasicBlock::MAX_LOOP_NUM to make the index range contiguous [0..BasicBlock::MAX_LOOP_NUM]
index = CEA_Count + (loopNum == BasicBlock::NOT_IN_LOOP ? BasicBlock::MAX_LOOP_NUM : loopNum);
}
ChunkNum cn = m_curAllocChunk[typ][index];
if (cn != NoChunk)
Expand Down Expand Up @@ -3667,7 +3668,7 @@ ValueNum ValueNumStore::VNForExpr(BasicBlock* block, var_types typ)
BasicBlock::loopNumber loopNum;
if (block == nullptr)
{
loopNum = MAX_LOOP_NUM;
loopNum = BasicBlock::MAX_LOOP_NUM;
}
else
{
Expand Down Expand Up @@ -4344,21 +4345,21 @@ var_types ValueNumStore::TypeOfVN(ValueNum vn)
//------------------------------------------------------------------------
// LoopOfVN: If the given value number is an opaque one associated with a particular
// expression in the IR, give the loop number where the expression occurs; otherwise,
// returns MAX_LOOP_NUM.
// returns BasicBlock::MAX_LOOP_NUM.
//
// Arguments:
// vn - Value number to query
//
// Return Value:
// The correspondingblock's bbNatLoopNum, which may be BasicBlock::NOT_IN_LOOP.
// Returns MAX_LOOP_NUM if this VN is not an opaque value number associated with
// Returns BasicBlock::MAX_LOOP_NUM if this VN is not an opaque value number associated with
// a particular expression/location in the IR.

BasicBlock::loopNumber ValueNumStore::LoopOfVN(ValueNum vn)
{
if (vn == NoVN)
{
return MAX_LOOP_NUM;
return BasicBlock::MAX_LOOP_NUM;
}

Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
Expand Down
11 changes: 7 additions & 4 deletions src/coreclr/jit/valuenum.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ class ValueNumStore
// Returns TYP_UNKNOWN if the given value number has not been given a type.
var_types TypeOfVN(ValueNum vn);

// Returns MAX_LOOP_NUM if the given value number's loop nest is unknown or ill-defined.
// Returns BasicBlock::MAX_LOOP_NUM if the given value number's loop nest is unknown or ill-defined.
BasicBlock::loopNumber LoopOfVN(ValueNum vn);

// Returns true iff the VN represents a (non-handle) constant.
Expand Down Expand Up @@ -1121,14 +1121,17 @@ class ValueNumStore
JitExpandArrayStack<Chunk*> m_chunks;

// These entries indicate the current allocation chunk, if any, for each valid combination of <var_types,
// ChunkExtraAttribute, loopNumber>. Valid combinations require attribs==CEA_None or loopNum==MAX_LOOP_NUM.
// ChunkExtraAttribute, loopNumber>. Valid combinations require attribs==CEA_None or
// loopNum==BasicBlock::MAX_LOOP_NUM.
// If the value is NoChunk, it indicates that there is no current allocation chunk for that pair, otherwise
// it is the index in "m_chunks" of a chunk with the given attributes, in which the next allocation should
// be attempted.
ChunkNum m_curAllocChunk[TYP_COUNT][CEA_Count + MAX_LOOP_NUM + 1];
ChunkNum m_curAllocChunk[TYP_COUNT][CEA_Count + BasicBlock::MAX_LOOP_NUM + 1];

// Returns a (pointer to a) chunk in which a new value number may be allocated.
Chunk* GetAllocChunk(var_types typ, ChunkExtraAttribs attribs, BasicBlock::loopNumber loopNum = MAX_LOOP_NUM);
Chunk* GetAllocChunk(var_types typ,
ChunkExtraAttribs attribs,
BasicBlock::loopNumber loopNum = BasicBlock::MAX_LOOP_NUM);

// First, we need mechanisms for mapping from constants to value numbers.
// For small integers, we'll use an array.
Expand Down