Skip to content

Commit 063bbfc

Browse files
authored
Merge pull request #20136 from atrick/silcloner-cleanup
[NFC] SILCloner rewrite stage 2: "threading" cloners.
2 parents f4033bb + 903a982 commit 063bbfc

File tree

6 files changed

+183
-211
lines changed

6 files changed

+183
-211
lines changed

include/swift/SIL/SILCloner.h

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
112112
/// instructions. `visitTerminator` is called in the same order, but only
113113
/// after mapping all blocks.
114114
void cloneReachableBlocks(SILBasicBlock *startBB,
115-
ArrayRef<SILBasicBlock *> exitBlocks);
115+
ArrayRef<SILBasicBlock *> exitBlocks,
116+
SILBasicBlock *insertAfterBB = nullptr);
116117

117118
/// Clone all blocks in this function and all instructions in those
118119
/// blocks.
@@ -149,9 +150,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
149150
/// recordFoldedValue() are the only two ways for a visitor to map an original
150151
/// value to another value for use within the cloned region.
151152
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);
155154
}
156155

157156
/// Mark a block containing an unreachable instruction for use in the `fixUp`
@@ -351,7 +350,11 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
351350
ProtocolConformanceRef remapConformance(Type Ty, ProtocolConformanceRef C) {
352351
return C;
353352
}
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.
354355
SILValue getMappedValue(SILValue Value);
356+
void mapValue(SILValue origValue, SILValue mappedValue);
357+
355358
SILFunction *remapFunction(SILFunction *Func) { return Func; }
356359
SILBasicBlock *remapBasicBlock(SILBasicBlock *BB);
357360
void postProcess(SILInstruction *Orig, SILInstruction *Cloned);
@@ -380,8 +383,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
380383

381384
void clonePhiArgs(SILBasicBlock *oldBB);
382385

383-
void visitBlocksDepthFirst(SILBasicBlock *StartBB,
384-
SILBasicBlock *insertBeforeBB = nullptr);
386+
void visitBlocksDepthFirst(SILBasicBlock *StartBB);
385387

386388
/// Also perform fundamental cleanup first, then call the CRTP extension,
387389
/// `fixUp`.
@@ -470,6 +472,41 @@ class SILClonerWithScopes : public SILCloner<ImplClass> {
470472
}
471473
};
472474

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+
473510
template<typename ImplClass>
474511
SILValue
475512
SILCloner<ImplClass>::getMappedValue(SILValue Value) {
@@ -488,6 +525,13 @@ SILCloner<ImplClass>::getMappedValue(SILValue Value) {
488525
llvm_unreachable("Unmapped value while cloning?");
489526
}
490527

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+
491535
template<typename ImplClass>
492536
SILBasicBlock*
493537
SILCloner<ImplClass>::remapBasicBlock(SILBasicBlock *BB) {
@@ -512,12 +556,8 @@ SILCloner<ImplClass>::postProcess(SILInstruction *orig,
512556
// Otherwise, map the results over one-by-one.
513557
auto clonedResults = cloned->getResults();
514558
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]);
521561
}
522562

523563
template<typename ImplClass>
@@ -530,16 +570,20 @@ void SILCloner<ImplClass>::visitInstructionsInBlock(SILBasicBlock* BB) {
530570

531571
template <typename ImplClass>
532572
void SILCloner<ImplClass>::cloneReachableBlocks(
533-
SILBasicBlock *startBB, ArrayRef<SILBasicBlock *> exitBlocks) {
573+
SILBasicBlock *startBB, ArrayRef<SILBasicBlock *> exitBlocks,
574+
SILBasicBlock *insertAfterBB) {
575+
534576
SILFunction *F = startBB->getParent();
535577
assert(F == &Builder.getFunction()
536578
&& "cannot clone region across functions.");
537579
assert(BBMap.empty() && "This API does not allow clients to map blocks.");
538580
assert(ValueMap.empty() && "Stale ValueMap.");
539581

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);
543587
clonePhiArgs(startBB);
544588

545589
// Premap exit blocks to terminate so that visitBlocksDepthFirst terminates
@@ -571,17 +615,8 @@ void SILCloner<ImplClass>::cloneFunctionBody(SILFunction *F,
571615

572616
Builder.setInsertionPoint(clonedEntryBB);
573617

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());
585620

586621
doFixUp(F);
587622
}
@@ -595,18 +630,15 @@ void SILCloner<ImplClass>::clonePhiArgs(SILBasicBlock *oldBB) {
595630
SILValue mappedArg = mappedBB->createPhiArgument(
596631
getOpType(Arg->getType()), Arg->getOwnershipKind());
597632

598-
ValueMap.insert(std::make_pair(Arg, mappedArg));
633+
asImpl().mapValue(Arg, mappedArg);
599634
}
600635
}
601636

602637
// This private helper visits BBs in depth-first preorder (only processing
603638
// blocks on the first visit), mapping newly visited BBs to new BBs and cloning
604639
// all instructions into the caller.
605640
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) {
610642
// The caller clones startBB because it may be a function header, which
611643
// requires special handling.
612644
assert(BBMap.count(startBB) && "The caller must map the first BB.");
@@ -617,40 +649,53 @@ void SILCloner<ImplClass>::visitBlocksDepthFirst(
617649
//
618650
// FIXME: Add reverse iteration to SILSuccessor, then convert this to an RPOT
619651
// 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.
621653
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];
622659
while (!dfsWorklist.empty()) {
623660
auto *BB = dfsWorklist.pop_back_val();
624661
preorderBlocks.push_back(BB);
625662

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.
629671
getBuilder().setInsertionPoint(BBMap[BB]);
630672
asImpl().visitInstructionsInBlock(BB);
631673

632-
unsigned succStartIdx = dfsWorklist.size();
633-
for (auto &Succ : BB->getSuccessors()) {
674+
unsigned dfsSuccStartIdx = dfsWorklist.size();
675+
for (auto &succ : BB->getSuccessors()) {
634676
// Only visit a successor that has not already been visited and was not
635677
// premapped by the client.
636-
if (BBMap.count(Succ))
678+
if (BBMap.count(succ))
637679
continue;
638680

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);
643685

644-
BBMap.insert(std::make_pair(Succ.getBB(), MappedBB));
686+
BBMap.insert(std::make_pair(succ.getBB(), lastClonedBB));
645687

646-
clonePhiArgs(Succ);
647-
648-
dfsWorklist.push_back(Succ);
688+
dfsWorklist.push_back(succ);
649689
}
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());
652693
}
653694
// 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.
654699
for (auto *origBB : preorderBlocks) {
655700
// Set the insertion point to the new mapped BB
656701
getBuilder().setInsertionPoint(BBMap[origBB]);

0 commit comments

Comments
 (0)