@@ -5409,6 +5409,176 @@ bool FlowGraphNaturalLoop::HasDef(unsigned lclNum)
5409
5409
return !result;
5410
5410
}
5411
5411
5412
+ // ------------------------------------------------------------------------
5413
+ // CanDuplicate: Check if this loop can be duplicated.
5414
+ //
5415
+ // Parameters:
5416
+ // reason - If this function returns false, the reason why.
5417
+ //
5418
+ // Returns:
5419
+ // True if the loop can be duplicated.
5420
+ //
5421
+ // Remarks:
5422
+ // We currently do not support duplicating loops with EH constructs in them.
5423
+ //
5424
+ bool FlowGraphNaturalLoop::CanDuplicate (INDEBUG(const char ** reason))
5425
+ {
5426
+ #ifdef DEBUG
5427
+ const char * localReason;
5428
+ if (reason == nullptr )
5429
+ {
5430
+ reason = &localReason;
5431
+ }
5432
+ #endif
5433
+
5434
+ Compiler* comp = m_dfsTree->GetCompiler ();
5435
+ BasicBlockVisit result = VisitLoopBlocks ([=](BasicBlock* block) {
5436
+ if (comp->bbIsTryBeg (block))
5437
+ {
5438
+ INDEBUG (*reason = " Loop has a `try` begin" );
5439
+ return BasicBlockVisit::Abort;
5440
+ }
5441
+
5442
+ return BasicBlockVisit::Continue;
5443
+ });
5444
+
5445
+ return result != BasicBlockVisit::Abort;
5446
+ }
5447
+
5448
+ // ------------------------------------------------------------------------
5449
+ // Duplicate: Duplicate the blocks of this loop, inserting them after `insertAfter`.
5450
+ //
5451
+ // Parameters:
5452
+ // insertAfter - [in, out] Block to insert duplicated blocks after; updated to last block inserted.
5453
+ // map - A map that will have mappings from loop blocks to duplicated blocks added to it.
5454
+ // weightScale - Factor to scale weight of new blocks by
5455
+ // bottomNeedsRedirection - Whether or not to insert a redirection block for the bottom block in case of fallthrough
5456
+ //
5457
+ // Remarks:
5458
+ // Due to fallthrough this block may need to insert blocks with no
5459
+ // corresponding source block in "map".
5460
+ //
5461
+ void FlowGraphNaturalLoop::Duplicate (BasicBlock** insertAfter,
5462
+ BlockToBlockMap* map,
5463
+ weight_t weightScale,
5464
+ bool bottomNeedsRedirection)
5465
+ {
5466
+ assert (CanDuplicate (nullptr ));
5467
+
5468
+ Compiler* comp = m_dfsTree->GetCompiler ();
5469
+
5470
+ BasicBlock* bottom = GetLexicallyBottomMostBlock ();
5471
+
5472
+ VisitLoopBlocksLexical ([=](BasicBlock* blk) {
5473
+ // Initialize newBlk as BBJ_ALWAYS without jump target, and fix up jump target later
5474
+ // with BasicBlock::CopyTarget().
5475
+ BasicBlock* newBlk = comp->fgNewBBafter (BBJ_ALWAYS, *insertAfter, /* extendRegion*/ true );
5476
+ JITDUMP (" Adding " FMT_BB " (copy of " FMT_BB " ) after " FMT_BB " \n " , newBlk->bbNum , blk->bbNum ,
5477
+ (*insertAfter)->bbNum );
5478
+
5479
+ BasicBlock::CloneBlockState (comp, newBlk, blk);
5480
+
5481
+ // We're going to create the preds below, which will set the bbRefs properly,
5482
+ // so clear out the cloned bbRefs field.
5483
+ newBlk->bbRefs = 0 ;
5484
+
5485
+ newBlk->scaleBBWeight (weightScale);
5486
+
5487
+ // If the loop we're cloning contains nested loops, we need to clear the pre-header bit on
5488
+ // any nested loop pre-header blocks, since they will no longer be loop pre-headers.
5489
+ //
5490
+ // TODO-Cleanup: BBF_LOOP_PREHEADER can be removed; we do not attempt
5491
+ // to keep it up to date anymore when we do FG changes.
5492
+ //
5493
+ if (newBlk->HasFlag (BBF_LOOP_PREHEADER))
5494
+ {
5495
+ JITDUMP (" Removing BBF_LOOP_PREHEADER flag from nested cloned loop block " FMT_BB " \n " , newBlk->bbNum );
5496
+ newBlk->RemoveFlags (BBF_LOOP_PREHEADER);
5497
+ }
5498
+
5499
+ *insertAfter = newBlk;
5500
+ map->Set (blk, newBlk, BlockToBlockMap::Overwrite);
5501
+
5502
+ // If the block falls through to a block outside the loop then we may
5503
+ // need to insert a new block to redirect.
5504
+ // Skip this once we get to the bottom block if our cloned version is
5505
+ // going to fall into the right version anyway.
5506
+ if (blk->bbFallsThrough () && !ContainsBlock (blk->Next ()) && ((blk != bottom) || bottomNeedsRedirection))
5507
+ {
5508
+ if (blk->KindIs (BBJ_COND))
5509
+ {
5510
+ BasicBlock* targetBlk = blk->GetFalseTarget ();
5511
+ assert (blk->NextIs (targetBlk));
5512
+
5513
+ // Need to insert a block.
5514
+ BasicBlock* newRedirBlk =
5515
+ comp->fgNewBBafter (BBJ_ALWAYS, *insertAfter, /* extendRegion */ true , targetBlk);
5516
+ newRedirBlk->copyEHRegion (*insertAfter);
5517
+ newRedirBlk->bbWeight = blk->Next ()->bbWeight ;
5518
+ newRedirBlk->CopyFlags (blk->Next (), (BBF_RUN_RARELY | BBF_PROF_WEIGHT));
5519
+ newRedirBlk->scaleBBWeight (weightScale);
5520
+
5521
+ JITDUMP (FMT_BB " falls through to " FMT_BB " ; inserted redirection block " FMT_BB " \n " , blk->bbNum ,
5522
+ blk->Next ()->bbNum , newRedirBlk->bbNum );
5523
+ // This block isn't part of the loop, so below loop won't add
5524
+ // refs for it.
5525
+ comp->fgAddRefPred (targetBlk, newRedirBlk);
5526
+ *insertAfter = newRedirBlk;
5527
+ }
5528
+ else
5529
+ {
5530
+ assert (!" Cannot handle fallthrough" );
5531
+ }
5532
+ }
5533
+
5534
+ return BasicBlockVisit::Continue;
5535
+ });
5536
+
5537
+ // Now go through the new blocks, remapping their jump targets within the loop
5538
+ // and updating the preds lists.
5539
+ VisitLoopBlocks ([=](BasicBlock* blk) {
5540
+ BasicBlock* newBlk = nullptr ;
5541
+ bool b = map->Lookup (blk, &newBlk);
5542
+ assert (b && newBlk != nullptr );
5543
+
5544
+ // Jump target should not be set yet
5545
+ assert (!newBlk->HasInitializedTarget ());
5546
+
5547
+ // First copy the jump destination(s) from "blk".
5548
+ newBlk->CopyTarget (comp, blk);
5549
+
5550
+ // Now redirect the new block according to "blockMap".
5551
+ comp->optRedirectBlock (newBlk, map);
5552
+
5553
+ // Add predecessor edges for the new successors, as well as the fall-through paths.
5554
+ switch (newBlk->GetKind ())
5555
+ {
5556
+ case BBJ_ALWAYS:
5557
+ case BBJ_CALLFINALLY:
5558
+ case BBJ_CALLFINALLYRET:
5559
+ comp->fgAddRefPred (newBlk->GetTarget (), newBlk);
5560
+ break ;
5561
+
5562
+ case BBJ_COND:
5563
+ comp->fgAddRefPred (newBlk->GetFalseTarget (), newBlk);
5564
+ comp->fgAddRefPred (newBlk->GetTrueTarget (), newBlk);
5565
+ break ;
5566
+
5567
+ case BBJ_SWITCH:
5568
+ for (BasicBlock* const switchDest : newBlk->SwitchTargets ())
5569
+ {
5570
+ comp->fgAddRefPred (switchDest, newBlk);
5571
+ }
5572
+ break ;
5573
+
5574
+ default :
5575
+ break ;
5576
+ }
5577
+
5578
+ return BasicBlockVisit::Continue;
5579
+ });
5580
+ }
5581
+
5412
5582
// ------------------------------------------------------------------------
5413
5583
// IterConst: Get the constant with which the iterator is modified
5414
5584
//
0 commit comments