@@ -4538,114 +4538,198 @@ bool Compiler::fgReorderBlocks(bool useProfile)
45384538#endif
45394539
45404540// -----------------------------------------------------------------------------
4541- // fgMoveBackwardJumpsToSuccessors : Try to move backward unconditional jumps to fall into their successors.
4541+ // fgMoveHotJumps : Try to move jumps to fall into their successors, if the jump is sufficiently hot .
45424542//
45434543// Template parameters:
45444544// hasEH - If true, method has EH regions, so check that we don't try to move blocks in different regions
45454545//
45464546template <bool hasEH>
4547- void Compiler::fgMoveBackwardJumpsToSuccessors ()
4547+ void Compiler::fgMoveHotJumps ()
45484548{
45494549#ifdef DEBUG
45504550 if (verbose)
45514551 {
4552- printf (" *************** In fgMoveBackwardJumpsToSuccessors ()\n " );
4552+ printf (" *************** In fgMoveHotJumps ()\n " );
45534553
45544554 printf (" \n Initial BasicBlocks" );
45554555 fgDispBasicBlocks (verboseTrees);
45564556 printf (" \n " );
45574557 }
45584558#endif // DEBUG
45594559
4560- // Compact blocks before trying to move any jumps.
4561- // This can unlock more opportunities for fallthrough behavior.
4560+ EnsureBasicBlockEpoch ();
4561+ BlockSet visitedBlocks (BlockSetOps::MakeEmpty (this ));
4562+ BlockSetOps::AddElemD (this , visitedBlocks, fgFirstBB->bbNum );
4563+
4564+ // If we have a funclet region, don't bother reordering anything in it.
45624565 //
4563- for (BasicBlock* block = fgFirstBB; block != fgFirstFuncletBB;)
4566+ BasicBlock* next;
4567+ for (BasicBlock* block = fgFirstBB; block != fgFirstFuncletBB; block = next)
45644568 {
45654569 if (fgCanCompactBlocks (block, block->Next ()))
45664570 {
4567- // We haven't fixed EH information yet, so don't do any correctness checks here
4571+ // Compact blocks before trying to move any jumps.
4572+ // This can unlock more opportunities for fallthrough behavior.
4573+ // We haven't fixed EH information yet, so don't do any correctness checks here.
45684574 //
45694575 fgCompactBlocks (block, block->Next () DEBUGARG (/* doDebugCheck */ false ));
4576+ next = block;
4577+ continue ;
45704578 }
4571- else
4572- {
4573- block = block->Next ();
4574- }
4575- }
45764579
4577- EnsureBasicBlockEpoch ();
4578- BlockSet visitedBlocks (BlockSetOps::MakeEmpty (this ));
4579- BlockSetOps::AddElemD (this , visitedBlocks, fgFirstBB->bbNum );
4580-
4581- // Don't try to move the first block.
4582- // Also, if we have a funclet region, don't bother reordering anything in it.
4583- //
4584- BasicBlock* next;
4585- for (BasicBlock* block = fgFirstBB->Next (); block != fgFirstFuncletBB; block = next)
4586- {
45874580 next = block->Next ();
45884581 BlockSetOps::AddElemD (this , visitedBlocks, block->bbNum );
45894582
45904583 // Don't bother trying to move cold blocks
45914584 //
4592- if (! block->KindIs (BBJ_ALWAYS) || block-> isRunRarely ( ))
4585+ if (block->isBBWeightCold ( this ))
45934586 {
45944587 continue ;
45954588 }
45964589
4597- // We will consider moving only backward jumps
4598- //
4599- BasicBlock* const target = block->GetTarget ();
4600- if ((block == target) || !BlockSetOps::IsMember (this , visitedBlocks, target->bbNum ))
4590+ FlowEdge* targetEdge;
4591+ FlowEdge* unlikelyEdge;
4592+
4593+ if (block->KindIs (BBJ_ALWAYS))
4594+ {
4595+ targetEdge = block->GetTargetEdge ();
4596+ unlikelyEdge = nullptr ;
4597+ }
4598+ else if (block->KindIs (BBJ_COND))
46014599 {
4600+ // Consider conditional block's most likely branch for moving
4601+ //
4602+ if (block->GetTrueEdge ()->getLikelihood () > 0.5 )
4603+ {
4604+ targetEdge = block->GetTrueEdge ();
4605+ unlikelyEdge = block->GetFalseEdge ();
4606+ }
4607+ else
4608+ {
4609+ targetEdge = block->GetFalseEdge ();
4610+ unlikelyEdge = block->GetTrueEdge ();
4611+ }
4612+ }
4613+ else
4614+ {
4615+ // Don't consider other block kinds
4616+ //
46024617 continue ;
46034618 }
46044619
4605- if (hasEH)
4620+ BasicBlock* target = targetEdge->getDestinationBlock ();
4621+ bool isBackwardJump = BlockSetOps::IsMember (this , visitedBlocks, target->bbNum );
4622+
4623+ if (isBackwardJump)
46064624 {
4607- // Don't move blocks in different EH regions
4625+ // We don't want to change the first block, so if block is a backward jump to the first block,
4626+ // don't try moving block before it.
46084627 //
4609- if (! BasicBlock::sameEHRegion (block, target))
4628+ if (target-> IsFirst ( ))
46104629 {
46114630 continue ;
46124631 }
46134632
4614- // block and target are in the same try/handler regions, and target is behind block,
4615- // so block cannot possibly be the start of the region.
4616- //
4617- assert (!bbIsTryBeg (block) && !bbIsHandlerBeg (block));
4633+ if (block->KindIs (BBJ_COND))
4634+ {
4635+ // This could be a loop exit, so don't bother moving this block up.
4636+ // Instead, try moving the unlikely target up to create fallthrough.
4637+ //
4638+ targetEdge = unlikelyEdge;
4639+ target = targetEdge->getDestinationBlock ();
4640+ isBackwardJump = BlockSetOps::IsMember (this , visitedBlocks, target->bbNum );
46184641
4619- // Don't change the entry block of an EH region
4642+ if (isBackwardJump)
4643+ {
4644+ continue ;
4645+ }
4646+ }
4647+ // Check for single-block loop case
46204648 //
4621- if (bbIsTryBeg (target) || bbIsHandlerBeg ( target) )
4649+ else if (block == target)
46224650 {
46234651 continue ;
46244652 }
46254653 }
46264654
4627- // We don't want to change the first block, so if the jump target is the first block,
4628- // don't try moving this block before it.
4629- // Also, if the target is cold, don't bother moving this block up to it.
4655+ // Check if block already falls into target
46304656 //
4631- if (target-> IsFirst () || target-> isRunRarely ( ))
4657+ if (block-> NextIs ( target))
46324658 {
46334659 continue ;
46344660 }
46354661
4662+ if (target->isBBWeightCold (this ))
4663+ {
4664+ // If target is block's most-likely successor, and block is not rarely-run,
4665+ // perhaps the profile data is misleading, and we need to run profile repair?
4666+ //
4667+ continue ;
4668+ }
4669+
4670+ if (hasEH)
4671+ {
4672+ // Don't move blocks in different EH regions
4673+ //
4674+ if (!BasicBlock::sameEHRegion (block, target))
4675+ {
4676+ continue ;
4677+ }
4678+
4679+ if (isBackwardJump)
4680+ {
4681+ // block and target are in the same try/handler regions, and target is behind block,
4682+ // so block cannot possibly be the start of the region.
4683+ //
4684+ assert (!bbIsTryBeg (block) && !bbIsHandlerBeg (block));
4685+
4686+ // Don't change the entry block of an EH region
4687+ //
4688+ if (bbIsTryBeg (target) || bbIsHandlerBeg (target))
4689+ {
4690+ continue ;
4691+ }
4692+ }
4693+ else
4694+ {
4695+ // block and target are in the same try/handler regions, and block is behind target,
4696+ // so target cannot possibly be the start of the region.
4697+ //
4698+ assert (!bbIsTryBeg (target) && !bbIsHandlerBeg (target));
4699+ }
4700+ }
4701+
46364702 // If moving block will break up existing fallthrough behavior into target, make sure it's worth it
46374703 //
46384704 FlowEdge* const fallthroughEdge = fgGetPredForBlock (target, target->Prev ());
4639- if ((fallthroughEdge != nullptr ) &&
4640- (fallthroughEdge->getLikelyWeight () >= block->GetTargetEdge ()->getLikelyWeight ()))
4705+ if ((fallthroughEdge != nullptr ) && (fallthroughEdge->getLikelyWeight () >= targetEdge->getLikelyWeight ()))
46414706 {
46424707 continue ;
46434708 }
46444709
4645- // Move block to before target
4646- //
4647- fgUnlinkBlock (block);
4648- fgInsertBBbefore (target, block);
4710+ if (isBackwardJump)
4711+ {
4712+ // Move block to before target
4713+ //
4714+ fgUnlinkBlock (block);
4715+ fgInsertBBbefore (target, block);
4716+ }
4717+ else if (hasEH && target->isBBCallFinallyPair ())
4718+ {
4719+ // target is a call-finally pair, so move the pair up to block
4720+ //
4721+ fgUnlinkRange (target, target->Next ());
4722+ fgMoveBlocksAfter (target, target->Next (), block);
4723+ next = target->Next ();
4724+ }
4725+ else
4726+ {
4727+ // Move target up to block
4728+ //
4729+ fgUnlinkBlock (target);
4730+ fgInsertBBafter (block, target);
4731+ next = target;
4732+ }
46494733 }
46504734}
46514735
@@ -4681,12 +4765,7 @@ void Compiler::fgDoReversePostOrderLayout()
46814765 fgInsertBBafter (block, blockToMove);
46824766 }
46834767
4684- // The RPO established a good base layout, but in some cases, it might produce a subpar layout for loops.
4685- // In particular, it may place the loop head after the loop exit, creating unnecessary branches.
4686- // Fix this by moving unconditional backward jumps up to their targets,
4687- // increasing the likelihood that the loop exit block is the last block in the loop.
4688- //
4689- fgMoveBackwardJumpsToSuccessors</* hasEH */ false >();
4768+ fgMoveHotJumps</* hasEH */ false >();
46904769
46914770 return ;
46924771 }
@@ -4775,7 +4854,7 @@ void Compiler::fgDoReversePostOrderLayout()
47754854 fgInsertBBafter (pair.callFinally , pair.callFinallyRet );
47764855 }
47774856
4778- fgMoveBackwardJumpsToSuccessors </* hasEH */ true >();
4857+ fgMoveHotJumps </* hasEH */ true >();
47794858
47804859 // The RPO won't change the entry blocks of any EH regions, but reordering can change the last block in a region
47814860 // (for example, by pushing throw blocks unreachable via normal flow to the end of the region).
0 commit comments