@@ -913,11 +913,10 @@ LinearScan::LinearScan(Compiler* theCompiler)
913913 // Note that we don't initialize the bbVisitedSet until we do the first traversal
914914 // This is so that any blocks that are added during the first traversal
915915 // are accounted for (and we don't have BasicBlockEpoch issues).
916- blockSequencingDone = false;
917- blockSequence = nullptr;
918- blockSequenceWorkList = nullptr;
919- curBBSeqNum = 0;
920- bbSeqCount = 0;
916+ blockSequencingDone = false;
917+ blockSequence = nullptr;
918+ curBBSeqNum = 0;
919+ bbSeqCount = 0;
921920
922921 // Information about each block, including predecessor blocks used for variable locations at block entry.
923922 blockInfo = nullptr;
@@ -926,39 +925,6 @@ LinearScan::LinearScan(Compiler* theCompiler)
926925 tgtPrefUse = nullptr;
927926}
928927
929- //------------------------------------------------------------------------
930- // getNextCandidateFromWorkList: Get the next candidate for block sequencing
931- //
932- // Arguments:
933- // None.
934- //
935- // Return Value:
936- // The next block to be placed in the sequence.
937- //
938- // Notes:
939- // This method currently always returns the next block in the list, and relies on having
940- // blocks added to the list only when they are "ready", and on the
941- // addToBlockSequenceWorkList() method to insert them in the proper order.
942- // However, a block may be in the list and already selected, if it was subsequently
943- // encountered as both a flow and layout successor of the most recently selected
944- // block.
945- //
946- BasicBlock* LinearScan::getNextCandidateFromWorkList()
947- {
948- BasicBlockList* nextWorkList = nullptr;
949- for (BasicBlockList* workList = blockSequenceWorkList; workList != nullptr; workList = nextWorkList)
950- {
951- nextWorkList = workList->next;
952- BasicBlock* candBlock = workList->block;
953- removeFromBlockSequenceWorkList(workList, nullptr);
954- if (!isBlockVisited(candBlock))
955- {
956- return candBlock;
957- }
958- }
959- return nullptr;
960- }
961-
962928//------------------------------------------------------------------------
963929// setBlockSequence: Determine the block order for register allocation.
964930//
@@ -969,8 +935,7 @@ BasicBlock* LinearScan::getNextCandidateFromWorkList()
969935// None
970936//
971937// Notes:
972- // On return, the blockSequence array contains the blocks, in the order in which they
973- // will be allocated.
938+ // On return, the blockSequence array contains the blocks in reverse post-order.
974939// This method clears the bbVisitedSet on LinearScan, and when it returns the set
975940// contains all the bbNums for the block.
976941//
@@ -986,19 +951,20 @@ void LinearScan::setBlockSequence()
986951 // Initialize the "visited" blocks set.
987952 bbVisitedSet = BlockSetOps::MakeEmpty(compiler);
988953
989- BlockSet readySet(BlockSetOps::MakeEmpty(compiler));
990- BlockSet predSet(BlockSetOps::MakeEmpty(compiler));
991-
992- assert(blockSequence == nullptr && bbSeqCount == 0);
993- blockSequence = new (compiler, CMK_LSRA) BasicBlock*[compiler->fgBBcount];
994- bbNumMaxBeforeResolution = compiler->fgBBNumMax;
995- blockInfo = new (compiler, CMK_LSRA) LsraBlockInfo[bbNumMaxBeforeResolution + 1];
954+ assert((blockSequence == nullptr) && (bbSeqCount == 0));
955+ FlowGraphDfsTree* const dfsTree = compiler->fgComputeDfs</* useProfile */ true>();
956+ blockSequence = dfsTree->GetPostOrder();
957+ bbNumMaxBeforeResolution = compiler->fgBBNumMax;
958+ blockInfo = new (compiler, CMK_LSRA) LsraBlockInfo[bbNumMaxBeforeResolution + 1];
996959
997- assert(blockSequenceWorkList == nullptr);
960+ // Flip the DFS traversal to get the reverse post-order traversal
961+ // (this is the order in which blocks will be allocated)
962+ for (unsigned left = 0, right = dfsTree->GetPostOrderCount() - 1; left < right; left++, right--)
963+ {
964+ std::swap(blockSequence[left], blockSequence[right]);
965+ }
998966
999- verifiedAllBBs = false;
1000967 hasCriticalEdges = false;
1001- BasicBlock* nextBlock;
1002968 // We use a bbNum of 0 for entry RefPositions.
1003969 // The other information in blockInfo[0] will never be used.
1004970 blockInfo[0].weight = BB_UNITY_WEIGHT;
@@ -1009,14 +975,9 @@ void LinearScan::setBlockSequence()
1009975 }
1010976#endif // TRACK_LSRA_STATS
1011977
1012- JITDUMP("Start LSRA Block Sequence: \n");
1013- for (BasicBlock* block = compiler->fgFirstBB; block != nullptr; block = nextBlock)
1014- {
978+ auto visitBlock = [this](BasicBlock* block) {
1015979 JITDUMP("Current block: " FMT_BB "\n", block->bbNum);
1016- blockSequence[bbSeqCount] = block;
1017980 markBlockVisited(block);
1018- bbSeqCount++;
1019- nextBlock = nullptr;
1020981
1021982 // Initialize the blockInfo.
1022983 // predBBNum will be set later.
@@ -1087,73 +1048,41 @@ void LinearScan::setBlockSequence()
10871048 assert(!"Switch with single successor");
10881049 }
10891050
1090- for (unsigned succIndex = 0; succIndex < numSuccs; succIndex++ )
1051+ for (BasicBlock* const succ : block->Succs(compiler) )
10911052 {
1092- BasicBlock* succ = block->GetSucc(succIndex, compiler);
1093- if (checkForCriticalOutEdge && succ->GetUniquePred(compiler) == nullptr)
1053+ if (checkForCriticalOutEdge && (succ->GetUniquePred(compiler) == nullptr))
10941054 {
10951055 blockInfo[block->bbNum].hasCriticalOutEdge = true;
10961056 hasCriticalEdges = true;
10971057 // We can stop checking now.
1098- checkForCriticalOutEdge = false;
1099- }
1100-
1101- if (isTraversalLayoutOrder() || isBlockVisited(succ))
1102- {
1103- continue;
1104- }
1105-
1106- // We've now seen a predecessor, so add it to the work list and the "readySet".
1107- // It will be inserted in the worklist according to the specified traversal order
1108- // (i.e. pred-first or random, since layout order is handled above).
1109- if (!BlockSetOps::IsMember(compiler, readySet, succ->bbNum))
1110- {
1111- JITDUMP("\tSucc block: " FMT_BB, succ->bbNum);
1112- addToBlockSequenceWorkList(readySet, succ, predSet);
1113- BlockSetOps::AddElemD(compiler, readySet, succ->bbNum);
1058+ break;
11141059 }
11151060 }
1061+ };
11161062
1117- // For layout order, simply use bbNext
1118- if (isTraversalLayoutOrder())
1119- {
1120- nextBlock = block->Next();
1121- continue;
1122- }
1063+ JITDUMP("Start LSRA Block Sequence: \n");
1064+ for (unsigned i = 0; i < dfsTree->GetPostOrderCount(); i++)
1065+ {
1066+ visitBlock(blockSequence[i]);
1067+ }
11231068
1124- while (nextBlock == nullptr)
1069+ // If the DFS didn't visit any blocks, add them to the end of blockSequence
1070+ if (dfsTree->GetPostOrderCount() < compiler->fgBBcount)
1071+ {
1072+ // Unvisited blocks are more likely to be at the back of the list, so iterate backwards
1073+ unsigned i = dfsTree->GetPostOrderCount();
1074+ for (BasicBlock* block = compiler->fgLastBB; i < compiler->fgBBcount; block = block->Prev())
11251075 {
1126- nextBlock = getNextCandidateFromWorkList();
1127-
1128- // TODO-Throughput: We would like to bypass this traversal if we know we've handled all
1129- // the blocks - but fgBBcount does not appear to be updated when blocks are removed.
1130- if (nextBlock == nullptr /* && bbSeqCount != compiler->fgBBcount*/ && !verifiedAllBBs)
1131- {
1132- // If we don't encounter all blocks by traversing the regular successor links, do a full
1133- // traversal of all the blocks, and add them in layout order.
1134- // This may include:
1135- // - internal-only blocks which may not be in the flow graph
1136- // - blocks that have become unreachable due to optimizations, but that are strongly
1137- // connected (these are not removed)
1138- // - EH blocks
1139-
1140- for (BasicBlock* const seqBlock : compiler->Blocks())
1141- {
1142- if (!isBlockVisited(seqBlock))
1143- {
1144- JITDUMP("\tUnvisited block: " FMT_BB, seqBlock->bbNum);
1145- addToBlockSequenceWorkList(readySet, seqBlock, predSet);
1146- BlockSetOps::AddElemD(compiler, readySet, seqBlock->bbNum);
1147- }
1148- }
1149- verifiedAllBBs = true;
1150- }
1151- else
1076+ assert(block != nullptr);
1077+ if (!isBlockVisited(block))
11521078 {
1153- break;
1079+ visitBlock(block);
1080+ blockSequence[i++] = block;
11541081 }
11551082 }
11561083 }
1084+
1085+ bbSeqCount = compiler->fgBBcount;
11571086 blockSequencingDone = true;
11581087
11591088#ifdef DEBUG
@@ -1199,169 +1128,6 @@ void LinearScan::setBlockSequence()
11991128#endif
12001129}
12011130
1202- //------------------------------------------------------------------------
1203- // compareBlocksForSequencing: Compare two basic blocks for sequencing order.
1204- //
1205- // Arguments:
1206- // block1 - the first block for comparison
1207- // block2 - the second block for comparison
1208- // useBlockWeights - whether to use block weights for comparison
1209- //
1210- // Return Value:
1211- // -1 if block1 is preferred.
1212- // 0 if the blocks are equivalent.
1213- // 1 if block2 is preferred.
1214- //
1215- // Notes:
1216- // See addToBlockSequenceWorkList.
1217- //
1218- int LinearScan::compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block2, bool useBlockWeights)
1219- {
1220- if (useBlockWeights)
1221- {
1222- weight_t weight1 = block1->getBBWeight(compiler);
1223- weight_t weight2 = block2->getBBWeight(compiler);
1224-
1225- if (weight1 > weight2)
1226- {
1227- return -1;
1228- }
1229- else if (weight1 < weight2)
1230- {
1231- return 1;
1232- }
1233- }
1234-
1235- // If weights are the same prefer LOWER bbnum
1236- if (block1->bbNum < block2->bbNum)
1237- {
1238- return -1;
1239- }
1240- else if (block1->bbNum == block2->bbNum)
1241- {
1242- return 0;
1243- }
1244- else
1245- {
1246- return 1;
1247- }
1248- }
1249-
1250- //------------------------------------------------------------------------
1251- // addToBlockSequenceWorkList: Add a BasicBlock to the work list for sequencing.
1252- //
1253- // Arguments:
1254- // sequencedBlockSet - the set of blocks that are already sequenced
1255- // block - the new block to be added
1256- // predSet - the buffer to save predecessors set. A block set allocated by the caller used here as a
1257- // temporary block set for constructing a predecessor set. Allocated by the caller to avoid reallocating a new block
1258- // set with every call to this function
1259- //
1260- // Return Value:
1261- // None.
1262- //
1263- // Notes:
1264- // The first block in the list will be the next one to be sequenced, as soon
1265- // as we encounter a block whose successors have all been sequenced, in pred-first
1266- // order, or the very next block if we are traversing in random order (once implemented).
1267- // This method uses a comparison method to determine the order in which to place
1268- // the blocks in the list. This method queries whether all predecessors of the
1269- // block are sequenced at the time it is added to the list and if so uses block weights
1270- // for inserting the block. A block is never inserted ahead of its predecessors.
1271- // A block at the time of insertion may not have all its predecessors sequenced, in
1272- // which case it will be sequenced based on its block number. Once a block is inserted,
1273- // its priority\order will not be changed later once its remaining predecessors are
1274- // sequenced. This would mean that work list may not be sorted entirely based on
1275- // block weights alone.
1276- //
1277- // Note also that, when random traversal order is implemented, this method
1278- // should insert the blocks into the list in random order, so that we can always
1279- // simply select the first block in the list.
1280- //
1281- void LinearScan::addToBlockSequenceWorkList(BlockSet sequencedBlockSet, BasicBlock* block, BlockSet& predSet)
1282- {
1283- // The block that is being added is not already sequenced
1284- assert(!BlockSetOps::IsMember(compiler, sequencedBlockSet, block->bbNum));
1285-
1286- // Get predSet of block
1287- BlockSetOps::ClearD(compiler, predSet);
1288- for (BasicBlock* const predBlock : block->PredBlocks())
1289- {
1290- BlockSetOps::AddElemD(compiler, predSet, predBlock->bbNum);
1291- }
1292-
1293- // If either a rarely run block or all its preds are already sequenced, use block's weight to sequence
1294- bool useBlockWeight = block->isRunRarely() || BlockSetOps::IsSubset(compiler, sequencedBlockSet, predSet);
1295- JITDUMP(", Criteria: %s", useBlockWeight ? "weight" : "bbNum");
1296-
1297- BasicBlockList* prevNode = nullptr;
1298- BasicBlockList* nextNode = blockSequenceWorkList;
1299- while (nextNode != nullptr)
1300- {
1301- int seqResult;
1302-
1303- if (nextNode->block->isRunRarely())
1304- {
1305- // If the block that is yet to be sequenced is a rarely run block, always use block weights for sequencing
1306- seqResult = compareBlocksForSequencing(nextNode->block, block, true);
1307- }
1308- else if (BlockSetOps::IsMember(compiler, predSet, nextNode->block->bbNum))
1309- {
1310- // always prefer unsequenced pred blocks
1311- seqResult = -1;
1312- }
1313- else
1314- {
1315- seqResult = compareBlocksForSequencing(nextNode->block, block, useBlockWeight);
1316- }
1317-
1318- if (seqResult > 0)
1319- {
1320- break;
1321- }
1322-
1323- prevNode = nextNode;
1324- nextNode = nextNode->next;
1325- }
1326-
1327- BasicBlockList* newListNode = new (compiler, CMK_LSRA) BasicBlockList(block, nextNode);
1328- if (prevNode == nullptr)
1329- {
1330- blockSequenceWorkList = newListNode;
1331- }
1332- else
1333- {
1334- prevNode->next = newListNode;
1335- }
1336-
1337- #ifdef DEBUG
1338- nextNode = blockSequenceWorkList;
1339- JITDUMP(", Worklist: [");
1340- while (nextNode != nullptr)
1341- {
1342- JITDUMP(FMT_BB " ", nextNode->block->bbNum);
1343- nextNode = nextNode->next;
1344- }
1345- JITDUMP("]\n");
1346- #endif
1347- }
1348-
1349- void LinearScan::removeFromBlockSequenceWorkList(BasicBlockList* listNode, BasicBlockList* prevNode)
1350- {
1351- if (listNode == blockSequenceWorkList)
1352- {
1353- assert(prevNode == nullptr);
1354- blockSequenceWorkList = listNode->next;
1355- }
1356- else
1357- {
1358- assert(prevNode != nullptr && prevNode->next == listNode);
1359- prevNode->next = listNode->next;
1360- }
1361- // TODO-Cleanup: consider merging Compiler::BlockListNode and BasicBlockList
1362- // compiler->FreeBlockListNode(listNode);
1363- }
1364-
13651131// Initialize the block order for allocation (called each time a new traversal begins).
13661132BasicBlock* LinearScan::startBlockSequence()
13671133{
0 commit comments