31
31
#include " swift/SIL/GraphOperationBuilder.h"
32
32
#include " swift/SIL/LoopInfo.h"
33
33
#include " swift/SIL/SILBuilder.h"
34
+ #include " swift/SIL/SILCloner.h"
34
35
#include " swift/SIL/SILConstants.h"
35
36
#include " swift/SIL/SILUndef.h"
36
37
#include " llvm/ADT/iterator_range.h"
@@ -321,6 +322,58 @@ static SILValue createTFIntegerConst(GraphFunctionDeviceInfo &deviceInfo,
321
322
return constNode->getResults ()[0 ];
322
323
}
323
324
325
+ namespace {
326
+
327
+ class BasicBlockCloner : public SILClonerWithScopes <BasicBlockCloner> {
328
+ private:
329
+ // / The flag to track if this cloner was used to clone any blocks.
330
+ bool cloned;
331
+
332
+ public:
333
+ BasicBlockCloner (SILFunction &F)
334
+ : SILClonerWithScopes(F), cloned(false ) {}
335
+
336
+ bool hasCloned () const { return cloned; }
337
+
338
+ // / Return a cloned block.
339
+ SILBasicBlock *cloneBlock (SILBasicBlock *bb) {
340
+ auto bbIt = BBMap.find (bb);
341
+ if (bbIt != BBMap.end ())
342
+ return bbIt->second ;
343
+
344
+ cloned = true ;
345
+
346
+ SILFunction &F = getBuilder ().getFunction ();
347
+ SILBasicBlock *newBB = F.createBasicBlock ();
348
+ getBuilder ().setInsertionPoint (newBB);
349
+ BBMap[bb] = newBB;
350
+ // If the basic block has arguments, clone them as well.
351
+ for (auto *arg : bb->getArguments ()) {
352
+ // Create a new argument and copy it into the ValueMap so future
353
+ // references use it.
354
+ ValueMap[arg] = newBB->createPHIArgument (
355
+ arg->getType (), arg->getOwnershipKind (), arg->getDecl ());
356
+ }
357
+ // Clone all the instructions.
358
+ for (auto &inst : *bb) {
359
+ visit (&inst);
360
+ }
361
+ return newBB;
362
+ }
363
+
364
+ // / Handle references to basic blocks when cloning.
365
+ SILBasicBlock *remapBasicBlock (SILBasicBlock *bb) {
366
+ // If the block was not cloned by this cloner, directly reference it.
367
+ // Otherwise, use the cloned block.
368
+ auto bbIt = BBMap.find (bb);
369
+ if (bbIt != BBMap.end ())
370
+ return bbIt->second ;
371
+ return bb;
372
+ }
373
+ };
374
+
375
+ } // namespace
376
+
324
377
// A helper class to transform a loop to have a single exit from the header.
325
378
class SingleExitLoopTransformer {
326
379
public:
@@ -432,6 +485,8 @@ class SingleExitLoopTransformer {
432
485
llvm::DenseMap<SILValue, SILValue> escapingValueSubstMap;
433
486
// / Similar to escapingValueSubstMap, but arguments of exit blocks.
434
487
llvm::DenseMap<SILValue, SILValue> exitArgSubstMap;
488
+ // Map from an arg of an exit block to the corresponding newly added header arg.
489
+ llvm::DenseMap<SILValue, SILValue> exitArgHeaderArgMap;
435
490
};
436
491
437
492
void SingleExitLoopTransformer::initialize () {
@@ -492,6 +547,8 @@ void SingleExitLoopTransformer::initialize() {
492
547
}
493
548
494
549
void SingleExitLoopTransformer::ensureSingleExitBlock () {
550
+ BasicBlockCloner cloner (*currentFn);
551
+
495
552
// Identify the common post dominator
496
553
SILPrintContext printContext (llvm::dbgs ());
497
554
SmallVector<SILBasicBlock*, 8 > exitBlockList;
@@ -528,21 +585,31 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
528
585
// appropriately and not deal with touching stale memory.
529
586
auto succs = current->getSuccessors ();
530
587
auto *succ = succs[edgeIdx].getBB ();
531
- // Skip if (1) already processed, (2) reached common pd, or (3)
532
- // block has in edges from outside the loop. In the last case, we will
533
- // need to clone the blocks.
588
+ // Skip if (1) already processed or (2) reached common pd.
534
589
if (blocksToBeMoved.count (succ) > 0 || succ == nearestCommonPD) {
535
590
continue ;
536
591
}
537
- if (!DI->properlyDominates (header, succ)) {
538
- // Split this edge so that we don't mess up arguments passed in
539
- // from other predecessors of succ.
540
- if (succ->getNumArguments () > 0 ) {
541
- splitEdge (current->getTerminator (), edgeIdx, DI, LI);
542
- }
592
+
593
+ if (DI->properlyDominates (header, succ)) {
594
+ worklist.insert (succ);
543
595
continue ;
544
596
}
545
- worklist.insert (succ);
597
+ // If `succ` is not dominated by `header`, then `succ` is reachable from
598
+ // a node outside of this loop. We might have to clone `succ` in such
599
+ // cases.
600
+
601
+ // Before cloning make sure that header -> succ is *not* backedge of a
602
+ // parent loop. This can happen when we have labeled breaks in loops. We
603
+ // cannot clone the blocks in such cases. Simply continue. This is still
604
+ // OK for our purposes because we will find an equivalent value at the
605
+ // header for any value that escapes along this edge.
606
+ if (DI->properlyDominates (succ, header)) continue ;
607
+
608
+ // Clone the block and rewire the edge.
609
+ SILBasicBlock *clonedSucc = cloner.cloneBlock (succ);
610
+ changeBranchTarget (current->getTerminator (), edgeIdx, clonedSucc,
611
+ /* preserveArgs*/ true );
612
+ worklist.insert (clonedSucc);
546
613
}
547
614
}
548
615
}
@@ -578,6 +645,12 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
578
645
}
579
646
loop->addBasicBlockToLoop (outsideBlock, LI->getBase ());
580
647
}
648
+ if (cloner.hasCloned ()) {
649
+ // TODO(https://bugs.swift.org/browse/SR-8336): the transformations here are
650
+ // simple that we should be able to incrementally update the DI & PDI.
651
+ DI->recalculate (*currentFn);
652
+ PDI->recalculate (*currentFn);
653
+ }
581
654
}
582
655
583
656
llvm::DenseMap<SILValue, SILValue>
@@ -699,30 +772,30 @@ SingleExitLoopTransformer::createNewHeader() {
699
772
}
700
773
header->dropAllArguments ();
701
774
// Add phi arguments in the new header corresponding to the escaping values.
702
- auto addArgument =
703
- [this , newHeader](SILValue escapingValue) {
704
- SILValue newValue = newHeader->createPHIArgument (
705
- escapingValue->getType (), escapingValue.getOwnershipKind ());
706
- // Replace uses *outside* of the loop with the new value.
707
- auto UI = escapingValue->use_begin (), E = escapingValue->use_end ();
708
- while (UI != E) {
709
- Operand *use = *UI;
710
- // Increment iterator before we invalidate it
711
- // when we invoke Operand::Set below.
712
- ++UI;
713
- if (loop->contains (use->getUser ()->getParent ())) {
714
- continue ;
715
- }
716
- use->set (newValue);
717
- }
718
- };
719
-
720
775
for (const auto &kv : escapingValueSubstMap) {
721
- addArgument (kv.first );
776
+ SILValue escapingValue = kv.first ;
777
+ SILValue newValue = newHeader->createPHIArgument (
778
+ escapingValue->getType (), escapingValue.getOwnershipKind ());
779
+ // Replace uses *outside* of the loop with the new value.
780
+ auto UI = escapingValue->use_begin (), E = escapingValue->use_end ();
781
+ while (UI != E) {
782
+ Operand *use = *UI;
783
+ // Increment iterator before we invalidate it
784
+ // when we invoke Operand::Set below.
785
+ ++UI;
786
+ if (loop->contains (use->getUser ()->getParent ())) {
787
+ continue ;
788
+ }
789
+ use->set (newValue);
790
+ }
722
791
}
723
792
if (TFNoUndefsInSESE) {
793
+ // Add arguments in the new header corresponding to exit block arguments.
724
794
for (const auto &kv : exitArgSubstMap) {
725
- addArgument (kv.first );
795
+ SILValue arg = kv.first ;
796
+ SILValue newValue =
797
+ newHeader->createPHIArgument (arg->getType (), arg.getOwnershipKind ());
798
+ exitArgHeaderArgMap[kv.first ] = newValue;
726
799
}
727
800
}
728
801
// An integer to identify the exit edge.
@@ -901,15 +974,6 @@ SingleExitLoopTransformer::patchEdges(SILBasicBlock *newHeader,
901
974
SILBasicBlock *SingleExitLoopTransformer::createNewExitBlockWithDemux (
902
975
const llvm::DenseMap<SILBasicBlock *, intmax_t > &exitIndices,
903
976
SILValue exitIndexArg) {
904
- if (TFNoUndefsInSESE) {
905
- // Drop all arguments as we have moved them into the headers arguments.
906
- for (SILBasicBlock *exitBlock : exitBlocks) {
907
- exitBlock->dropAllArguments ();
908
- }
909
- }
910
- if (exitBlocks.size () == 1 ) {
911
- return *exitBlocks.begin ();
912
- }
913
977
auto createBlockOutsideLoop = [this ]() {
914
978
SILBasicBlock *newBlock = currentFn->createBasicBlock ();
915
979
SILLoop *parentLoop = loop->getParentLoop ();
@@ -919,11 +983,9 @@ SILBasicBlock *SingleExitLoopTransformer::createNewExitBlockWithDemux(
919
983
return newBlock;
920
984
};
921
985
922
- // Create a new exit block.
923
- // FIXME: We can avoid creating an additional block and instead connect the
924
- // header directly to the demuxBlock created in the loop below. Alternatively,
925
- // we can also use contractUncondBranches in TFParititon.cpp to remove this
926
- // block later.
986
+ // Create a new exit block. Strictly, we don't always need this block, but it
987
+ // makes it slightly easier to implement the demux blocks. contractUncondEdges
988
+ // will merge this block away if appropriate.
927
989
SILBasicBlock *newExitBlock = createBlockOutsideLoop ();
928
990
929
991
SILBuilder builder (newExitBlock);
@@ -934,6 +996,17 @@ SILBasicBlock *SingleExitLoopTransformer::createNewExitBlockWithDemux(
934
996
SILLocation headerLocation =
935
997
getUserSourceLocation (header->getTerminator ()->getDebugLocation ());
936
998
999
+ // Find the arguments at the header that were added for the exit arguments
1000
+ // and pass that along to the original exit block.
1001
+ auto remapExitArguments = [this ](SILBasicBlock *exitingBlock,
1002
+ SILBasicBlock *exitBlock) {
1003
+ SmallVector<SILValue, 8 > headerArgs;
1004
+ for (SILValue arg : exitBlock->getArguments ()) {
1005
+ headerArgs.push_back (exitArgHeaderArgMap[arg]);
1006
+ }
1007
+ appendArguments (exitingBlock->getTerminator (), exitBlock, headerArgs);
1008
+ };
1009
+
937
1010
while (curBlockIter != exitBlocks.end ()) {
938
1011
SILBasicBlock *newBlock = createBlockOutsideLoop ();
939
1012
SILBasicBlock *trueBlock = *curBlockIter++;
@@ -959,10 +1032,18 @@ SILBasicBlock *SingleExitLoopTransformer::createNewExitBlockWithDemux(
959
1032
condTensorInst->getResults ()[0 ], builder, headerLocation, *deviceInfo);
960
1033
builder.createCondBranch (headerLocation, condValue->getResults ()[0 ],
961
1034
trueBlock, demuxBlock);
1035
+
1036
+ if (TFNoUndefsInSESE) {
1037
+ remapExitArguments (newBlock, trueBlock);
1038
+ remapExitArguments (newBlock, demuxBlock);
1039
+ }
962
1040
demuxBlock = newBlock;
963
1041
}
964
1042
builder.setInsertionPoint (newExitBlock);
965
1043
builder.createBranch (headerLocation, demuxBlock);
1044
+ if (TFNoUndefsInSESE) {
1045
+ remapExitArguments (newExitBlock, demuxBlock);
1046
+ }
966
1047
return newExitBlock;
967
1048
}
968
1049
@@ -1061,7 +1142,11 @@ void SESERegionBuilder::ensureSingleExitFromLoops() {
1061
1142
changed |= loopChanged;
1062
1143
}
1063
1144
if (changed) {
1064
- splitAllCondBrCriticalEdgesWithNonTrivialArgs (*F, nullptr , &LI);
1145
+ splitAllCondBrCriticalEdgesWithNonTrivialArgs (*F, &DI, &LI);
1146
+ contractUncondBranches (F, &DI, &LI);
1147
+ // TODO(https://bugs.swift.org/browse/SR-8336): the transformations here are
1148
+ // simple that we should be able to incrementally update PDI.
1149
+ PDI.recalculate (*F);
1065
1150
}
1066
1151
}
1067
1152
0 commit comments