@@ -4538,114 +4538,198 @@ bool Compiler::fgReorderBlocks(bool useProfile)
4538
4538
#endif
4539
4539
4540
4540
// -----------------------------------------------------------------------------
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 .
4542
4542
//
4543
4543
// Template parameters:
4544
4544
// hasEH - If true, method has EH regions, so check that we don't try to move blocks in different regions
4545
4545
//
4546
4546
template <bool hasEH>
4547
- void Compiler::fgMoveBackwardJumpsToSuccessors ()
4547
+ void Compiler::fgMoveHotJumps ()
4548
4548
{
4549
4549
#ifdef DEBUG
4550
4550
if (verbose)
4551
4551
{
4552
- printf (" *************** In fgMoveBackwardJumpsToSuccessors ()\n " );
4552
+ printf (" *************** In fgMoveHotJumps ()\n " );
4553
4553
4554
4554
printf (" \n Initial BasicBlocks" );
4555
4555
fgDispBasicBlocks (verboseTrees);
4556
4556
printf (" \n " );
4557
4557
}
4558
4558
#endif // DEBUG
4559
4559
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.
4562
4565
//
4563
- for (BasicBlock* block = fgFirstBB; block != fgFirstFuncletBB;)
4566
+ BasicBlock* next;
4567
+ for (BasicBlock* block = fgFirstBB; block != fgFirstFuncletBB; block = next)
4564
4568
{
4565
4569
if (fgCanCompactBlocks (block, block->Next ()))
4566
4570
{
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.
4568
4574
//
4569
4575
fgCompactBlocks (block, block->Next () DEBUGARG (/* doDebugCheck */ false ));
4576
+ next = block;
4577
+ continue ;
4570
4578
}
4571
- else
4572
- {
4573
- block = block->Next ();
4574
- }
4575
- }
4576
4579
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
- {
4587
4580
next = block->Next ();
4588
4581
BlockSetOps::AddElemD (this , visitedBlocks, block->bbNum );
4589
4582
4590
4583
// Don't bother trying to move cold blocks
4591
4584
//
4592
- if (! block->KindIs (BBJ_ALWAYS) || block-> isRunRarely ( ))
4585
+ if (block->isBBWeightCold ( this ))
4593
4586
{
4594
4587
continue ;
4595
4588
}
4596
4589
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))
4601
4599
{
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
+ //
4602
4617
continue ;
4603
4618
}
4604
4619
4605
- if (hasEH)
4620
+ BasicBlock* target = targetEdge->getDestinationBlock ();
4621
+ bool isBackwardJump = BlockSetOps::IsMember (this , visitedBlocks, target->bbNum );
4622
+
4623
+ if (isBackwardJump)
4606
4624
{
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.
4608
4627
//
4609
- if (! BasicBlock::sameEHRegion (block, target))
4628
+ if (target-> IsFirst ( ))
4610
4629
{
4611
4630
continue ;
4612
4631
}
4613
4632
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 );
4618
4641
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
4620
4648
//
4621
- if (bbIsTryBeg (target) || bbIsHandlerBeg ( target) )
4649
+ else if (block == target)
4622
4650
{
4623
4651
continue ;
4624
4652
}
4625
4653
}
4626
4654
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
4630
4656
//
4631
- if (target-> IsFirst () || target-> isRunRarely ( ))
4657
+ if (block-> NextIs ( target))
4632
4658
{
4633
4659
continue ;
4634
4660
}
4635
4661
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
+
4636
4702
// If moving block will break up existing fallthrough behavior into target, make sure it's worth it
4637
4703
//
4638
4704
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 ()))
4641
4706
{
4642
4707
continue ;
4643
4708
}
4644
4709
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
+ }
4649
4733
}
4650
4734
}
4651
4735
@@ -4681,12 +4765,7 @@ void Compiler::fgDoReversePostOrderLayout()
4681
4765
fgInsertBBafter (block, blockToMove);
4682
4766
}
4683
4767
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 >();
4690
4769
4691
4770
return ;
4692
4771
}
@@ -4775,7 +4854,7 @@ void Compiler::fgDoReversePostOrderLayout()
4775
4854
fgInsertBBafter (pair.callFinally , pair.callFinallyRet );
4776
4855
}
4777
4856
4778
- fgMoveBackwardJumpsToSuccessors </* hasEH */ true >();
4857
+ fgMoveHotJumps </* hasEH */ true >();
4779
4858
4780
4859
// The RPO won't change the entry blocks of any EH regions, but reordering can change the last block in a region
4781
4860
// (for example, by pushing throw blocks unreachable via normal flow to the end of the region).
0 commit comments