@@ -4459,7 +4459,8 @@ bool Compiler::fgReorderBlocks(bool useProfile)
4459
4459
// Returns:
4460
4460
// True if 'right' should be considered before 'left', and false otherwise
4461
4461
//
4462
- /* static */ bool Compiler::ThreeOptLayout::EdgeCmp (const FlowEdge* left, const FlowEdge* right)
4462
+ template <bool hasEH>
4463
+ /* static */ bool Compiler::ThreeOptLayout<hasEH>::EdgeCmp(const FlowEdge* left, const FlowEdge* right)
4463
4464
{
4464
4465
assert (left != right);
4465
4466
const weight_t leftWeight = left->getLikelyWeight ();
@@ -4494,7 +4495,8 @@ bool Compiler::fgReorderBlocks(bool useProfile)
4494
4495
// To save an allocation, we will reuse the DFS tree's underlying array for 'tempOrder'.
4495
4496
// This means we will trash the DFS tree.
4496
4497
//
4497
- Compiler::ThreeOptLayout::ThreeOptLayout (Compiler* comp, BasicBlock** initialLayout, unsigned numHotBlocks)
4498
+ template <bool hasEH>
4499
+ Compiler::ThreeOptLayout<hasEH>::ThreeOptLayout(Compiler* comp, BasicBlock** initialLayout, unsigned numHotBlocks)
4498
4500
: compiler(comp)
4499
4501
, cutPoints(comp->getAllocator (CMK_FlowEdge), &ThreeOptLayout::EdgeCmp)
4500
4502
, blockOrder(initialLayout)
@@ -4503,6 +4505,23 @@ Compiler::ThreeOptLayout::ThreeOptLayout(Compiler* comp, BasicBlock** initialLay
4503
4505
{
4504
4506
}
4505
4507
4508
+ // -----------------------------------------------------------------------------
4509
+ // Compiler::ThreeOptLayout::IsCandidateBlock: Determines if a block is being considered for reordering
4510
+ // by checking if it is in 'blockOrder'.
4511
+ //
4512
+ // Parameters:
4513
+ // block - the block to check
4514
+ //
4515
+ // Returns:
4516
+ // True if 'block' is in the set of candidate blocks, false otherwise
4517
+ //
4518
+ template <bool hasEH>
4519
+ bool Compiler::ThreeOptLayout<hasEH>::IsCandidateBlock(BasicBlock* block) const
4520
+ {
4521
+ assert (block != nullptr );
4522
+ return (block->bbPreorderNum < numCandidateBlocks) && (blockOrder[block->bbPreorderNum ] == block);
4523
+ }
4524
+
4506
4525
#ifdef DEBUG
4507
4526
// -----------------------------------------------------------------------------
4508
4527
// Compiler::ThreeOptLayout::GetLayoutCost: Computes the cost of the layout for the region
@@ -4515,7 +4534,8 @@ Compiler::ThreeOptLayout::ThreeOptLayout(Compiler* comp, BasicBlock** initialLay
4515
4534
// Returns:
4516
4535
// The region's layout cost
4517
4536
//
4518
- weight_t Compiler::ThreeOptLayout::GetLayoutCost (unsigned startPos, unsigned endPos)
4537
+ template <bool hasEH>
4538
+ weight_t Compiler::ThreeOptLayout<hasEH>::GetLayoutCost(unsigned startPos, unsigned endPos)
4519
4539
{
4520
4540
assert (startPos <= endPos);
4521
4541
assert (endPos < numCandidateBlocks);
@@ -4542,7 +4562,8 @@ weight_t Compiler::ThreeOptLayout::GetLayoutCost(unsigned startPos, unsigned end
4542
4562
// Returns:
4543
4563
// The cost
4544
4564
//
4545
- weight_t Compiler::ThreeOptLayout::GetCost (BasicBlock* block, BasicBlock* next)
4565
+ template <bool hasEH>
4566
+ weight_t Compiler::ThreeOptLayout<hasEH>::GetCost(BasicBlock* block, BasicBlock* next)
4546
4567
{
4547
4568
assert (block != nullptr );
4548
4569
assert (next != nullptr );
@@ -4574,10 +4595,11 @@ weight_t Compiler::ThreeOptLayout::GetCost(BasicBlock* block, BasicBlock* next)
4574
4595
// The difference in cost between the current and proposed layouts.
4575
4596
// A negative delta indicates the proposed layout is an improvement.
4576
4597
//
4577
- weight_t Compiler::ThreeOptLayout::GetPartitionCostDelta (unsigned s2Start,
4578
- unsigned s3Start,
4579
- unsigned s3End,
4580
- unsigned s4End)
4598
+ template <bool hasEH>
4599
+ weight_t Compiler::ThreeOptLayout<hasEH>::GetPartitionCostDelta(unsigned s2Start,
4600
+ unsigned s3Start,
4601
+ unsigned s3End,
4602
+ unsigned s4End)
4581
4603
{
4582
4604
BasicBlock* const s2Block = blockOrder[s2Start];
4583
4605
BasicBlock* const s2BlockPrev = blockOrder[s2Start - 1 ];
@@ -4632,7 +4654,8 @@ weight_t Compiler::ThreeOptLayout::GetPartitionCostDelta(unsigned s2Start,
4632
4654
//
4633
4655
// If 's3End' and 's4End' are the same, the fourth partition doesn't exist.
4634
4656
//
4635
- void Compiler::ThreeOptLayout::SwapPartitions (
4657
+ template <bool hasEH>
4658
+ void Compiler::ThreeOptLayout<hasEH>::SwapPartitions(
4636
4659
unsigned s1Start, unsigned s2Start, unsigned s3Start, unsigned s3End, unsigned s4End)
4637
4660
{
4638
4661
INDEBUG (const weight_t currLayoutCost = GetLayoutCost (s1Start, s4End));
@@ -4691,13 +4714,14 @@ void Compiler::ThreeOptLayout::SwapPartitions(
4691
4714
// Returns:
4692
4715
// True if 'edge' can be considered for aligning, false otherwise
4693
4716
//
4717
+ template <bool hasEH>
4694
4718
template <bool addToQueue>
4695
- bool Compiler::ThreeOptLayout::ConsiderEdge (FlowEdge* edge)
4719
+ bool Compiler::ThreeOptLayout<hasEH> ::ConsiderEdge(FlowEdge* edge)
4696
4720
{
4697
4721
assert (edge != nullptr );
4698
4722
4699
- // Don't add an edge that we've already considered
4700
- // ( For exceptionally branchy methods, we want to avoid exploding 'cutPoints' in size)
4723
+ // Don't add an edge that we've already considered.
4724
+ // For exceptionally branchy methods, we want to avoid exploding 'cutPoints' in size.
4701
4725
if (addToQueue && edge->visited ())
4702
4726
{
4703
4727
return false ;
@@ -4706,45 +4730,26 @@ bool Compiler::ThreeOptLayout::ConsiderEdge(FlowEdge* edge)
4706
4730
BasicBlock* const srcBlk = edge->getSourceBlock ();
4707
4731
BasicBlock* const dstBlk = edge->getDestinationBlock ();
4708
4732
4709
- // Ignore cross-region branches
4710
- if (!BasicBlock::sameTryRegion (srcBlk, dstBlk))
4733
+ // Don't consider edges to or from outside the hot range.
4734
+ if (!IsCandidateBlock (srcBlk) || ! IsCandidateBlock ( dstBlk))
4711
4735
{
4712
4736
return false ;
4713
4737
}
4714
4738
4715
- // For backward jumps, we will consider partitioning before 'srcBlk'.
4716
- // If 'srcBlk' is a BBJ_CALLFINALLYRET, this partition will split up a call-finally pair.
4717
- // Thus, don't consider edges out of BBJ_CALLFINALLYRET blocks.
4718
- if (srcBlk->KindIs (BBJ_CALLFINALLYRET))
4739
+ // Don't consider single-block loop backedges.
4740
+ if (srcBlk == dstBlk)
4719
4741
{
4720
4742
return false ;
4721
4743
}
4722
4744
4723
- const unsigned srcPos = srcBlk->bbPreorderNum ;
4724
- const unsigned dstPos = dstBlk->bbPreorderNum ;
4725
- assert (srcPos < compiler->m_dfsTree ->GetPostOrderCount ());
4726
- assert (dstPos < compiler->m_dfsTree ->GetPostOrderCount ());
4727
-
4728
- // Don't consider edges to or from outside the hot range (i.e. ordinal doesn't match 'blockOrder' position).
4729
- if ((srcPos >= numCandidateBlocks) || (srcBlk != blockOrder[srcPos]))
4730
- {
4731
- return false ;
4732
- }
4733
-
4734
- if ((dstPos >= numCandidateBlocks) || (dstBlk != blockOrder[dstPos]))
4745
+ // Don't move the method entry block.
4746
+ if (dstBlk->IsFirst ())
4735
4747
{
4736
4748
return false ;
4737
4749
}
4738
4750
4739
- // Don't consider edges to blocks outside the hot range (i.e. ordinal number isn't set),
4740
- // or backedges to the first block in a region; we don't want to change the entry point.
4741
- if ((dstPos == 0 ) || compiler->bbIsTryBeg (dstBlk))
4742
- {
4743
- return false ;
4744
- }
4745
-
4746
- // Don't consider backedges for single-block loops
4747
- if (srcPos == dstPos)
4751
+ // Ignore cross-region branches, and don't try to change the region's entry block.
4752
+ if (hasEH && (!BasicBlock::sameTryRegion (srcBlk, dstBlk) || compiler->bbIsTryBeg (dstBlk)))
4748
4753
{
4749
4754
return false ;
4750
4755
}
@@ -4765,7 +4770,8 @@ bool Compiler::ThreeOptLayout::ConsiderEdge(FlowEdge* edge)
4765
4770
// Parameters:
4766
4771
// blockPos - The index into 'blockOrder' of the source block
4767
4772
//
4768
- void Compiler::ThreeOptLayout::AddNonFallthroughSuccs (unsigned blockPos)
4773
+ template <bool hasEH>
4774
+ void Compiler::ThreeOptLayout<hasEH>::AddNonFallthroughSuccs(unsigned blockPos)
4769
4775
{
4770
4776
assert (blockPos < numCandidateBlocks);
4771
4777
BasicBlock* const block = blockOrder[blockPos];
@@ -4787,7 +4793,8 @@ void Compiler::ThreeOptLayout::AddNonFallthroughSuccs(unsigned blockPos)
4787
4793
// Parameters:
4788
4794
// blockPos - The index into 'blockOrder' of the target block
4789
4795
//
4790
- void Compiler::ThreeOptLayout::AddNonFallthroughPreds (unsigned blockPos)
4796
+ template <bool hasEH>
4797
+ void Compiler::ThreeOptLayout<hasEH>::AddNonFallthroughPreds(unsigned blockPos)
4791
4798
{
4792
4799
assert (blockPos < numCandidateBlocks);
4793
4800
BasicBlock* const block = blockOrder[blockPos];
@@ -4809,7 +4816,8 @@ void Compiler::ThreeOptLayout::AddNonFallthroughPreds(unsigned blockPos)
4809
4816
// Returns:
4810
4817
// True if any blocks were moved
4811
4818
//
4812
- bool Compiler::ThreeOptLayout::Run ()
4819
+ template <bool hasEH>
4820
+ bool Compiler::ThreeOptLayout<hasEH>::Run()
4813
4821
{
4814
4822
assert (numCandidateBlocks > 0 );
4815
4823
RunThreeOpt ();
@@ -4834,7 +4842,8 @@ bool Compiler::ThreeOptLayout::Run()
4834
4842
// and try to create fallthrough on each edge via partition swaps, starting with the hottest edges.
4835
4843
// For each swap, repopulate the priority queue with edges along the modified cut points.
4836
4844
//
4837
- bool Compiler::ThreeOptLayout::RunGreedyThreeOptPass (unsigned startPos, unsigned endPos)
4845
+ template <bool hasEH>
4846
+ bool Compiler::ThreeOptLayout<hasEH>::RunGreedyThreeOptPass(unsigned startPos, unsigned endPos)
4838
4847
{
4839
4848
assert (cutPoints.Empty ());
4840
4849
assert (startPos < endPos);
@@ -4952,7 +4961,7 @@ bool Compiler::ThreeOptLayout::RunGreedyThreeOptPass(unsigned startPos, unsigned
4952
4961
BasicBlock* const s3BlockPrev = blockOrder[position - 1 ];
4953
4962
4954
4963
// Don't consider any cut points that would break up call-finally pairs
4955
- if (s3Block->KindIs (BBJ_CALLFINALLYRET))
4964
+ if (hasEH && s3Block->KindIs (BBJ_CALLFINALLYRET))
4956
4965
{
4957
4966
continue ;
4958
4967
}
@@ -5012,7 +5021,8 @@ bool Compiler::ThreeOptLayout::RunGreedyThreeOptPass(unsigned startPos, unsigned
5012
5021
// -----------------------------------------------------------------------------
5013
5022
// Compiler::ThreeOptLayout::RunThreeOpt: Runs 3-opt on the candidate span of blocks.
5014
5023
//
5015
- void Compiler::ThreeOptLayout::RunThreeOpt ()
5024
+ template <bool hasEH>
5025
+ void Compiler::ThreeOptLayout<hasEH>::RunThreeOpt()
5016
5026
{
5017
5027
// For methods with fewer than three candidate blocks, we cannot partition anything
5018
5028
if (numCandidateBlocks < 3 )
@@ -5047,28 +5057,47 @@ void Compiler::ThreeOptLayout::RunThreeOpt()
5047
5057
// Returns:
5048
5058
// True if any blocks were moved
5049
5059
//
5050
- bool Compiler::ThreeOptLayout::ReorderBlockList ()
5060
+ template <bool hasEH>
5061
+ bool Compiler::ThreeOptLayout<hasEH>::ReorderBlockList()
5051
5062
{
5052
5063
// As we reorder blocks, remember the last candidate block we found in each region.
5053
5064
// In case we cannot place two blocks next to each other because they are in different regions,
5054
5065
// we will instead place the latter block after the last one we saw in its region.
5055
5066
// This ensures cold blocks sink to the end of their respective regions.
5056
5067
// This will also push nested regions further down the method, but we will move them later, anyway.
5057
- BasicBlock** const lastHotBlocks = new (compiler, CMK_BasicBlock) BasicBlock* [compiler->compHndBBtabCount + 1 ] {};
5058
- lastHotBlocks[0 ] = compiler->fgFirstBB ;
5068
+ BasicBlock** lastHotBlocks = nullptr ;
5059
5069
5060
- for (EHblkDsc* const HBtab : EHClauses (compiler) )
5070
+ if (hasEH )
5061
5071
{
5062
- lastHotBlocks[HBtab->ebdTryBeg ->bbTryIndex ] = HBtab->ebdTryBeg ;
5072
+ lastHotBlocks = new (compiler, CMK_BasicBlock) BasicBlock* [compiler->compHndBBtabCount + 1 ] {};
5073
+ lastHotBlocks[0 ] = compiler->fgFirstBB ;
5074
+
5075
+ for (EHblkDsc* const HBtab : EHClauses (compiler))
5076
+ {
5077
+ lastHotBlocks[HBtab->ebdTryBeg ->bbTryIndex ] = HBtab->ebdTryBeg ;
5078
+ }
5063
5079
}
5064
5080
5065
5081
// Reorder the block list.
5066
5082
JITDUMP (" Reordering block list\n " );
5067
5083
bool modified = false ;
5068
5084
for (unsigned i = 1 ; i < numCandidateBlocks; i++)
5069
5085
{
5070
- BasicBlock* const block = blockOrder[i - 1 ];
5071
- BasicBlock* const blockToMove = blockOrder[i];
5086
+ BasicBlock* const block = blockOrder[i - 1 ];
5087
+ BasicBlock* const blockToMove = blockOrder[i];
5088
+
5089
+ if (!hasEH)
5090
+ {
5091
+ if (!block->NextIs (blockToMove))
5092
+ {
5093
+ compiler->fgUnlinkBlock (blockToMove);
5094
+ compiler->fgInsertBBafter (block, blockToMove);
5095
+ modified = true ;
5096
+ }
5097
+
5098
+ continue ;
5099
+ }
5100
+
5072
5101
lastHotBlocks[block->bbTryIndex ] = block;
5073
5102
5074
5103
// Don't move call-finally pair tails independently.
@@ -5121,7 +5150,7 @@ bool Compiler::ThreeOptLayout::ReorderBlockList()
5121
5150
}
5122
5151
}
5123
5152
5124
- if (compiler-> compHndBBtabCount == 0 )
5153
+ if (!hasEH )
5125
5154
{
5126
5155
return modified;
5127
5156
}
@@ -5141,8 +5170,7 @@ bool Compiler::ThreeOptLayout::ReorderBlockList()
5141
5170
// If this try region isn't in the candidate span of blocks, don't consider it.
5142
5171
// Also, if this try region's entry is also the method entry, don't move it.
5143
5172
BasicBlock* const tryBeg = HBtab->ebdTryBeg ;
5144
- if ((tryBeg->bbPreorderNum >= numCandidateBlocks) || (blockOrder[tryBeg->bbPreorderNum ] != tryBeg) ||
5145
- tryBeg->IsFirst ())
5173
+ if (!IsCandidateBlock (tryBeg) || tryBeg->IsFirst ())
5146
5174
{
5147
5175
continue ;
5148
5176
}
@@ -5190,17 +5218,14 @@ bool Compiler::ThreeOptLayout::ReorderBlockList()
5190
5218
// Compiler::ThreeOptLayout::CompactHotJumps: Move blocks in the candidate span
5191
5219
// closer to their most-likely successors.
5192
5220
//
5193
- void Compiler::ThreeOptLayout::CompactHotJumps ()
5221
+ template <bool hasEH>
5222
+ void Compiler::ThreeOptLayout<hasEH>::CompactHotJumps()
5194
5223
{
5195
5224
JITDUMP (" Compacting hot jumps\n " );
5196
5225
5197
- auto isCandidateBlock = [this ](BasicBlock* block) {
5198
- return (block->bbPreorderNum < numCandidateBlocks) && (blockOrder[block->bbPreorderNum ] == block);
5199
- };
5200
-
5201
5226
auto isBackwardJump = [&](BasicBlock* block, BasicBlock* target) {
5202
- assert (isCandidateBlock (block));
5203
- assert (isCandidateBlock (target));
5227
+ assert (IsCandidateBlock (block));
5228
+ assert (IsCandidateBlock (target));
5204
5229
return block->bbPreorderNum >= target->bbPreorderNum ;
5205
5230
};
5206
5231
@@ -5232,7 +5257,7 @@ void Compiler::ThreeOptLayout::CompactHotJumps()
5232
5257
// If we aren't sure which successor is hotter, and we already fall into one of them,
5233
5258
// do nothing.
5234
5259
BasicBlock* const unlikelyTarget = unlikelyEdge->getDestinationBlock ();
5235
- if ((unlikelyEdge->getLikelihood () == 0.5 ) && isCandidateBlock (unlikelyTarget) &&
5260
+ if ((unlikelyEdge->getLikelihood () == 0.5 ) && IsCandidateBlock (unlikelyTarget) &&
5236
5261
(unlikelyTarget->bbPreorderNum == (i + 1 )))
5237
5262
{
5238
5263
continue ;
@@ -5401,14 +5426,19 @@ PhaseStatus Compiler::fgSearchImprovedLayout()
5401
5426
}
5402
5427
5403
5428
bool modified = false ;
5404
- if (numHotBlocks > 0 )
5429
+ if (numHotBlocks == 0 )
5405
5430
{
5406
- ThreeOptLayout layoutRunner (this , initialLayout, numHotBlocks);
5431
+ JITDUMP (" No hot blocks found. Skipping reordering.\n " );
5432
+ }
5433
+ else if (compHndBBtabCount == 0 )
5434
+ {
5435
+ ThreeOptLayout</* hasEH */ false > layoutRunner (this , initialLayout, numHotBlocks);
5407
5436
modified = layoutRunner.Run ();
5408
5437
}
5409
5438
else
5410
5439
{
5411
- JITDUMP (" No hot blocks found. Skipping reordering.\n " );
5440
+ ThreeOptLayout</* hasEH */ true > layoutRunner (this , initialLayout, numHotBlocks);
5441
+ modified = layoutRunner.Run ();
5412
5442
}
5413
5443
5414
5444
// 3-opt will mess with post-order numbers regardless of whether it modifies anything,
0 commit comments