@@ -5366,55 +5366,27 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
5366
5366
//
5367
5367
if (compCurBB->KindIs(BBJ_ALWAYS))
5368
5368
{
5369
+ BasicBlock* const curBlock = compCurBB;
5370
+ BasicBlock* const targetBlock = curBlock->GetTarget();
5371
+
5369
5372
// Flow no longer reaches the target from here.
5370
5373
//
5371
- fgRemoveRefPred(compCurBB ->GetTargetEdge());
5374
+ fgRemoveRefPred(curBlock ->GetTargetEdge());
5372
5375
5373
- // Adjust profile weights of the successor blocks .
5376
+ // Adjust profile weights of the successor block .
5374
5377
//
5375
5378
// Note if this is a tail call to loop, further updates
5376
5379
// are needed once we install the loop edge.
5377
5380
//
5378
- BasicBlock* curBlock = compCurBB;
5379
- if (curBlock->hasProfileWeight())
5381
+ if (curBlock->hasProfileWeight() && targetBlock->hasProfileWeight())
5380
5382
{
5381
- weight_t weightLoss = curBlock->bbWeight;
5382
- BasicBlock* nextBlock = curBlock->GetTarget();
5383
+ targetBlock->decreaseBBProfileWeight(curBlock->bbWeight);
5383
5384
5384
- while (nextBlock->hasProfileWeight() )
5385
+ if (targetBlock->NumSucc() > 0 )
5385
5386
{
5386
- // Since we have linear flow we can update the next block weight.
5387
- //
5388
- weight_t const nextWeight = nextBlock->bbWeight;
5389
- weight_t const newNextWeight = nextWeight - weightLoss;
5390
-
5391
- // If the math would result in a negative weight then there's
5392
- // no local repair we can do; just leave things inconsistent.
5393
- //
5394
- if (newNextWeight >= 0)
5395
- {
5396
- // Note if we'd already morphed the IR in nextblock we might
5397
- // have done something profile sensitive that we should arguably reconsider.
5398
- //
5399
- JITDUMP("Reducing profile weight of " FMT_BB " from " FMT_WT " to " FMT_WT "\n", nextBlock->bbNum,
5400
- nextWeight, newNextWeight);
5401
-
5402
- nextBlock->setBBProfileWeight(newNextWeight);
5403
- }
5404
- else
5405
- {
5406
- JITDUMP("Not reducing profile weight of " FMT_BB " as its weight " FMT_WT
5407
- " is less than direct flow pred " FMT_BB " weight " FMT_WT "\n",
5408
- nextBlock->bbNum, nextWeight, compCurBB->bbNum, weightLoss);
5409
- }
5410
-
5411
- if (!nextBlock->KindIs(BBJ_ALWAYS))
5412
- {
5413
- break;
5414
- }
5415
-
5416
- curBlock = nextBlock;
5417
- nextBlock = curBlock->GetTarget();
5387
+ JITDUMP("Flow removal out of " FMT_BB " needs to be propagated. Data %s inconsistent.\n",
5388
+ curBlock->bbNum, fgPgoConsistent ? "is now" : "was already");
5389
+ fgPgoConsistent = false;
5418
5390
}
5419
5391
}
5420
5392
}
@@ -6755,12 +6727,12 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
6755
6727
fgRemoveStmt(block, lastStmt);
6756
6728
6757
6729
// Set the loop edge.
6730
+ BasicBlock* entryBB;
6758
6731
if (opts.IsOSR())
6759
6732
{
6760
6733
// Todo: this may not look like a viable loop header.
6761
6734
// Might need the moral equivalent of an init BB.
6762
- FlowEdge* const newEdge = fgAddRefPred(fgEntryBB, block);
6763
- block->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
6735
+ entryBB = fgEntryBB;
6764
6736
}
6765
6737
else
6766
6738
{
@@ -6769,9 +6741,19 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
6769
6741
// TODO-Cleanup: We should really be expanding tailcalls into loops
6770
6742
// much earlier than this, at a place where we do not need to have
6771
6743
// hacky workarounds to figure out what the actual IL entry block is.
6772
- BasicBlock* firstILBB = fgGetFirstILBlock();
6773
- FlowEdge* const newEdge = fgAddRefPred(firstILBB, block);
6774
- block->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
6744
+ entryBB = fgGetFirstILBlock();
6745
+ }
6746
+
6747
+ FlowEdge* const newEdge = fgAddRefPred(entryBB, block);
6748
+ block->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
6749
+
6750
+ // Update profile
6751
+ if (block->hasProfileWeight() && entryBB->hasProfileWeight())
6752
+ {
6753
+ entryBB->increaseBBProfileWeight(block->bbWeight);
6754
+ JITDUMP("Flow into entry BB " FMT_BB " increased. Data %s inconsistent.\n", entryBB->bbNum,
6755
+ fgPgoConsistent ? "is now" : "was already");
6756
+ fgPgoConsistent = false;
6775
6757
}
6776
6758
6777
6759
// Finish hooking things up.
@@ -12741,24 +12723,38 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block)
12741
12723
// modify the flow graph
12742
12724
12743
12725
// Find the actual jump target
12744
- size_t switchVal = (size_t)cond->AsIntCon()->gtIconVal;
12745
- unsigned jumpCnt = block->GetSwitchTargets()->bbsCount;
12746
- FlowEdge** jumpTab = block->GetSwitchTargets()->bbsDstTab;
12747
- bool foundVal = false;
12726
+ size_t switchVal = (size_t)cond->AsIntCon()->gtIconVal;
12727
+ unsigned jumpCnt = block->GetSwitchTargets()->bbsCount;
12728
+ FlowEdge** jumpTab = block->GetSwitchTargets()->bbsDstTab;
12729
+ bool foundVal = false;
12730
+ bool profileInconsistent = false;
12748
12731
12749
12732
for (unsigned val = 0; val < jumpCnt; val++, jumpTab++)
12750
12733
{
12751
12734
FlowEdge* curEdge = *jumpTab;
12752
12735
12753
12736
assert(curEdge->getDestinationBlock()->countOfInEdges() > 0);
12754
12737
12738
+ BasicBlock* const targetBlock = curEdge->getDestinationBlock();
12739
+ if (block->hasProfileWeight() && targetBlock->hasProfileWeight())
12740
+ {
12741
+ targetBlock->decreaseBBProfileWeight(curEdge->getLikelyWeight());
12742
+ profileInconsistent |= (targetBlock->NumSucc() > 0);
12743
+ }
12744
+
12755
12745
// If val matches switchVal or we are at the last entry and
12756
12746
// we never found the switch value then set the new jump dest
12757
12747
12758
12748
if ((val == switchVal) || (!foundVal && (val == jumpCnt - 1)))
12759
12749
{
12760
12750
block->SetKindAndTargetEdge(BBJ_ALWAYS, curEdge);
12761
12751
foundVal = true;
12752
+
12753
+ if (block->hasProfileWeight() && targetBlock->hasProfileWeight())
12754
+ {
12755
+ targetBlock->increaseBBProfileWeight(block->bbWeight);
12756
+ profileInconsistent |= (targetBlock->NumSucc() > 0);
12757
+ }
12762
12758
}
12763
12759
else
12764
12760
{
@@ -12767,6 +12763,13 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block)
12767
12763
}
12768
12764
}
12769
12765
12766
+ if (profileInconsistent)
12767
+ {
12768
+ JITDUMP("Flow change out of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum,
12769
+ fgPgoConsistent ? "is now" : "was already");
12770
+ fgPgoConsistent = false;
12771
+ }
12772
+
12770
12773
assert(foundVal);
12771
12774
#ifdef DEBUG
12772
12775
if (verbose)
@@ -13408,6 +13411,11 @@ PhaseStatus Compiler::fgMorphBlocks()
13408
13411
//
13409
13412
fgGlobalMorph = true;
13410
13413
13414
+ if (fgPgoConsistent)
13415
+ {
13416
+ Metrics.ProfileConsistentBeforeMorph = 1;
13417
+ }
13418
+
13411
13419
if (opts.OptimizationEnabled())
13412
13420
{
13413
13421
// Local assertion prop is enabled if we are optimizing.
@@ -13505,6 +13513,25 @@ PhaseStatus Compiler::fgMorphBlocks()
13505
13513
fgEntryBB->bbRefs--;
13506
13514
fgEntryBBExtraRefs = 0;
13507
13515
13516
+ // The original method entry will now be checked for profile consistency.
13517
+ // If the entry has inconsistent incoming weight, flag the profile as inconsistent.
13518
+ //
13519
+ if (fgEntryBB->hasProfileWeight())
13520
+ {
13521
+ weight_t incomingWeight = BB_ZERO_WEIGHT;
13522
+ for (FlowEdge* const predEdge : fgEntryBB->PredEdges())
13523
+ {
13524
+ incomingWeight += predEdge->getLikelyWeight();
13525
+ }
13526
+
13527
+ if (!fgProfileWeightsConsistent(incomingWeight, fgEntryBB->bbWeight))
13528
+ {
13529
+ JITDUMP("OSR: Original method entry " FMT_BB " has inconsistent weight. Data %s inconsistent.\n",
13530
+ fgPgoConsistent ? "is now" : "was already");
13531
+ fgPgoConsistent = false;
13532
+ }
13533
+ }
13534
+
13508
13535
// We don't need to remember this block anymore.
13509
13536
fgEntryBB = nullptr;
13510
13537
}
@@ -13544,6 +13571,11 @@ PhaseStatus Compiler::fgMorphBlocks()
13544
13571
// may no longer be canonical.
13545
13572
fgCanonicalizeFirstBB();
13546
13573
13574
+ if (fgPgoConsistent)
13575
+ {
13576
+ Metrics.ProfileConsistentAfterMorph = 1;
13577
+ }
13578
+
13547
13579
INDEBUG(fgPostGlobalMorphChecks();)
13548
13580
13549
13581
return PhaseStatus::MODIFIED_EVERYTHING;
@@ -14263,6 +14295,15 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
14263
14295
BasicBlock* condBlock = fgNewBBafter(BBJ_ALWAYS, block, true);
14264
14296
BasicBlock* elseBlock = fgNewBBafter(BBJ_ALWAYS, condBlock, true);
14265
14297
14298
+ // Update flowgraph
14299
+ fgRedirectTargetEdge(block, condBlock);
14300
+ condBlock->SetTargetEdge(fgAddRefPred(elseBlock, condBlock));
14301
+ elseBlock->SetTargetEdge(fgAddRefPred(remainderBlock, elseBlock));
14302
+
14303
+ // Propagate flow from block into condBlock.
14304
+ // Leave flow out of remainderBlock intact, as it will post-dominate block.
14305
+ condBlock->inheritWeight(block);
14306
+
14266
14307
// These blocks are only internal if 'block' is (but they've been set as internal by fgNewBBafter).
14267
14308
// If they're not internal, mark them as imported to avoid asserts about un-imported blocks.
14268
14309
if (!block->HasFlag(BBF_INTERNAL))
@@ -14276,27 +14317,6 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
14276
14317
block->RemoveFlags(BBF_NEEDS_GCPOLL);
14277
14318
remainderBlock->SetFlags(propagateFlagsToRemainder | propagateFlagsToAll);
14278
14319
14279
- condBlock->inheritWeight(block);
14280
-
14281
- // Make sure remainderBlock gets exactly the same weight as block after split
14282
- assert(condBlock->bbWeight == remainderBlock->bbWeight);
14283
-
14284
- assert(block->KindIs(BBJ_ALWAYS));
14285
- fgRedirectTargetEdge(block, condBlock);
14286
-
14287
- {
14288
- FlowEdge* const newEdge = fgAddRefPred(elseBlock, condBlock);
14289
- condBlock->SetTargetEdge(newEdge);
14290
- }
14291
-
14292
- {
14293
- FlowEdge* const newEdge = fgAddRefPred(remainderBlock, elseBlock);
14294
- elseBlock->SetTargetEdge(newEdge);
14295
- }
14296
-
14297
- assert(condBlock->JumpsToNext());
14298
- assert(elseBlock->JumpsToNext());
14299
-
14300
14320
condBlock->SetFlags(propagateFlagsToAll);
14301
14321
elseBlock->SetFlags(propagateFlagsToAll);
14302
14322
@@ -14311,6 +14331,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
14311
14331
// +--->--------+
14312
14332
// bbj_cond(true)
14313
14333
//
14334
+ // TODO: Remove unnecessary condition reversal
14314
14335
gtReverseCond(condExpr);
14315
14336
14316
14337
thenBlock = fgNewBBafter(BBJ_ALWAYS, condBlock, true);
@@ -14324,13 +14345,12 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
14324
14345
const unsigned thenLikelihood = qmark->ThenNodeLikelihood();
14325
14346
const unsigned elseLikelihood = qmark->ElseNodeLikelihood();
14326
14347
14327
- FlowEdge* const newEdge = fgAddRefPred(remainderBlock, thenBlock);
14328
- thenBlock->SetTargetEdge(newEdge);
14348
+ thenBlock->SetTargetEdge(fgAddRefPred(remainderBlock, thenBlock));
14329
14349
14330
14350
assert(condBlock->TargetIs(elseBlock));
14331
- FlowEdge* const elseEdge = fgAddRefPred(thenBlock, condBlock);
14332
- FlowEdge* const thenEdge = condBlock->GetTargetEdge();
14333
- condBlock->SetCond(thenEdge, elseEdge );
14351
+ FlowEdge* const thenEdge = fgAddRefPred(thenBlock, condBlock);
14352
+ FlowEdge* const elseEdge = condBlock->GetTargetEdge();
14353
+ condBlock->SetCond(elseEdge, thenEdge );
14334
14354
thenBlock->inheritWeightPercentage(condBlock, thenLikelihood);
14335
14355
elseBlock->inheritWeightPercentage(condBlock, elseLikelihood);
14336
14356
thenEdge->setLikelihood(thenLikelihood / 100.0);
@@ -14344,6 +14364,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
14344
14364
// +-->-------------+
14345
14365
// bbj_cond(true)
14346
14366
//
14367
+ // TODO: Remove unnecessary condition reversal
14347
14368
gtReverseCond(condExpr);
14348
14369
14349
14370
const unsigned thenLikelihood = qmark->ThenNodeLikelihood();
0 commit comments