@@ -1117,43 +1117,39 @@ PhaseStatus Compiler::TransformAsync()
11171117PhaseStatus AsyncTransformation::Run ()
11181118{
11191119 PhaseStatus result = PhaseStatus::MODIFIED_NOTHING ;
1120- ArrayStack<BasicBlock*> worklist (m_compiler->getAllocator (CMK_Async));
1120+ ArrayStack<BasicBlock*> blocksWithNormalAwaits (m_compiler->getAllocator (CMK_Async));
1121+ ArrayStack<BasicBlock*> blocksWithTailAwaits (m_compiler->getAllocator (CMK_Async));
1122+ int numNormalAwaits = 0 ;
1123+ int numTailAwaits = 0 ;
1124+ FindAwaits (blocksWithNormalAwaits, blocksWithTailAwaits, &numNormalAwaits, &numTailAwaits);
11211125
1122- // First find all basic blocks with awaits in them. We'll have to track
1123- // liveness in these basic blocks, so it does not help to record the calls
1124- // ahead of time.
1125- BasicBlock* nextBlock;
1126- for (BasicBlock* block = m_compiler->fgFirstBB ; block != nullptr ; block = nextBlock)
1126+ if (numNormalAwaits + numTailAwaits > 1 )
11271127 {
1128- bool hasAwait = false ;
1129- nextBlock = block->Next ();
1130- for (GenTree* tree : LIR::AsRange (block))
1131- {
1132- if (!tree->IsCall () || !tree->AsCall ()->IsAsync () || tree->AsCall ()->IsTailCall ())
1133- {
1134- continue ;
1135- }
1136-
1137- if (tree->AsCall ()->GetAsyncInfo ().IsTailAwait )
1138- {
1139- TransformTailAwait (block, tree->AsCall (), &nextBlock);
1140- result = PhaseStatus::MODIFIED_EVERYTHING ;
1141- break ;
1142- }
1143-
1144- JITDUMP (FMT_BB " contains await(s)\n " , block->bbNum );
1145- hasAwait = true ;
1146- }
1128+ CreateSharedReturnBB ();
1129+ }
11471130
1148- if (hasAwait)
1131+ // Transform all tail awaits first. They will not require running all of
1132+ // our analyses.
1133+ if (numTailAwaits > 0 )
1134+ {
1135+ JITDUMP (" Found %d tail awaits in %d blocks\n " , numTailAwaits, blocksWithTailAwaits.Height ());
1136+ TransformTailAwaits (blocksWithTailAwaits);
1137+ if (numNormalAwaits > 0 )
11491138 {
1150- worklist.Push (block);
1139+ blocksWithNormalAwaits.Reset ();
1140+ blocksWithTailAwaits.Reset ();
1141+ numNormalAwaits = 0 ;
1142+ numTailAwaits = 0 ;
1143+ FindAwaits (blocksWithNormalAwaits, blocksWithTailAwaits, &numNormalAwaits, &numTailAwaits);
1144+ assert ((numTailAwaits == 0 ) && (blocksWithTailAwaits.Height () == 0 ));
11511145 }
1146+
1147+ result = PhaseStatus::MODIFIED_EVERYTHING ;
11521148 }
11531149
1154- JITDUMP (" Found %d blocks with awaits \n " , worklist .Height ());
1150+ JITDUMP (" Found %d awaits in %d blocks \n " , numNormalAwaits, blocksWithNormalAwaits .Height ());
11551151
1156- if (worklist. Height () <= 0 )
1152+ if (numNormalAwaits <= 0 )
11571153 {
11581154 return result;
11591155 }
@@ -1165,9 +1161,6 @@ PhaseStatus AsyncTransformation::Run()
11651161
11661162 m_asyncInfo = m_compiler->eeGetAsyncInfo ();
11671163
1168- // Create the shared return BB now to put it in the right place in the block order.
1169- GetSharedReturnBB ();
1170-
11711164 // Compute liveness to be used for determining what must be captured on
11721165 // suspension.
11731166 if (m_compiler->m_dfsTree == nullptr )
@@ -1189,11 +1182,11 @@ PhaseStatus AsyncTransformation::Run()
11891182 // async calls are additional live variables that must be spilled.
11901183 jitstd::vector<GenTree*> defs (m_compiler->getAllocator (CMK_Async));
11911184
1192- for (int i = 0 ; i < worklist .Height (); i++)
1185+ for (int i = 0 ; i < blocksWithNormalAwaits .Height (); i++)
11931186 {
11941187 assert (defs.size () == 0 );
11951188
1196- BasicBlock* block = worklist .Bottom (i);
1189+ BasicBlock* block = blocksWithNormalAwaits .Bottom (i);
11971190 liveness.StartBlock (block);
11981191
11991192 bool any;
@@ -1294,6 +1287,88 @@ PhaseStatus AsyncTransformation::Run()
12941287 return PhaseStatus::MODIFIED_EVERYTHING ;
12951288}
12961289
1290+ // ------------------------------------------------------------------------
1291+ // AsyncTransformation::FindAwaits:
1292+ // Find the blocks that have awaits in them and do some accounting of how
1293+ // many awaits there are.
1294+ //
1295+ // Parameters:
1296+ // blocksWithNormalAwaits - [out] Blocks with normal awaits are pushed onto this stack
1297+ // blocksWithTailAwaits - [out] Blocks with tail awaits are pushed onto this stack
1298+ // numNormalAwaits - [out] Number of normal awaits found
1299+ // numTailAwaits - [out] Number of tail awaits found
1300+ //
1301+ void AsyncTransformation::FindAwaits (ArrayStack<BasicBlock*>& blocksWithNormalAwaits,
1302+ ArrayStack<BasicBlock*>& blocksWithTailAwaits,
1303+ int * numNormalAwaits,
1304+ int * numTailAwaits)
1305+ {
1306+ for (BasicBlock* block : m_compiler->Blocks ())
1307+ {
1308+ bool hasNormalAwait = false ;
1309+ bool hasTailAwait = false ;
1310+ for (GenTree* tree : LIR::AsRange (block))
1311+ {
1312+ if (!tree->IsCall () || !tree->AsCall ()->IsAsync () || tree->AsCall ()->IsTailCall ())
1313+ {
1314+ continue ;
1315+ }
1316+
1317+ if (tree->AsCall ()->GetAsyncInfo ().IsTailAwait )
1318+ {
1319+ hasTailAwait = true ;
1320+ (*numTailAwaits)++;
1321+ }
1322+ else
1323+ {
1324+ hasNormalAwait = true ;
1325+ (*numNormalAwaits)++;
1326+ }
1327+ }
1328+
1329+ if (hasNormalAwait)
1330+ {
1331+ blocksWithNormalAwaits.Push (block);
1332+ }
1333+
1334+ if (hasTailAwait)
1335+ {
1336+ blocksWithTailAwaits.Push (block);
1337+ }
1338+ }
1339+ }
1340+
1341+ // ------------------------------------------------------------------------
1342+ // AsyncTransformation::TransformTailAwaits:
1343+ // Transform all tail awaits in the specified blocks.
1344+ //
1345+ // Parameters:
1346+ // blocksWithTailAwaits - Blocks containing tail awaits
1347+ //
1348+ void AsyncTransformation::TransformTailAwaits (ArrayStack<BasicBlock*>& blocksWithTailAwaits)
1349+ {
1350+ for (int i = 0 ; i < blocksWithTailAwaits.Height (); i++)
1351+ {
1352+ BasicBlock* block = blocksWithTailAwaits.Bottom (i);
1353+
1354+ bool any;
1355+ do
1356+ {
1357+ any = false ;
1358+ for (GenTree* tree : LIR::AsRange (block))
1359+ {
1360+ if (tree->IsCall () && tree->AsCall ()->IsAsync () && !tree->AsCall ()->IsTailCall () &&
1361+ tree->AsCall ()->GetAsyncInfo ().IsTailAwait )
1362+ {
1363+ TransformTailAwait (block, tree->AsCall (), &block);
1364+ any = true ;
1365+ break ;
1366+ }
1367+ }
1368+ } while (any);
1369+ }
1370+ }
1371+
12971372// ------------------------------------------------------------------------
12981373// AsyncTransformation::TransformTailAwait:
12991374// Transform an await that was marked as a tail await.
@@ -1328,7 +1403,7 @@ void AsyncTransformation::TransformTailAwait(BasicBlock* block, GenTreeCall* cal
13281403//
13291404BasicBlock* AsyncTransformation::CreateTailAwaitSuspension (BasicBlock* block, GenTreeCall* call)
13301405{
1331- BasicBlock* sharedReturnBB = GetSharedReturnBB () ;
1406+ BasicBlock* sharedReturnBB = m_sharedReturnBB ;
13321407
13331408 if (m_lastSuspensionBB == nullptr )
13341409 {
@@ -3173,21 +3248,11 @@ unsigned AsyncTransformation::GetExceptionVar()
31733248}
31743249
31753250// ------------------------------------------------------------------------
3176- // AsyncTransformation::GetSharedReturnBB:
3177- // Create the shared return BB, if one is needed.
3178- //
3179- // Returns:
3180- // Basic block or nullptr.
3251+ // AsyncTransformation::CreateSharedReturnBB:
3252+ // Create the shared return BB.
31813253//
3182- BasicBlock* AsyncTransformation::GetSharedReturnBB ()
3254+ void AsyncTransformation::CreateSharedReturnBB ()
31833255{
3184- #ifdef JIT32_GCENCODER
3185- if (m_sharedReturnBB != nullptr )
3186- {
3187- return m_sharedReturnBB;
3188- }
3189-
3190- // Due to a hard cap on epilogs we need a shared return here.
31913256 m_sharedReturnBB = m_compiler->fgNewBBafter (BBJ_RETURN , m_compiler->fgLastBBInMainFunction (), false );
31923257 m_sharedReturnBB->bbSetRunRarely ();
31933258 m_sharedReturnBB->clearTryIndex ();
@@ -3207,10 +3272,6 @@ BasicBlock* AsyncTransformation::GetSharedReturnBB()
32073272 JITDUMP (" Created shared return BB " FMT_BB " \n " , m_sharedReturnBB->bbNum );
32083273
32093274 DISPRANGE (LIR::AsRange (m_sharedReturnBB));
3210- return m_sharedReturnBB;
3211- #else
3212- return nullptr ;
3213- #endif
32143275}
32153276
32163277// ------------------------------------------------------------------------
0 commit comments