summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/lsra.cpp135
-rw-r--r--src/jit/lsra.h3
2 files changed, 109 insertions, 29 deletions
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 127b720594..cef80184dc 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -1211,25 +1211,18 @@ LinearScan::setBlockSequence()
// We can stop checking now.
checkForCriticalOutEdge = false;
}
+
if (isTraversalLayoutOrder() || isBlockVisited(succ))
{
continue;
}
- // For pred-first order, we prefer layout order, as long as there is an edge between
- // them. Otherwise, we'll add it to the list.
- if (isTraversalPredFirstOrder() && succ == block->bbNext)
- {
- nextBlock = succ;
- BlockSetOps::AddElemD(compiler, readySet, succ->bbNum);
- continue;
- }
// We've now seen a predecessor, so add it to the work list and the "readySet".
// It will be inserted in the worklist according to the specified traversal order
// (i.e. pred-first or random, since layout order is handled above).
if (!BlockSetOps::IsMember(compiler, readySet, succ->bbNum))
{
- addToBlockSequenceWorkList(succ);
+ addToBlockSequenceWorkList(readySet, succ);
BlockSetOps::AddElemD(compiler, readySet, succ->bbNum);
}
}
@@ -1244,6 +1237,7 @@ LinearScan::setBlockSequence()
while (nextBlock == nullptr)
{
nextBlock = getNextCandidateFromWorkList();
+
// TODO-Throughput: We would like to bypass this traversal if we know we've handled all
// the blocks - but fgBBcount does not appear to be updated when blocks are removed.
if (nextBlock == nullptr /* && bbSeqCount != compiler->fgBBcount*/ && !verifiedAllBBs)
@@ -1261,15 +1255,16 @@ LinearScan::setBlockSequence()
{
if (!isBlockVisited(block))
{
- addToBlockSequenceWorkList(block);
+ addToBlockSequenceWorkList(readySet, block);
BlockSetOps::AddElemD(compiler, readySet, block->bbNum);
}
}
+
for (BasicBlock* block = compiler->fgFirstBB; block; block = block->bbNext)
{
if (!isBlockVisited(block))
{
- addToBlockSequenceWorkList(block);
+ addToBlockSequenceWorkList(readySet, block);
BlockSetOps::AddElemD(compiler, readySet, block->bbNum);
}
}
@@ -1286,11 +1281,35 @@ LinearScan::setBlockSequence()
#ifdef DEBUG
// Make sure that we've visited all the blocks.
for( BasicBlock* block = compiler->fgFirstBB;
- block != nullptr;
- block = block->bbNext)
+ block != nullptr;
+ block = block->bbNext)
{
assert(isBlockVisited(block));
}
+
+ JITDUMP("LSRA Block Sequence: ");
+ int i = 1;
+ for (BasicBlock* block = startBlockSequence();
+ block != nullptr;
+ ++i, block = moveToNextBlock())
+ {
+ JITDUMP("BB%02u", block->bbNum);
+
+ if (block->isMaxBBWeight())
+ {
+ JITDUMP("(MAX) ");
+ }
+ else
+ {
+ JITDUMP("(%6s) ", refCntWtd2str(block->getBBWeight(compiler)));
+ }
+
+ if (i % 10 == 0)
+ {
+ JITDUMP("\n ");
+ }
+ }
+ JITDUMP("\n\n");
#endif
}
@@ -1298,8 +1317,9 @@ LinearScan::setBlockSequence()
// compareBlocksForSequencing: Compare two basic blocks for sequencing order.
//
// Arguments:
-// block1 - the first block for comparison
-// block2 - the second block for comparison
+// block1 - the first block for comparison
+// block2 - the second block for comparison
+// useBlockWeights - whether to use block weights for comparison
//
// Return Value:
// -1 if block1 is preferred.
@@ -1308,11 +1328,25 @@ LinearScan::setBlockSequence()
//
// Notes:
// See addToBlockSequenceWorkList.
-// Currently, this is a simplistic method that prioritizes low bbNum.
-static int
-compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2)
-{
- // Prefer LOWER bbnum
+int
+LinearScan::compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2, bool useBlockWeights)
+{
+ if (useBlockWeights)
+ {
+ unsigned weight1 = block1->getBBWeight(compiler);
+ unsigned weight2 = block2->getBBWeight(compiler);
+
+ if (weight1 > weight2)
+ {
+ return -1;
+ }
+ else if (weight1 < weight2)
+ {
+ return 1;
+ }
+ }
+
+ // If weights are the same prefer LOWER bbnum
if (block1->bbNum < block2->bbNum)
{
return -1;
@@ -1331,7 +1365,8 @@ compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2)
// addToBlockSequenceWorkList: Add a BasicBlock to the work list for sequencing.
//
// Arguments:
-// block - the block to be added
+// sequencedBlockSet - the set of blocks that are already sequenced
+// block - the new block to be added
//
// Return Value:
// None.
@@ -1341,22 +1376,66 @@ compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2)
// as we encounter a block whose successors have all been sequenced, in pred-first
// order, or the very next block if we are traversing in random order (once implemented).
// This method uses a comparison method to determine the order in which to place
-// the blocks in the list. Currently, this is a simplistic method based on
-// bbNum. This could be a future candidate for tuning.
+// the blocks in the list. This method queries whether all predecessors of the
+// block are sequenced at the time it is added to the list and if so uses block weights
+// for inserting the block. A block is never inserted ahead of its predecessors.
+// A block at the time of insertion may not have all its predecessors sequenced, in
+// which case it will be sequenced based on its block number. Once a block is inserted,
+// its priority\order will not be changed later once its remaining predecessors are
+// sequenced. This would mean that work list may not be sorted entirely based on
+// block weights alone.
+//
// Note also that, when random traversal order is implemented, this method
// should insert the blocks into the list in random order, so that we can always
// simply select the first block in the list.
void
-LinearScan::addToBlockSequenceWorkList(BasicBlock* block)
+LinearScan::addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block)
{
+ // The block that is being added is not already sequenced
+ assert(!BlockSetOps::IsMember(compiler, sequencedBlockSet, block->bbNum));
+
+ // Get predSet of block
+ BlockSet BLOCKSET_INIT_NOCOPY(predSet, BlockSetOps::MakeEmpty(compiler));
+ flowList* pred;
+ for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
+ {
+ BlockSetOps::AddElemD(compiler, predSet, pred->flBlock->bbNum);
+ }
+
+ // If either a rarely run block or all its preds are already sequenced, use block's weight to sequence
+ bool useBlockWeight = block->isRunRarely() || BlockSetOps::IsSubset(compiler, sequencedBlockSet, predSet);
+
BasicBlockList* prevNode = nullptr;
- BasicBlockList* nextNode;
- for (nextNode = blockSequenceWorkList;
- nextNode != nullptr && compareBlocksForSequencing(nextNode->block, block) <= 0;
- nextNode = nextNode->next)
+ BasicBlockList* nextNode = blockSequenceWorkList;
+
+ while (nextNode != nullptr)
{
+ int seqResult;
+
+ if (nextNode->block->isRunRarely())
+ {
+ // If the block that is yet to be sequenced is a rarely run block, always use block weights for sequencing
+ seqResult = compareBlocksForSequencing(nextNode->block, block, true);
+ }
+ else if (BlockSetOps::IsMember(compiler, predSet, nextNode->block->bbNum))
+ {
+ // always prefer unsequenced pred blocks
+ seqResult = -1;
+ }
+ else
+ {
+ seqResult = compareBlocksForSequencing(nextNode->block, block, useBlockWeight);
+ }
+
+ if (seqResult > 0)
+ {
+ break;
+ }
+
prevNode = nextNode;
+ nextNode = nextNode->next;
}
+
BasicBlockList* newListNode = new (compiler, CMK_LSRA) BasicBlockList(block, nextNode);
if (prevNode == nullptr)
{
diff --git a/src/jit/lsra.h b/src/jit/lsra.h
index 4e53369535..27939d7422 100644
--- a/src/jit/lsra.h
+++ b/src/jit/lsra.h
@@ -981,9 +981,10 @@ private:
// included in the blockSeuqence above, during setBlockSequence().
bool verifiedAllBBs;
void setBlockSequence();
+ int compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2, bool useBlockWeights);
BasicBlockList* blockSequenceWorkList;
bool blockSequencingDone;
- void addToBlockSequenceWorkList(BasicBlock* block);
+ void addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block);
void removeFromBlockSequenceWorkList(BasicBlockList* listNode, BasicBlockList* prevNode);
BasicBlock* getNextCandidateFromWorkList();