@@ -112,7 +112,8 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
112
112
// / instructions. `visitTerminator` is called in the same order, but only
113
113
// / after mapping all blocks.
114
114
void cloneReachableBlocks (SILBasicBlock *startBB,
115
- ArrayRef<SILBasicBlock *> exitBlocks);
115
+ ArrayRef<SILBasicBlock *> exitBlocks,
116
+ SILBasicBlock *insertAfterBB = nullptr );
116
117
117
118
// / Clone all blocks in this function and all instructions in those
118
119
// / blocks.
@@ -149,9 +150,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
149
150
// / recordFoldedValue() are the only two ways for a visitor to map an original
150
151
// / value to another value for use within the cloned region.
151
152
void recordFoldedValue (SILValue origValue, SILValue mappedValue) {
152
- auto iterAndInserted = ValueMap.insert ({origValue, mappedValue});
153
- (void )iterAndInserted;
154
- assert (iterAndInserted.second && " Original value already mapped." );
153
+ asImpl ().mapValue (origValue, mappedValue);
155
154
}
156
155
157
156
// / Mark a block containing an unreachable instruction for use in the `fixUp`
@@ -351,7 +350,11 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
351
350
ProtocolConformanceRef remapConformance (Type Ty, ProtocolConformanceRef C) {
352
351
return C;
353
352
}
353
+ // / Get the value that takes the place of the given `Value` within the cloned
354
+ // / region. The given value must already have been mapped by this cloner.
354
355
SILValue getMappedValue (SILValue Value);
356
+ void mapValue (SILValue origValue, SILValue mappedValue);
357
+
355
358
SILFunction *remapFunction (SILFunction *Func) { return Func; }
356
359
SILBasicBlock *remapBasicBlock (SILBasicBlock *BB);
357
360
void postProcess (SILInstruction *Orig, SILInstruction *Cloned);
@@ -380,8 +383,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
380
383
381
384
void clonePhiArgs (SILBasicBlock *oldBB);
382
385
383
- void visitBlocksDepthFirst (SILBasicBlock *StartBB,
384
- SILBasicBlock *insertBeforeBB = nullptr );
386
+ void visitBlocksDepthFirst (SILBasicBlock *StartBB);
385
387
386
388
// / Also perform fundamental cleanup first, then call the CRTP extension,
387
389
// / `fixUp`.
@@ -470,6 +472,41 @@ class SILClonerWithScopes : public SILCloner<ImplClass> {
470
472
}
471
473
};
472
474
475
+ // / Clone a function without transforming it.
476
+ class SILFunctionCloner : public SILClonerWithScopes <SILFunctionCloner> {
477
+ using SuperTy = SILClonerWithScopes<SILFunctionCloner>;
478
+ friend class SILCloner <SILFunctionCloner>;
479
+
480
+ public:
481
+ SILFunctionCloner (SILFunction *newF) : SILClonerWithScopes(*newF) {}
482
+
483
+ // / Clone all blocks in this function and all instructions in those
484
+ // / blocks.
485
+ // /
486
+ // / This is used to clone an entire function without mutating the original
487
+ // / function.
488
+ // /
489
+ // / The new function is expected to be completely empty. Clone the entry
490
+ // / blocks arguments here. The cloned arguments become the inputs to the
491
+ // / general SILCloner, which expects the new entry block to be ready to emit
492
+ // / instructions into.
493
+ void cloneFunction (SILFunction *origF) {
494
+ SILFunction *newF = &Builder.getFunction ();
495
+
496
+ auto *newEntryBB = newF->createBasicBlock ();
497
+ newEntryBB->cloneArgumentList (origF->getEntryBlock ());
498
+
499
+ // Copy the new entry block arguments into a separate vector purely to
500
+ // resolve the type mismatch between SILArgument* and SILValue.
501
+ SmallVector<SILValue, 8 > entryArgs;
502
+ entryArgs.reserve (newF->getArguments ().size ());
503
+ transform (newF->getArguments (), std::back_inserter (entryArgs),
504
+ [](SILArgument *arg) -> SILValue { return arg; });
505
+
506
+ SuperTy::cloneFunctionBody (origF, newEntryBB, entryArgs);
507
+ }
508
+ };
509
+
473
510
template <typename ImplClass>
474
511
SILValue
475
512
SILCloner<ImplClass>::getMappedValue(SILValue Value) {
@@ -488,6 +525,13 @@ SILCloner<ImplClass>::getMappedValue(SILValue Value) {
488
525
llvm_unreachable (" Unmapped value while cloning?" );
489
526
}
490
527
528
+ template <typename ImplClass>
529
+ void SILCloner<ImplClass>::mapValue(SILValue origValue, SILValue mappedValue) {
530
+ auto iterAndInserted = ValueMap.insert ({origValue, mappedValue});
531
+ (void )iterAndInserted;
532
+ assert (iterAndInserted.second && " Original value already mapped." );
533
+ }
534
+
491
535
template <typename ImplClass>
492
536
SILBasicBlock*
493
537
SILCloner<ImplClass>::remapBasicBlock(SILBasicBlock *BB) {
@@ -512,12 +556,8 @@ SILCloner<ImplClass>::postProcess(SILInstruction *orig,
512
556
// Otherwise, map the results over one-by-one.
513
557
auto clonedResults = cloned->getResults ();
514
558
assert (origResults.size () == clonedResults.size ());
515
- for (auto i : indices (origResults)) {
516
- SILValue origResult = origResults[i], clonedResult = clonedResults[i];
517
- auto insertion = ValueMap.insert (std::make_pair (origResult, clonedResult));
518
- if (!insertion.second )
519
- insertion.first ->second = clonedResult;
520
- }
559
+ for (auto i : indices (origResults))
560
+ asImpl ().mapValue (origResults[i], clonedResults[i]);
521
561
}
522
562
523
563
template <typename ImplClass>
@@ -530,16 +570,20 @@ void SILCloner<ImplClass>::visitInstructionsInBlock(SILBasicBlock* BB) {
530
570
531
571
template <typename ImplClass>
532
572
void SILCloner<ImplClass>::cloneReachableBlocks(
533
- SILBasicBlock *startBB, ArrayRef<SILBasicBlock *> exitBlocks) {
573
+ SILBasicBlock *startBB, ArrayRef<SILBasicBlock *> exitBlocks,
574
+ SILBasicBlock *insertAfterBB) {
575
+
534
576
SILFunction *F = startBB->getParent ();
535
577
assert (F == &Builder.getFunction ()
536
578
&& " cannot clone region across functions." );
537
579
assert (BBMap.empty () && " This API does not allow clients to map blocks." );
538
580
assert (ValueMap.empty () && " Stale ValueMap." );
539
581
540
- auto *ClonedStart = F->createBasicBlock ();
541
- BBMap.insert (std::make_pair (startBB, ClonedStart));
542
- getBuilder ().setInsertionPoint (ClonedStart);
582
+ auto *clonedStartBB = insertAfterBB ? F->createBasicBlockAfter (insertAfterBB)
583
+ : F->createBasicBlock ();
584
+
585
+ BBMap.insert (std::make_pair (startBB, clonedStartBB));
586
+ getBuilder ().setInsertionPoint (clonedStartBB);
543
587
clonePhiArgs (startBB);
544
588
545
589
// Premap exit blocks to terminate so that visitBlocksDepthFirst terminates
@@ -571,17 +615,8 @@ void SILCloner<ImplClass>::cloneFunctionBody(SILFunction *F,
571
615
572
616
Builder.setInsertionPoint (clonedEntryBB);
573
617
574
- // If the caller's BB is not the last BB in the calling function, then keep
575
- // track of the next BB so we always insert new BBs before it; otherwise,
576
- // we just leave the new BBs at the end as they are by default.
577
- auto *callerF = clonedEntryBB->getParent ();
578
- auto IBI = std::next (SILFunction::iterator (clonedEntryBB));
579
- SILBasicBlock *insertBeforeBB = IBI != callerF->end () ? &*IBI : nullptr ;
580
-
581
- // Visiting in pre-order provides a nice property for the individual
582
- // instruction visitors. It allows those visitors to make use of dominance
583
- // relationships, particularly the fact that operand values will be mapped.
584
- visitBlocksDepthFirst (&*F->begin (), insertBeforeBB);
618
+ // This will layout all newly cloned blocks immediate after clonedEntryBB.
619
+ visitBlocksDepthFirst (&*F->begin ());
585
620
586
621
doFixUp (F);
587
622
}
@@ -595,18 +630,15 @@ void SILCloner<ImplClass>::clonePhiArgs(SILBasicBlock *oldBB) {
595
630
SILValue mappedArg = mappedBB->createPhiArgument (
596
631
getOpType (Arg->getType ()), Arg->getOwnershipKind ());
597
632
598
- ValueMap. insert ( std::make_pair ( Arg, mappedArg) );
633
+ asImpl (). mapValue ( Arg, mappedArg);
599
634
}
600
635
}
601
636
602
637
// This private helper visits BBs in depth-first preorder (only processing
603
638
// blocks on the first visit), mapping newly visited BBs to new BBs and cloning
604
639
// all instructions into the caller.
605
640
template <typename ImplClass>
606
- void SILCloner<ImplClass>::visitBlocksDepthFirst(
607
- SILBasicBlock *startBB, SILBasicBlock *insertBeforeBB) {
608
- SILFunction &newF = getBuilder ().getFunction ();
609
-
641
+ void SILCloner<ImplClass>::visitBlocksDepthFirst(SILBasicBlock *startBB) {
610
642
// The caller clones startBB because it may be a function header, which
611
643
// requires special handling.
612
644
assert (BBMap.count (startBB) && " The caller must map the first BB." );
@@ -617,40 +649,53 @@ void SILCloner<ImplClass>::visitBlocksDepthFirst(
617
649
//
618
650
// FIXME: Add reverse iteration to SILSuccessor, then convert this to an RPOT
619
651
// traversal. We would prefer to keep CFG regions in RPO order, and this would
620
- // be more scalable for functions with many large switches.
652
+ // not create as large a worklist for functions with many large switches.
621
653
SmallVector<SILBasicBlock *, 8 > dfsWorklist (1 , startBB);
654
+ // Keep a reference to the last cloned BB so blocks can be laid out in the
655
+ // order they are created, which differs from the order they are
656
+ // cloned. Blocks are created in BFS order but cloned in DFS preorder (when no
657
+ // critical edges are present).
658
+ SILBasicBlock *lastClonedBB = BBMap[startBB];
622
659
while (!dfsWorklist.empty ()) {
623
660
auto *BB = dfsWorklist.pop_back_val ();
624
661
preorderBlocks.push_back (BB);
625
662
626
- // Visit all dominating instructions before visiting block phi arguments so
627
- // that all opened existentials are registered with the
628
- // OpenedArchetypesTracker before subsituting the phi argument types.
663
+ // Phis are cloned during the first preorder walk so that successor phis
664
+ // exist before predecessor terminators are generated.
665
+ if (BB != startBB)
666
+ clonePhiArgs (BB);
667
+
668
+ // Non-terminating instructions are cloned in the first preorder walk so
669
+ // that all opened existentials are registered with OpenedArchetypesTracker
670
+ // before phi argument type substitution in successors.
629
671
getBuilder ().setInsertionPoint (BBMap[BB]);
630
672
asImpl ().visitInstructionsInBlock (BB);
631
673
632
- unsigned succStartIdx = dfsWorklist.size ();
633
- for (auto &Succ : BB->getSuccessors ()) {
674
+ unsigned dfsSuccStartIdx = dfsWorklist.size ();
675
+ for (auto &succ : BB->getSuccessors ()) {
634
676
// Only visit a successor that has not already been visited and was not
635
677
// premapped by the client.
636
- if (BBMap.count (Succ ))
678
+ if (BBMap.count (succ ))
637
679
continue ;
638
680
639
- // Map the successor to a new BB.
640
- auto *MappedBB = insertBeforeBB
641
- ? newF. createBasicBlockBefore (insertBeforeBB)
642
- : newF. createBasicBlock ( );
681
+ // Map the successor to a new BB. Layout the cloned blocks in the order
682
+ // they are visited and cloned.
683
+ lastClonedBB =
684
+ getBuilder (). getFunction (). createBasicBlockAfter (lastClonedBB );
643
685
644
- BBMap.insert (std::make_pair (Succ .getBB (), MappedBB ));
686
+ BBMap.insert (std::make_pair (succ .getBB (), lastClonedBB ));
645
687
646
- clonePhiArgs (Succ);
647
-
648
- dfsWorklist.push_back (Succ);
688
+ dfsWorklist.push_back (succ);
649
689
}
650
- // Reverse the worklist to pop the successors in forward order.
651
- std::reverse (dfsWorklist.begin () + succStartIdx, dfsWorklist.end ());
690
+ // Reverse the worklist to pop the successors in forward order. This
691
+ // precisely yields DFS preorder when no critical edges are present.
692
+ std::reverse (dfsWorklist.begin () + dfsSuccStartIdx, dfsWorklist.end ());
652
693
}
653
694
// Visit terminators only after the CFG is valid so all branch targets exist.
695
+ //
696
+ // Visiting in pre-order provides a nice property for the individual
697
+ // instruction visitors. It allows those visitors to make use of dominance
698
+ // relationships, particularly the fact that operand values will be mapped.
654
699
for (auto *origBB : preorderBlocks) {
655
700
// Set the insertion point to the new mapped BB
656
701
getBuilder ().setInsertionPoint (BBMap[origBB]);
0 commit comments